evas-wayland-egl: Add www protocol handling to wayland-egl engine
authorDerek Foreman <derekf@osg.samsung.com>
Mon, 28 Mar 2016 17:56:23 +0000 (12:56 -0500)
committerMike Blumenkrantz <zmike@osg.samsung.com>
Fri, 1 Apr 2016 10:49:50 +0000 (06:49 -0400)
Use the new post-processing API and www extension to implement
CSS effects for wayland-egl applications.

Signed-off-by: Derek Foreman <derekf@osg.samsung.com>
Signed-off-by: Mike Blumenkrantz <zmike@osg.samsung.com>
src/Makefile_Evas.am
src/modules/evas/engines/wayland_egl/evas_engine.c
src/modules/evas/engines/wayland_egl/evas_engine.h
src/modules/evas/engines/wayland_egl/evas_wl_main.c
src/modules/evas/engines/wayland_egl/www.c [new file with mode: 0644]
src/modules/evas/engines/wayland_egl/www.h [new file with mode: 0644]

index 0769220..d2e15de 100644 (file)
@@ -1193,7 +1193,9 @@ dist_installed_evasmainheaders_DATA += modules/evas/engines/wayland_egl/Evas_Eng
 WAYLAND_EGL_SOURCES = \
 modules/evas/engines/wayland_egl/evas_engine.c \
 modules/evas/engines/wayland_egl/evas_wl_main.c \
-modules/evas/engines/wayland_egl/evas_engine.h
+modules/evas/engines/wayland_egl/evas_engine.h \
+modules/evas/engines/wayland_egl/www.c \
+modules/evas/engines/wayland_egl/www.h
 if EVAS_STATIC_BUILD_WAYLAND_EGL
 lib_evas_libevas_la_SOURCES += $(WAYLAND_EGL_SOURCES)
 lib_evas_libevas_la_CPPFLAGS += @evas_engine_wayland_egl_cflags@
index 0e27ade..aef2120 100644 (file)
@@ -62,6 +62,11 @@ Evas_GL_Common_Context_Call glsym_evas_gl_common_context_newframe = NULL;
 Evas_GL_Common_Context_Call glsym_evas_gl_common_context_done = NULL;
 Evas_GL_Common_Context_Resize_Call glsym_evas_gl_common_context_resize = NULL;
 Evas_GL_Common_Buffer_Dump_Call glsym_evas_gl_common_buffer_dump = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_unredirect = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_redirect = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_redirect_bind = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_redirect_unbind = NULL;
+Evas_GL_Common_Context_Call_GLuint_Return glsym_evas_gl_common_context_redirect_texture_get = NULL;
 Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_lock = NULL;
 Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock = NULL;
 Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_relax = NULL;
@@ -73,6 +78,17 @@ void (*glsym_glEGLImageTargetTexture2DOES) (int a, void *b)  = NULL;
 unsigned int (*glsym_eglSwapBuffersWithDamage) (EGLDisplay a, void *b, const EGLint *d, EGLint c) = NULL;
 unsigned int (*glsym_eglSetDamageRegionKHR) (EGLDisplay a, EGLSurface b, EGLint *c, EGLint d) = NULL;
 unsigned int (*glsym_eglQueryWaylandBufferWL)(EGLDisplay a, struct wl_resource *b, EGLint c, EGLint *d) = NULL;
+GLuint       (*glsym_glCreateShader) (GLenum a) = NULL;
+void         (*glsym_glShaderSource) (GLuint a, GLsizei b, const GLchar **c, const GLint *d) = NULL;
+void         (*glsym_glCompileShader) (GLuint a) = NULL;
+void         (*glsym_glGetShaderiv) (GLuint a, GLenum b, GLint *c) = NULL;
+void         (*glsym_glGetShaderInfoLog) (GLuint a, GLsizei b, GLsizei *c, GLchar *d) = NULL;
+GLuint       (*glsym_glCreateProgram) (void) = NULL;
+void         (*glsym_glAttachShader) (GLuint a, GLuint b) = NULL;
+void         (*glsym_glBindAttribLocation) (GLuint a, GLuint b, const GLchar *c) = NULL;
+void         (*glsym_glLinkProgram) (GLuint a) = NULL;
+void         (*glsym_glGetProgramiv) (GLuint a, GLenum b, GLint *c) = NULL;
+void         (*glsym_glGetProgramInfoLog) (GLuint a, GLsizei b, GLsizei *c, GLchar *d) = NULL;
 
 /* local variables */
 static Eina_Bool initted = EINA_FALSE;
@@ -124,6 +140,11 @@ gl_symbols(void)
    LINK2GENERIC(evas_gl_common_context_newframe);
    LINK2GENERIC(evas_gl_common_context_done);
    LINK2GENERIC(evas_gl_common_context_resize);
+   LINK2GENERIC(evas_gl_common_context_unredirect);
+   LINK2GENERIC(evas_gl_common_context_redirect);
+   LINK2GENERIC(evas_gl_common_context_redirect_bind);
+   LINK2GENERIC(evas_gl_common_context_redirect_unbind);
+   LINK2GENERIC(evas_gl_common_context_redirect_texture_get);
    LINK2GENERIC(evas_gl_common_buffer_dump);
    LINK2GENERIC(evas_gl_preload_render_lock);
    LINK2GENERIC(evas_gl_preload_render_unlock);
@@ -174,6 +195,28 @@ gl_symbols(void)
    FINDSYM(glsym_eglQueryWaylandBufferWL, "eglQueryWaylandBufferWL",
            glsym_func_uint);
 
+   FINDSYM(glsym_glCreateShader, "glCreateShader", glsym_func_uint);
+
+   FINDSYM(glsym_glShaderSource, "glShaderSource", glsym_func_void);
+
+   FINDSYM(glsym_glCompileShader, "glCompileShader", glsym_func_void);
+
+   FINDSYM(glsym_glGetShaderiv, "glGetShaderiv", glsym_func_void);
+
+   FINDSYM(glsym_glGetShaderInfoLog, "glGetShaderInfoLog", glsym_func_void);
+
+   FINDSYM(glsym_glCreateProgram, "glCreateProgram", glsym_func_uint);
+
+   FINDSYM(glsym_glAttachShader, "glAttachShader", glsym_func_void);
+
+   FINDSYM(glsym_glBindAttribLocation, "glBindAttribLocation", glsym_func_void);
+
+   FINDSYM(glsym_glLinkProgram, "glLinkProgram", glsym_func_void);
+
+   FINDSYM(glsym_glGetProgramiv, "glGetProgramiv", glsym_func_void);
+
+   FINDSYM(glsym_glGetProgramInfoLog, "glGetProgramInfoLog", glsym_func_void);
+
    done = EINA_TRUE;
 }
 
index a4ccbf8..a7bc7c7 100644 (file)
@@ -7,6 +7,8 @@
 # include "Evas.h"
 # include "Evas_Engine_Wayland_Egl.h"
 
+# include "www.h"
+
 /* NB: This already includes wayland-client.h */
 # include <wayland-egl.h>
 
@@ -81,6 +83,11 @@ struct _Outbuf
 
    Eina_Bool lost_back : 1;
    Eina_Bool surf : 1;
+
+   Model *model;
+   Eina_Bool redirected : 1;
+
+   float offset_x, offset_y;
 };
 
 struct _Context_3D
@@ -100,6 +107,11 @@ extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_use;
 extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_newframe;
 extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_done;
 extern Evas_GL_Common_Context_Resize_Call glsym_evas_gl_common_context_resize;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_unredirect;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_redirect;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_redirect_bind;
+extern Evas_GL_Common_Context_Call glsym_evas_gl_common_context_redirect_unbind;
+extern Evas_GL_Common_Context_Call_GLuint_Return glsym_evas_gl_common_context_redirect_texture_get;
 extern Evas_GL_Common_Buffer_Dump_Call glsym_evas_gl_common_buffer_dump;
 extern Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_lock;
 extern Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock;
@@ -107,6 +119,19 @@ extern Evas_GL_Preload_Render_Call glsym_evas_gl_preload_render_unlock;
 extern unsigned int (*glsym_eglSwapBuffersWithDamage) (EGLDisplay a, void *b, const EGLint *d, EGLint c);
 extern unsigned int (*glsym_eglSetDamageRegionKHR) (EGLDisplay a, EGLSurface b, EGLint *c, EGLint d);
 
+extern GLuint       (*glsym_glCreateShader) (GLenum a);
+extern void         (*glsym_glShaderSource) (GLuint a, GLsizei b, const GLchar **c, const GLint *d);
+extern void         (*glsym_glCompileShader) (GLuint a);
+extern void         (*glsym_glGetShaderiv) (GLuint a, GLenum b, GLint *c);
+extern void         (*glsym_glGetShaderInfoLog) (GLuint a, GLsizei b, GLsizei *c, GLchar *d);
+extern GLuint       (*glsym_glCreateProgram) (void);
+extern void         (*glsym_glAttachShader) (GLuint a, GLuint b);
+extern void         (*glsym_glBindAttribLocation) (GLuint a, GLuint b, const GLchar *c);
+extern void         (*glsym_glLinkProgram) (GLuint a);
+extern void         (*glsym_glGetProgramiv) (GLuint a, GLenum b, GLint *c);
+extern void         (*glsym_glGetProgramInfoLog) (GLuint a, GLsizei b, GLsizei *c, GLchar *d);
+
+
 Outbuf *eng_window_new(Evas *evas, Evas_Engine_Info_Wayland_Egl *einfo, int w, int h, Render_Engine_Swap_Mode swap_mode);
 void eng_window_free(Outbuf *gw);
 void eng_window_use(Outbuf *gw);
index e65570c..59806cf 100644 (file)
@@ -217,7 +217,8 @@ eng_window_free(Outbuf *gw)
         eglReleaseThread();
         context = EGL_NO_CONTEXT;
      }
-
+   free(gw->model);
+   gw->model = NULL;
    free(gw);
 }
 
@@ -314,6 +315,11 @@ eng_window_resurf(Outbuf *gw)
 void 
 eng_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth EINA_UNUSED)
 {
+   if (!ob->model) ob->model = wobbly_create(0, 0, w, h);
+   wobbly_resize(ob->model, w, h);
+   glsym_evas_gl_common_context_unredirect(ob->gl_context);
+   ob->redirected = EINA_FALSE;
+
    ob->w = w;
    ob->h = h;
    ob->rot = rot;
@@ -361,6 +367,11 @@ eng_outbuf_rotation_get(Outbuf *ob)
 Render_Engine_Swap_Mode 
 eng_outbuf_swap_mode_get(Outbuf *ob)
 {
+   if (ob->redirected)
+     {
+        ob->prev_age = 0;
+        return MODE_FULL;
+     }
    if ((ob->swap_mode == MODE_AUTO) && (extn_have_buffer_age))
      {
         Render_Engine_Swap_Mode swap_mode;
@@ -488,6 +499,8 @@ eng_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update EINA_UNUSED, int x
 void 
 eng_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode)
 {
+   Eina_Bool effect_continues = EINA_FALSE;
+
    if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) goto end;
 
    if (!_re_wincheck(ob)) goto end;
@@ -507,7 +520,33 @@ eng_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode)
    if (ob->info->callback.pre_swap)
      ob->info->callback.pre_swap(ob->info->callback.data, ob->evas);
 
-   if ((glsym_eglSwapBuffersWithDamage) && (rects) &&
+   if (ob->model) effect_continues = wobbly_process(ob->model, ob->info,
+                                                    ob->w, ob->h,
+                                                    ob->redirected);
+
+   if (ob->redirected)
+     {
+        float tlx, tly, brx, bry;
+        int w, h;
+
+        wobbly_bounds(ob->model, &tlx, &tly, &brx, &bry);
+        w = brx - tlx;
+        h = bry - tly;
+
+        wl_egl_window_resize(ob->win, w, h,
+                             tlx - ob->offset_x,
+                             tly - ob->offset_y);
+        ob->offset_x = tlx;
+        ob->offset_y = tly;
+        glsym_evas_gl_common_context_redirect_unbind(ob->gl_context);
+        glViewport(0, 0, w, h);
+        wobbly_draw(ob->gl_context, ob->model);
+        wl_surface_set_opaque_region(ob->info->info.surface, NULL);
+        eglSwapBuffers(ob->egl_disp, ob->egl_surface[0]);
+        glsym_evas_gl_common_context_redirect_bind(ob->gl_context);
+        glViewport(0, 0, ob->w, ob->h);
+     }
+   else if ((glsym_eglSwapBuffersWithDamage) && (rects) &&
        (ob->swap_mode != MODE_FULL))
      {
         EGLint num = 0, *result = NULL, i = 0;
@@ -530,6 +569,21 @@ eng_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode)
    else
       eglSwapBuffers(ob->egl_disp, ob->egl_surface[0]);
 
+   if (ob->redirected && !effect_continues) ob->info->wobbling = EINA_TRUE;
+   else ob->info->wobbling = effect_continues;
+
+   if (effect_continues)
+     {
+        glsym_evas_gl_common_context_redirect(ob->gl_context);
+        ob->redirected = EINA_TRUE;
+     }
+   else
+     {
+        ob->offset_x = 0;
+        ob->offset_y = 0;
+        glsym_evas_gl_common_context_unredirect(ob->gl_context);
+        ob->redirected = EINA_FALSE;
+     }
    if (ob->info->callback.post_swap)
      ob->info->callback.post_swap(ob->info->callback.data, ob->evas);
 
diff --git a/src/modules/evas/engines/wayland_egl/www.c b/src/modules/evas/engines/wayland_egl/www.c
new file mode 100644 (file)
index 0000000..c6bb5ca
--- /dev/null
@@ -0,0 +1,885 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+/*
+ * Spring model implemented by Kristian Hogsberg.
+ */
+
+#include "evas_engine.h"
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <Eina.h>
+#include <Evas.h>
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include "www.h"
+
+# define GRID_WIDTH        4
+# define GRID_HEIGHT       4
+
+# define MODEL_MAX_SPRINGS (GRID_WIDTH * GRID_HEIGHT * 2)
+
+# define MASS              15.0f
+
+# define MAXSHORT 32767
+# define MINSHORT -MAXSHORT
+
+# define WOBBLY_GRID_RESOLUTION 32
+# define WOBBLY_MIN_GRID_SIZE 64
+
+typedef struct _xy_pair
+{
+   float x, y;
+} Point, Vector;
+
+typedef struct _Object
+{
+   Vector       force;
+   Point        position;
+   Vector       velocity;
+   float        theta;
+   Eina_Bool    immobile;
+} Object;
+
+typedef struct _Spring
+{
+   Object *a;
+   Object *b;
+   Vector  offset;
+} Spring;
+
+typedef struct _Model
+{
+   Object      *objects;
+   int          numObjects;
+   Spring       springs[MODEL_MAX_SPRINGS];
+   int          numSprings;
+   Object      *anchorObject;
+   float        steps;
+   Point        topLeft;
+   Point        bottomRight;
+
+   int indexSize;
+   GLushort *indices;
+   int vertexStride;
+   GLfloat *vertices;
+   int vertexSize;
+   int texCoordSize;
+
+   int wobbleGrace;
+   int vCount;
+   int indexCount;
+   struct timeval tv;
+
+   GLuint fs;
+   GLuint vs;
+   GLuint prog;
+} Model;
+
+static const GLchar *prog_vs =
+   "attribute vec3 pos;\n"
+   "attribute vec2 tc;\n"
+   "varying vec2 f_tc;\n"
+   "void main()\n"
+   "{\n"
+   "   gl_Position = vec4(pos, 1.0);\n"
+   "   f_tc = tc;\n"
+   "}\n";
+
+static const GLchar *prog_fs =
+   "precision mediump float;\n"
+   "varying vec2 f_tc;\n"
+   "uniform sampler2D ts;\n"
+   "void main()\n"
+   "{\n"
+   "   gl_FragColor = texture2D(ts, f_tc);\n"
+   "}\n";
+
+static Eina_Bool
+setup_shaders(Model *m)
+{
+   GLint err;
+   char errbuf[2048];
+
+   m->vs = glsym_glCreateShader(GL_VERTEX_SHADER);
+   glsym_glShaderSource(m->vs, 1, &prog_vs, NULL);
+   glsym_glCompileShader(m->vs);
+   glsym_glGetShaderiv(m->vs, GL_COMPILE_STATUS, &err);
+   if (!err)
+     {
+        glsym_glGetShaderInfoLog(m->vs, sizeof errbuf, NULL, errbuf);
+        fprintf(stderr, "vs sigh: %s\n", errbuf);
+        return EINA_FALSE;
+     }
+
+   m->fs = glsym_glCreateShader(GL_FRAGMENT_SHADER);
+   glsym_glShaderSource(m->fs, 1, &prog_fs, NULL);
+   glsym_glCompileShader(m->fs);
+   glsym_glGetShaderiv(m->fs, GL_COMPILE_STATUS, &err);
+   if (!err)
+     {
+        glsym_glGetShaderInfoLog(m->fs, sizeof errbuf, NULL, errbuf);
+        fprintf(stderr, "fs sigh: %s\n", errbuf);
+        return EINA_FALSE;
+     }
+
+   m->prog = glsym_glCreateProgram();
+   glsym_glAttachShader(m->prog, m->vs);
+   glsym_glAttachShader(m->prog, m->fs);
+   glsym_glBindAttribLocation(m->prog, 0, "tc");
+   glsym_glBindAttribLocation(m->prog, 1, "pos");
+   glsym_glLinkProgram(m->prog);
+   glsym_glGetProgramiv(m->prog, GL_LINK_STATUS, &err);
+   if (!err)
+     {
+        glsym_glGetProgramInfoLog(m->prog, sizeof errbuf, NULL, errbuf);
+        fprintf(stderr, "link : %s\n", errbuf);
+        return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+
+static void
+objectInit(Object *object,
+           float positionX,
+           float positionY,
+           float velocityX,
+           float velocityY)
+{
+   object->force.x = 0;
+   object->force.y = 0;
+
+   object->position.x = positionX;
+   object->position.y = positionY;
+
+   object->velocity.x = velocityX;
+   object->velocity.y = velocityY;
+
+   object->theta = 0;
+   object->immobile = EINA_FALSE;
+}
+
+static void
+springInit(Spring *spring,
+           Object *a,
+           Object *b,
+           float offsetX,
+           float offsetY)
+{
+   spring->a = a;
+   spring->b = b;
+   spring->offset.x = offsetX;
+   spring->offset.y = offsetY;
+}
+
+static void
+modelCalcBounds(Model *model)
+{
+   int i;
+
+   model->topLeft.x = MAXSHORT;
+   model->topLeft.y = MAXSHORT;
+   model->bottomRight.x = MINSHORT;
+   model->bottomRight.y = MINSHORT;
+
+   for (i = 0; i < model->numObjects; i++)
+     {
+        if (model->objects[i].position.x < model->topLeft.x)
+          model->topLeft.x = model->objects[i].position.x;
+        else if (model->objects[i].position.x > model->bottomRight.x)
+          model->bottomRight.x = model->objects[i].position.x;
+
+        if (model->objects[i].position.y < model->topLeft.y)
+          model->topLeft.y = model->objects[i].position.y;
+        else if (model->objects[i].position.y > model->bottomRight.y)
+          model->bottomRight.y = model->objects[i].position.y;
+     }
+}
+
+static void
+modelAddSpring(Model *model,
+               Object *a,
+               Object *b,
+               float offsetX,
+               float offsetY)
+{
+   Spring *spring;
+
+   spring = &model->springs[model->numSprings];
+   model->numSprings++;
+
+   springInit(spring, a, b, offsetX, offsetY);
+}
+
+static void
+modelSetMiddleAnchor(Model *model,
+                     int x,
+                     int y,
+                     int width,
+                     int height)
+{
+   float gx, gy;
+
+   gx = ((GRID_WIDTH - 1) / 2 * width) / (float)(GRID_WIDTH - 1);
+   gy = ((GRID_HEIGHT - 1) / 2 * height) / (float)(GRID_HEIGHT - 1);
+
+   if (model->anchorObject)
+     model->anchorObject->immobile = EINA_FALSE;
+
+   model->anchorObject = &model->objects[GRID_WIDTH *
+                                         ((GRID_HEIGHT - 1) / 2) +
+                                         (GRID_WIDTH - 1) / 2];
+   model->anchorObject->position.x = x + gx;
+   model->anchorObject->position.y = y + gy;
+
+   model->anchorObject->immobile = EINA_TRUE;
+}
+
+static void
+modelAdjustObjectPosition(Model *model,
+                          Object *object,
+                          int x,
+                          int y,
+                          int width,
+                          int height)
+{
+   Object *o;
+   int gridX, gridY, i = 0;
+
+   for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+     {
+        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+          {
+             o = &model->objects[i];
+             if (o == object)
+               {
+                  o->position.x = x + (gridX * width) / (GRID_WIDTH - 1);
+                  o->position.y = y + (gridY * height) / (GRID_HEIGHT - 1);
+
+                  return;
+               }
+
+             i++;
+          }
+     }
+}
+
+static void
+modelInitObjects(Model *model,
+                 int x,
+                 int y,
+                 int width,
+                 int height)
+{
+   int gridX, gridY, i = 0;
+   float gw, gh;
+
+   gw = GRID_WIDTH - 1;
+   gh = GRID_HEIGHT - 1;
+
+   for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+     {
+        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+          {
+             objectInit(&model->objects[i],
+                        x + (gridX * width) / gw,
+                        y + (gridY * height) / gh,
+                        0, 0);
+             i++;
+          }
+     }
+
+   modelSetMiddleAnchor(model, x, y, width, height);
+}
+
+static void
+modelAdjustObjectsForShiver(Model *model,
+                            int x,
+                            int y,
+                            int width,
+                            int height)
+{
+   int gridX, gridY, i = 0;
+   float vX, vY;
+   float w, h;
+   float scale;
+
+   w = width;
+   h = height;
+
+   for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+     {
+        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+          {
+             if (!model->objects[i].immobile)
+               {
+                  vX = model->objects[i].position.x - (x + w / 2);
+                  vY = model->objects[i].position.y - (y + h / 2);
+
+                  vX /= w;
+                  vY /= h;
+
+                  scale = ((float)rand() * 7.5f) / RAND_MAX;
+
+                  model->objects[i].velocity.x += vX * scale;
+                  model->objects[i].velocity.y += vY * scale;
+               }
+
+             i++;
+          }
+     }
+}
+
+static void
+modelInitSprings(Model *model,
+                 int x EINA_UNUSED,
+                 int y EINA_UNUSED,
+                 int width,
+                 int height)
+{
+   int gridX, gridY, i = 0;
+   float hpad, vpad;
+
+   model->numSprings = 0;
+
+   hpad = ((float)width) / (GRID_WIDTH - 1);
+   vpad = ((float)height) / (GRID_HEIGHT - 1);
+
+   for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+     {
+        for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+          {
+             if (gridX > 0)
+               modelAddSpring(model,
+                              &model->objects[i - 1],
+                              &model->objects[i],
+                              hpad, 0);
+
+             if (gridY > 0)
+               modelAddSpring(model,
+                              &model->objects[i - GRID_WIDTH],
+                              &model->objects[i],
+                              0, vpad);
+
+             i++;
+          }
+     }
+}
+
+Model *
+wobbly_create(int x,
+              int y,
+              int width,
+              int height)
+{
+   Model *model;
+
+   model = calloc(sizeof (Model), 1);
+   if (!model)
+     return 0;
+
+   model->numObjects = GRID_WIDTH * GRID_HEIGHT;
+   model->objects = malloc(sizeof (Object) * model->numObjects);
+   if (!model->objects)
+     {
+        free(model);
+        return 0;
+     }
+
+   model->anchorObject = 0;
+   model->numSprings = 0;
+
+   model->steps = 0;
+
+   modelInitObjects(model, x, y, width, height);
+   modelInitSprings(model, x, y, width, height);
+
+   modelCalcBounds(model);
+
+   setup_shaders(model);
+
+   return model;
+}
+
+static void
+objectApplyForce(Object *object,
+                 float fx,
+                 float fy)
+{
+   object->force.x += fx;
+   object->force.y += fy;
+}
+
+static void
+springExertForces(Spring *spring,
+                  float k)
+{
+   Vector da, db;
+   Vector a, b;
+
+   a = spring->a->position;
+   b = spring->b->position;
+
+   da.x = 0.5f * (b.x - a.x - spring->offset.x);
+   da.y = 0.5f * (b.y - a.y - spring->offset.y);
+
+   db.x = 0.5f * (a.x - b.x + spring->offset.x);
+   db.y = 0.5f * (a.y - b.y + spring->offset.y);
+
+   objectApplyForce(spring->a, k * da.x, k * da.y);
+   objectApplyForce(spring->b, k * db.x, k * db.y);
+}
+
+static float
+modelStepObject(Object *object, float *force)
+{
+   float friction = 0.8f;
+
+   object->theta += 0.05f;
+
+   if (object->immobile)
+     {
+        object->velocity.x = 0.0f;
+        object->velocity.y = 0.0f;
+
+        object->force.x = 0.0f;
+        object->force.y = 0.0f;
+
+        *force = 0.0f;
+
+        return 0.0f;
+     }
+   else
+     {
+        object->force.x -= friction * object->velocity.x;
+        object->force.y -= friction * object->velocity.y;
+
+        object->velocity.x += object->force.x / MASS;
+        object->velocity.y += object->force.y / MASS;
+
+        object->position.x += object->velocity.x;
+        object->position.y += object->velocity.y;
+
+        *force = fabs(object->force.x) + fabs(object->force.y);
+
+        object->force.x = 0.0f;
+        object->force.y = 0.0f;
+
+        return fabs(object->velocity.x) + fabs(object->velocity.y);
+     }
+}
+
+int
+modelStep(Model *model, float time)
+{
+   float k = 0.9;
+   int i, j, steps;
+   float velocitySum = 0.0f;
+   float force, forceSum = 0.0f;
+   int wobbly = 0;
+
+   if (model->wobbleGrace)
+     {
+        model->wobbleGrace--;
+        wobbly |= 4;
+     }
+
+   model->steps += time / 15.0f;
+   steps = floor(model->steps);
+   model->steps -= steps;
+
+   if (!steps)
+     return 1;
+
+   for (j = 0; j < steps; j++)
+     {
+        for (i = 0; i < model->numSprings; i++)
+          springExertForces(&model->springs[i], k);
+
+        for (i = 0; i < model->numObjects; i++)
+          {
+             velocitySum += modelStepObject(&model->objects[i], &force);
+             forceSum += force;
+          }
+     }
+
+   modelCalcBounds(model);
+
+   if (velocitySum > 0.5f)
+     wobbly |= 1; //WobblyVelocity;
+
+   if (forceSum > 20.0f)
+     wobbly |= 2; //WobblyForce;
+
+   return wobbly;
+}
+
+static void
+bezierPatchEvaluate(Model *model,
+                    float u,
+                    float v,
+                    float *patchX,
+                    float *patchY)
+{
+   float coeffsU[4], coeffsV[4];
+   float x, y;
+   int i, j;
+
+   coeffsU[0] = (1 - u) * (1 - u) * (1 - u);
+   coeffsU[1] = 3 * u * (1 - u) * (1 - u);
+   coeffsU[2] = 3 * u * u * (1 - u);
+   coeffsU[3] = u * u * u;
+
+   coeffsV[0] = (1 - v) * (1 - v) * (1 - v);
+   coeffsV[1] = 3 * v * (1 - v) * (1 - v);
+   coeffsV[2] = 3 * v * v * (1 - v);
+   coeffsV[3] = v * v * v;
+
+   x = y = 0.0f;
+
+   for (i = 0; i < 4; i++)
+     {
+        for (j = 0; j < 4; j++)
+          {
+             x += coeffsU[i] * coeffsV[j] *
+               model->objects[j * GRID_WIDTH + i].position.x;
+             y += coeffsU[i] * coeffsV[j] *
+               model->objects[j * GRID_WIDTH + i].position.y;
+          }
+     }
+
+   *patchX = x;
+   *patchY = y;
+}
+
+static float
+objectDistance(Object *object,
+               float x,
+               float y)
+{
+   float dx, dy;
+
+   dx = object->position.x - x;
+   dy = object->position.y - y;
+
+   return sqrt(dx * dx + dy * dy);
+}
+
+static Object *
+modelFindNearestObject(Model *model,
+                       float x,
+                       float y)
+{
+   Object *object = &model->objects[0];
+   float distance, minDistance = 0.0;
+   int i;
+
+   for (i = 0; i < model->numObjects; i++)
+     {
+        distance = objectDistance(&model->objects[i], x, y);
+        if (i == 0 || distance < minDistance)
+          {
+             minDistance = distance;
+             object = &model->objects[i];
+          }
+     }
+
+   return object;
+}
+
+static Eina_Bool
+moreWindowVertices(Model *m, int newSize)
+{
+   if (newSize > m->vertexSize)
+     {
+        GLfloat *vertices;
+
+        vertices = realloc(m->vertices, sizeof(GLfloat) * newSize);
+        if (!vertices) return EINA_FALSE;
+
+        m->vertices = vertices;
+        m->vertexSize = newSize;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+moreWindowIndices(Model *m, int newSize)
+{
+   if (newSize > m->indexSize)
+     {
+        GLushort *indices;
+
+        indices = realloc(m->indices, sizeof(GLushort) * newSize);
+        if (!indices) return EINA_FALSE;
+
+        m->indices = indices;
+        m->indexSize = newSize;
+     }
+
+   return EINA_TRUE;
+}
+
+void
+wobblyGeometryDo(Model *m, int in_w, int in_h)
+{
+   int nVertices, nIndices;
+   GLushort *i;
+   GLfloat *v;
+   int x1, y1, x2, y2;
+   float width, height;
+   float deformedX, deformedY;
+   int x, y, iw, ih, wx, wy;
+   int vSize;
+   int gridW, gridH;
+   int bound_w = m->bottomRight.x - m->topLeft.x;
+   int bound_h = m->bottomRight.y - m->topLeft.y;
+
+   wx = 0;
+   wy = 0;
+   width = in_w;
+   height = in_h;
+
+   gridW = width / WOBBLY_GRID_RESOLUTION;
+   if (gridW < WOBBLY_MIN_GRID_SIZE)
+     gridW = WOBBLY_MIN_GRID_SIZE;
+
+   gridH = height / WOBBLY_GRID_RESOLUTION;
+   if (gridH < WOBBLY_MIN_GRID_SIZE)
+     gridH = WOBBLY_MIN_GRID_SIZE;
+
+   vSize = 3 + 2; /* 3 vert, 2 texcoord */
+
+   nVertices = m->vCount = 0;
+   nIndices = m->indexCount = 0;
+
+   v = m->vertices + (nVertices * vSize);
+   i = m->indices + nIndices;
+
+   x1 = 0;
+   y1 = 0;
+   x2 = width;
+   y2 = height;
+
+   iw = ((x2 - x1 - 1) / gridW) + 1;
+   ih = ((y2 - y1 - 1) / gridH) + 1;
+
+   if (nIndices + (iw * ih * 6) > m->indexSize)
+     {
+        if (!moreWindowIndices(m, nIndices + (iw * ih * 6)))
+          return;
+
+        i = m->indices + nIndices;
+     }
+
+   iw++;
+   ih++;
+
+   for (y = 0; y < ih - 1; y++)
+     {
+        for (x = 0; x < iw - 1; x++)
+          {
+             *i++ = nVertices + iw * (y + 1) + x;
+             *i++ = nVertices + iw * (y + 1) + x + 1;
+             *i++ = nVertices + iw * y + x + 1;
+
+             *i++ = nVertices + iw * y + x + 1;
+             *i++ = nVertices + iw * y + x;
+             *i++ = nVertices + iw * (y + 1) + x;
+
+             nIndices += 6;
+          }
+     }
+
+   if (((nVertices + iw * ih) * vSize) > m->vertexSize)
+     {
+        if (!moreWindowVertices(m, (nVertices + iw * ih) * vSize))
+          return;
+
+        v = m->vertices + (nVertices * vSize);
+     }
+
+   for (y = y1;; y += gridH)
+     {
+        if (y > y2)
+          y = y2;
+
+        for (x = x1;; x += gridW)
+          {
+             if (x > x2)
+               x = x2;
+
+             bezierPatchEvaluate(m,
+                                 (x - wx) / width,
+                                 (y - wy) / height,
+                                 &deformedX,
+                                 &deformedY);
+
+             //Tex co-ord
+             *v++ = x / width;
+             *v++ = y / height;
+
+             // vertex
+             *v++ = -1 + ((deformedX - m->topLeft.x) / (bound_w / 2.0));
+             *v++ = -1 + ((deformedY - m->topLeft.y) / (bound_h / 2.0));
+             *v++ = 0.0;
+
+             nVertices++;
+
+             if (x == x2)
+               break;
+          }
+
+        if (y == y2)
+          break;
+     }
+
+   m->vCount = nVertices;
+   m->vertexStride = vSize;
+   m->texCoordSize = 2;
+   m->indexCount = nIndices;
+}
+
+void
+wobblyMap(Model *m, int w, int h)
+{
+   modelInitObjects(m, 0, 0, w, h);
+   modelInitSprings(m, 0, 0, w, h);
+   modelSetMiddleAnchor(m, 0, 0, w, h);
+   modelAdjustObjectsForShiver(m, 0, 0, w, h);
+   m->wobbleGrace = 10;
+}
+
+void
+wobblyMove(Model *m, int dx, int dy, int w, int h)
+{
+   m->wobbleGrace = 10;
+   modelAdjustObjectPosition(m, m->anchorObject, 0, 0, w, h);
+   m->anchorObject->position.x += dx;
+   m->anchorObject->position.y += dy;
+}
+
+void
+wobblyAnchorRelease(Model *m)
+{
+   if (m->anchorObject)
+     m->anchorObject->immobile = EINA_FALSE;
+}
+
+void
+wobblyAnchor(Model *m, int cx, int cy, int w, int h)
+{
+   wobblyAnchorRelease(m);
+   m->anchorObject = modelFindNearestObject(m, cx, h - cy);
+   m->anchorObject->immobile = EINA_TRUE;
+   modelAdjustObjectPosition(m, m->anchorObject, 0, 0, w, h);
+   m->wobbleGrace = 10;
+}
+
+void
+wobbly_resize(Model *m, int dwidth, int dheight)
+{
+   m->wobbleGrace = 10;
+   modelInitObjects(m, 0, 0, dwidth, dheight);
+   modelInitSprings(m, 0, 0, dwidth, dheight);
+   modelCalcBounds(m);
+}
+
+void
+wobbly_draw(Evas_Engine_GL_Context *gl_context, Model *m)
+{
+   GLuint tex;
+
+   glClearColor(0.0, 0.0, 0.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT);
+   glUseProgram(m->prog);
+   tex = glsym_evas_gl_common_context_redirect_texture_get(gl_context);
+   glBindTexture(GL_TEXTURE_2D, tex);
+   glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), m->vertices);
+   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), m->vertices + 2);
+   glEnableVertexAttribArray(0);
+   glEnableVertexAttribArray(1);
+   glDrawElements(GL_TRIANGLES, m->indexCount, GL_UNSIGNED_SHORT, m->indices);
+   glDisableVertexAttribArray(1);
+   glDisableVertexAttribArray(0);
+}
+
+Eina_Bool
+wobbly_process(Model *m, Evas_Engine_Info_Wayland_Egl *info, int w, int h, Eina_Bool redirected)
+{
+   int ret = EINA_FALSE;
+
+   if (info->just_mapped)
+     {
+        info->just_mapped = EINA_FALSE;
+        wobblyMap(m, w, h);
+        return EINA_TRUE;
+     }
+
+   if (info->drag_start)
+     {
+        wobblyAnchor(m, info->x_cursor, info->y_cursor, w, h);
+        ret = EINA_TRUE;
+     }
+   if (!info->resizing && (info->x_rel || info->y_rel))
+     {
+        wobblyMove(m, info->x_rel, -info->y_rel, w, h);
+        ret = EINA_TRUE;
+     }
+
+   if (info->drag_stop)
+     {
+        wobblyAnchorRelease(m);
+        ret = EINA_TRUE;
+     }
+
+   if (redirected)
+     {
+        double oldms, ms;
+
+        oldms = m->tv.tv_usec / 1000 + m->tv.tv_sec * 1000;
+        gettimeofday(&m->tv, NULL);
+        ms = m->tv.tv_usec / 1000 + m->tv.tv_sec * 1000 - oldms;
+
+        if (ms > 100) ms = 0;
+        if (modelStep(m, ms)) ret = EINA_TRUE;
+
+        wobblyGeometryDo(m, w, h);
+     }
+   return ret;
+}
+
+void
+wobbly_bounds(Model *m, float *tlx, float *tly, float *brx, float *bry)
+{
+   *tlx = m->topLeft.x;
+   *tly = m->topLeft.y;
+   *brx = m->bottomRight.x;
+   *bry = m->bottomRight.y;
+}
diff --git a/src/modules/evas/engines/wayland_egl/www.h b/src/modules/evas/engines/wayland_egl/www.h
new file mode 100644 (file)
index 0000000..99fd09f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright C 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+/*
+ * Spring model implemented by Kristian Hogsberg.
+ */
+
+#ifndef EVAS_WWW_H
+# define EVAS_WWW_H
+
+# include "../gl_generic/Evas_Engine_GL_Generic.h"
+
+typedef struct _Model Model;
+
+Model *
+wobbly_create(int x, int y, int width, int height);
+
+void
+wobbly_resize(Model *m, int dw, int dh);
+
+void
+wobbly_draw(Evas_Engine_GL_Context *gl_context, Model *m);
+
+Eina_Bool
+wobbly_process(Model *m, Evas_Engine_Info_Wayland_Egl *info, int w, int h, Eina_Bool redirected);
+
+void
+wobbly_bounds(Model *m, float *tlx, float *tly, float *brx, float *bry);
+
+#endif