Upon reviewing the elm_glview, I've realized a few issues and mistakes that i've
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 20 Jun 2011 10:55:02 +0000 (10:55 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 20 Jun 2011 10:55:02 +0000 (10:55 +0000)
made originally so I've made some changes/ updates to elm_glview

1.)  GL Resource Deletion in ELM_GLView

In order to delete GL resources, the current approach simply registered a
delete callback to the GLView object and handled resource deletion there.
Unfortunately, using the delete callback did not guarantee the glview context to be
current.  In order to guarantee that the current context was the glview context,
the make_current call needs to be called explicitly.  Since we were hiding all the
make current details in elm_glview, i've decided to add an API that registers a
delete callback function. I know that this may seem redundant since there is already
a delete callback that you can register with glview objects. Unfortunately, this is the
only option that we have apart from exposing make_current, which is something that
went again what we are trying to do with elm_glview.

Since adding delete callback alone seemed a little out of place, i've taken the liberty
to add other callback functions to make it seem consistent.

void elm_glview_init_func_set(Evas_Object *obj, Elm_GLView_Func func);
void elm_glview_del_func_set(Evas_Object *obj, Elm_GLView_Func func);
void elm_glview_resize_func_set(Evas_Object *obj, Elm_GLView_Func func);

resize callback can be controversial as well but I want to argue that adding this callback
makes the render function a lot cleaner.  To handle resize differently, the user in
render function needs to manually compare and see if the size has changed, and
then handle the cases.  Doing all of this internally once makes the developers life
a lot easier in my opinion.

these callback functions do make the render function a lot cleaner. You can check
out the updated test_glview.c or newly added test_glview_simple.

2.) Minor bug fixes/changes

elm_glview_scale_policy_set() was supposed to be elm_glview_resize_policy_set()
but it somehow evaded our reviews.  That has been fixed.

Also, in _glview_resize, after updating the surface, it was explicitly calling the
render function.  It is actually unnecessary here and calling it here will cause
problems if resize gets called before everything else is setup properly.  So that has
been commented out.

3.) test_glview & test_glview_simple

elementary_test case for glview has been updated to reflect the api changes.
when you run the elmentary_test, you need to make sure that you set
ELM_ENGINE=gl as glview currently only runs on gl backend.

test_glview runs the gears example.  For testing purposes I've included a simple
glview test case that renders a triangle and changing background color.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@60517 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/bin/Makefile.am
src/bin/test.c
src/bin/test_glview.c
src/bin/test_glview_simple.c [new file with mode: 0644]
src/lib/Elementary.h.in
src/lib/elm_glview.c

index 3b59fb1..229592a 100644 (file)
@@ -66,6 +66,7 @@ test_focus3.c \
 test_focus.c \
 test_gengrid.c \
 test_genlist.c \
+test_glview_simple.c \
 test_glview.c \
 test_grid.c \
 test_hover.c \
index 66bf32a..34eaaa9 100644 (file)
@@ -134,6 +134,7 @@ void test_segment_control(void *data, Evas_Object *obj, void *event_info);
 void test_store(void *data, Evas_Object *obj, void *event_info);
 void test_win_inline(void *data, Evas_Object *obj, void *event_info);
 void test_grid(void *data, Evas_Object *obj, void *event_info);
+void test_glview_simple(void *data, Evas_Object *obj, void *event_info);
 void test_glview(void *data, Evas_Object *obj, void *event_info);
 void test_3d(void *data, Evas_Object *obj, void *event_info);
 #ifdef HAVE_EIO
@@ -408,6 +409,7 @@ my_win_main(char *autorun)
    ADD_TEST("Store", test_store);
    ADD_TEST("Window Inline", test_win_inline);
    ADD_TEST("Grid", test_grid);
+   ADD_TEST("GLViewSimple", test_glview_simple);
    ADD_TEST("GLView", test_glview);
    ADD_TEST("3D", test_3d);
 #undef ADD_TEST
index 33450dd..3f495e1 100644 (file)
@@ -47,6 +47,7 @@ struct _GLData
 };
 
 static void gears_init(GLData *gld);
+static void free_gear(Gear *gear);
 static void gears_reshape(GLData *gld, int width, int height);
 static void render_gears(GLData *gld);
 
@@ -172,10 +173,19 @@ make_gear(GLData *gld, GLfloat inner_radius, GLfloat outer_radius, GLfloat width
    gl->glBufferData(GL_ARRAY_BUFFER, gear->count * 6 * 4,
                     gear->vertices, GL_STATIC_DRAW);
 
+
    return gear;
 }
 
 static void
+free_gear(Gear *gear)
+{
+    free(gear->vertices);
+    free(gear);
+    gear = NULL;
+}
+
+static void
 multiply(GLfloat *m, const GLfloat *n)
 {
    GLfloat tmp[16];
@@ -315,20 +325,21 @@ static const char vertex_shader[] =
    "   rotated_normal = tmp.xyz;\n"
    "}\n";
 
-static const char fragment_shader[] =
-   //"precision mediump float;\n"
+ static const char fragment_shader[] =
+   "precision mediump float;\n"
    "uniform vec4 color;\n"
    "uniform vec3 light;\n"
    "varying vec3 rotated_normal;\n"
    "varying vec3 rotated_position;\n"
    "vec3 light_direction;\n"
-   "vec4 white = vec4(0.3, 0.3, 0.5, 1.0);\n"
+   "vec4 white = vec4(0.5, 0.5, 0.5, 1.0);\n"
    "void main()\n"
    "{\n"
    "   light_direction = normalize(light - rotated_position);\n"
    "   gl_FragColor = color + white * dot(light_direction, rotated_normal);\n"
    "}\n";
 
+
 static void
 gears_init(GLData *gld)
 {
@@ -345,14 +356,14 @@ gears_init(GLData *gld)
    gl->glShaderSource(gld->vtx_shader, 1, &p, NULL);
    gl->glCompileShader(gld->vtx_shader);
    gl->glGetShaderInfoLog(gld->vtx_shader, sizeof msg, NULL, msg);
-   //printf("vertex shader info: %s\n", msg);
+   printf("vertex shader info: %s\n", msg);
 
    p = fragment_shader;
    gld->fgmt_shader = gl->glCreateShader(GL_FRAGMENT_SHADER);
    gl->glShaderSource(gld->fgmt_shader, 1, &p, NULL);
    gl->glCompileShader(gld->fgmt_shader);
    gl->glGetShaderInfoLog(gld->fgmt_shader, sizeof msg, NULL, msg);
-   //printf("fragment shader info: %s\n", msg);
+   printf("fragment shader info: %s\n", msg);
 
    gld->program = gl->glCreateProgram();
    gl->glAttachShader(gld->program, gld->vtx_shader);
@@ -362,7 +373,7 @@ gears_init(GLData *gld)
 
    gl->glLinkProgram(gld->program);
    gl->glGetProgramInfoLog(gld->program, sizeof msg, NULL, msg);
-   //printf("info: %s\n", msg);
+   printf("info: %s\n", msg);
 
    gl->glUseProgram(gld->program);
    gld->proj_location  = gl->glGetUniformLocation(gld->program, "proj");
@@ -396,24 +407,61 @@ gldata_init(GLData *gld)
 //-------------------------//
 
 static void
-_draw_gl(Evas_Object *obj)
+_init_gl(Evas_Object *obj)
 {
-   int w, h;
-   Evas_GL_API *gl = elm_glview_gl_api_get(obj);
    GLData *gld = evas_object_data_get(obj, "gld");
-   if (!gld) return;
 
-   elm_glview_size_get(obj, &w, &h);
+   gears_init(gld);
+}
 
-   if (!gld->initialized)
+static void
+_del_gl(Evas_Object *obj)
+{
+   GLData *gld = evas_object_data_get(obj, "gld");
+   if (!gld)
      {
-        gears_init(gld);
-        gld->initialized = 1;
+        printf("Unable to get GLData. \n");
+        return;
      }
+   Evas_GL_API *gl = gld->glapi;
+
+   gl->glDeleteShader(gld->vtx_shader);
+   gl->glDeleteShader(gld->fgmt_shader);
+   gl->glDeleteProgram(gld->program);
+   gl->glDeleteBuffers(1, &gld->gear1->vbo);
+   gl->glDeleteBuffers(1, &gld->gear2->vbo);
+   gl->glDeleteBuffers(1, &gld->gear3->vbo);
+
+   free_gear(gld->gear1);
+   free_gear(gld->gear2);
+   free_gear(gld->gear3);
+
+   evas_object_data_del((Evas_Object*)obj, "..gld");
+   free(gld);
+}
+
+
+static void
+_resize_gl(Evas_Object *obj)
+{
+   int w, h;
+   GLData *gld = evas_object_data_get(obj, "gld");
+
+   elm_glview_size_get(obj, &w, &h);
 
    // GL Viewport stuff. you can avoid doing this if viewport is all the
    // same as last frame if you want
    gears_reshape(gld, w,h);
+}
+
+
+
+static void
+_draw_gl(Evas_Object *obj)
+{
+   Evas_GL_API *gl = elm_glview_gl_api_get(obj);
+   GLData *gld = evas_object_data_get(obj, "gld");
+   if (!gld) return;
 
    render_gears(gld);
    gl->glFinish();
@@ -434,29 +482,15 @@ _on_done(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
 
 
 static void
-_del(void *data, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+_del(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
 {
-   GLData *gld = evas_object_data_get(data, "gld");
-   if (!gld)
-     {
-        printf("Unable to get GLData. \n");
-        return;
-     }
-   Evas_GL_API *gl = gld->glapi;
-
-   gl->glDeleteShader(gld->vtx_shader);
-   gl->glDeleteShader(gld->fgmt_shader);
-   gl->glDeleteProgram(gld->program);
-   evas_object_data_del((Evas_Object*)data, "..gld");
-   free(gld);
-
    Ecore_Animator *ani = evas_object_data_get(obj, "ani");
    ecore_animator_del(ani);
 }
 
 
 static void
-_key_down(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
+_key_down(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
 {
    Evas_Event_Key_Down *ev;
    ev = (Evas_Event_Key_Down *)event_info;
@@ -488,7 +522,7 @@ _key_down(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
    if ((strcmp(ev->keyname, "Escape") == 0) ||
        (strcmp(ev->keyname, "Return") == 0))
      {
-        _on_done(data, obj, event_info);
+        //_on_done(data, obj, event_info);
         return;
      }
 }
@@ -533,16 +567,20 @@ test_glview(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    Ecore_Animator *ani;
    GLData *gld = NULL;
 
+   // alloc a data struct to hold our relevant gl info in
    if (!(gld = calloc(1, sizeof(GLData)))) return;
    gldata_init(gld);
 
+   // new window - do the usual and give it a name, title and delete handler 
    win = elm_win_add(NULL, "glview", ELM_WIN_BASIC);
    elm_win_title_set(win, "GLView");
    elm_win_autodel_set(win, 1);
 
+
+   // add a standard bg 
    bg = elm_bg_add(win);
-   elm_win_resize_object_add(win, bg);
    evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bg);
    evas_object_show(bg);
 
    bx = elm_box_add(win);
@@ -550,38 +588,45 @@ test_glview(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info
    elm_win_resize_object_add(win, bx);
    evas_object_show(bx);
 
+   // Add a GLView
    gl = elm_glview_add(win);
    evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
-   elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH);
-//   elm_glview_scale_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_SCALE);
-//   elm_glview_size_set(gl, 256, 256);
-   elm_glview_scale_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE);
+   elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA|ELM_GLVIEW_DEPTH);
+   elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE);
    elm_glview_render_policy_set(gl, ELM_GLVIEW_RENDER_POLICY_ALWAYS);
-   elm_glview_render_func_set(gl, _draw_gl);
+   elm_glview_init_func_set(gl, _init_gl);
+   elm_glview_del_func_set(gl, _del_gl);
+   elm_glview_resize_func_set(gl, _resize_gl);
+   elm_glview_render_func_set(gl, (Elm_GLView_Func)_draw_gl);
    elm_box_pack_end(bx, gl);
    evas_object_show(gl);
 
+   // Add Mouse/Key Event Callbacks
    elm_object_focus(gl);
    evas_object_event_callback_add(gl, EVAS_CALLBACK_KEY_DOWN, _key_down, gl);
    evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, gl);
    evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_UP, _mouse_up, gl);
    evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, gl);
 
+
+   // Animator and other vars
    ani = ecore_animator_add(_anim, gl);
    gld->glapi = elm_glview_gl_api_get(gl);
    evas_object_data_set(gl, "ani", ani);
    evas_object_data_set(gl, "gld", gld);
    evas_object_event_callback_add(gl, EVAS_CALLBACK_DEL, _del, gl);
 
+
+   /* add an ok button */
    bt = elm_button_add(win);
    elm_button_label_set(bt, "OK");
    evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
-   evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0); 
    elm_box_pack_end(bx, bt);
    evas_object_show(bt);
    evas_object_smart_callback_add(bt, "clicked", _on_done, win);
-
    evas_object_resize(win, 320, 480);
    evas_object_show(win);
 }
diff --git a/src/bin/test_glview_simple.c b/src/bin/test_glview_simple.c
new file mode 100644 (file)
index 0000000..ad24fe4
--- /dev/null
@@ -0,0 +1,288 @@
+#include <Elementary.h>
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+#ifndef ELM_LIB_QUICKLAUNCH
+
+typedef struct _GLData GLData;
+
+// GL related data here..
+struct _GLData
+{
+   Evas_GL_API *glapi;
+   GLuint       program;
+   GLuint       vtx_shader;
+   GLuint       fgmt_shader;
+   GLuint       vbo;
+   int          initialized : 1;
+};
+
+
+static float red = 1.0;
+
+//--------------------------------//
+static GLuint
+load_shader( GLData *gld, GLenum type, const char *shader_src )
+{
+   Evas_GL_API *gl = gld->glapi;
+   GLuint shader;
+   GLint compiled;
+
+   // Create the shader object
+   shader = gl->glCreateShader(type);
+   if (shader==0)
+      return 0;
+
+   // Load/Compile shader source
+   gl->glShaderSource(shader, 1, &shader_src, NULL);
+   gl->glCompileShader(shader);
+   gl->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+   if (!compiled) 
+     {
+        GLint info_len = 0;
+        gl->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len);
+        if (info_len > 1)
+          {
+             char* info_log = malloc(sizeof(char) * info_len);
+
+             gl->glGetShaderInfoLog(shader, info_len, NULL, info_log);
+             printf("Error compiling shader:\n%s\n", info_log );            
+             free(info_log);
+          }
+        gl->glDeleteShader(shader);
+        return 0;
+     }
+
+   return shader;
+}
+
+// Initialize the shader and program object
+static int 
+init_shaders(GLData *gld)
+{
+   Evas_GL_API *gl = gld->glapi;
+   GLbyte vShaderStr[] =  
+      "attribute vec4 vPosition;    \n"
+      "void main()                  \n"
+      "{                            \n"
+      "   gl_Position = vPosition;  \n"
+      "}                            \n";
+
+   GLbyte fShaderStr[] =  
+      "precision mediump float;\n"\
+      "void main()                                  \n"
+      "{                                            \n"
+      "  gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n"
+      "}                                            \n";
+
+   GLint linked;
+
+   // Load the vertex/fragment shaders
+   gld->vtx_shader  = load_shader(gld, GL_VERTEX_SHADER, (const char*)vShaderStr);
+   gld->fgmt_shader = load_shader(gld, GL_FRAGMENT_SHADER, (const char*)fShaderStr);
+
+   // Create the program object
+   gld->program = gl->glCreateProgram( );
+   if (gld->program==0)
+      return 0;
+
+   gl->glAttachShader(gld->program, gld->vtx_shader);
+   gl->glAttachShader(gld->program, gld->fgmt_shader);
+
+   gl->glBindAttribLocation(gld->program, 0, "vPosition");
+   gl->glLinkProgram(gld->program);
+   gl->glGetProgramiv(gld->program, GL_LINK_STATUS, &linked);
+
+   if (!linked) 
+     {
+        GLint info_len = 0;
+        gl->glGetProgramiv(gld->program, GL_INFO_LOG_LENGTH, &info_len);
+        if (info_len > 1)
+          {
+             char* info_log = malloc(sizeof(char) * info_len);
+
+             gl->glGetProgramInfoLog(gld->program, info_len, NULL, info_log);
+             printf("Error linking program:\n%s\n", info_log);            
+             free(info_log);
+          }
+        gl->glDeleteProgram(gld->program);
+        return 0;
+     }
+   return 1;
+}
+
+
+
+// Callbacks
+static void
+_init_gl(Evas_Object *obj)
+{
+   GLData *gld = evas_object_data_get(obj, "gld");
+   Evas_GL_API *gl = gld->glapi;
+   GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f, 
+                           -0.5f, -0.5f, 0.0f,
+                            0.5f, -0.5f, 0.0f };
+
+   if (!init_shaders(gld))
+     {
+        printf("Error Initializing Shaders\n");
+        return;
+     }
+
+   gl->glGenBuffers(1, &gld->vbo);
+   gl->glBindBuffer(GL_ARRAY_BUFFER, gld->vbo);
+   gl->glBufferData(GL_ARRAY_BUFFER, 3 * 3 * 4, vVertices, GL_STATIC_DRAW);
+}
+
+static void
+_del_gl(Evas_Object *obj)
+{
+   GLData *gld = evas_object_data_get(obj, "gld");
+   if (!gld)
+     {
+        printf("Unable to get GLData. \n");
+        return;
+     }
+   Evas_GL_API *gl = gld->glapi;
+
+   gl->glDeleteShader(gld->vtx_shader);
+   gl->glDeleteShader(gld->fgmt_shader);
+   gl->glDeleteProgram(gld->program);
+   gl->glDeleteBuffers(1, &gld->vbo); 
+
+   evas_object_data_del((Evas_Object*)obj, "..gld");
+   free(gld);
+}
+
+
+static void
+_resize_gl(Evas_Object *obj)
+{
+   int w, h;
+   GLData *gld = evas_object_data_get(obj, "gld");
+   Evas_GL_API *gl = gld->glapi;
+
+   elm_glview_size_get(obj, &w, &h);
+
+   // GL Viewport stuff. you can avoid doing this if viewport is all the
+   // same as last frame if you want
+   gl->glViewport(0, 0, w, h);
+}
+
+
+
+static void
+_draw_gl(Evas_Object *obj)
+{
+   Evas_GL_API *gl = elm_glview_gl_api_get(obj);
+   GLData *gld = evas_object_data_get(obj, "gld");
+   if (!gld) return;
+   int w, h;
+
+   elm_glview_size_get(obj, &w, &h);
+
+   gl->glViewport(0, 0, w, h);
+   gl->glClearColor(red,0.8,0.3,1);
+   gl->glClear(GL_COLOR_BUFFER_BIT);
+
+   // Draw a Triangle
+   gl->glEnable(GL_BLEND);
+
+   gl->glUseProgram(gld->program);
+
+   gl->glBindBuffer(GL_ARRAY_BUFFER, gld->vbo);
+   gl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
+                             0, 0);
+   gl->glEnableVertexAttribArray(0);
+
+   gl->glDrawArrays(GL_TRIANGLES, 0, 3);
+
+   // Optional - Flush the GL pipeline
+   gl->glFinish();
+
+   red -= 0.1;
+   if (red < 0.0) red = 1.0;
+}
+
+static Eina_Bool
+_anim(void *data)
+{
+   elm_glview_changed_set(data);
+   return EINA_TRUE;
+}
+
+static void
+_on_done(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   evas_object_del((Evas_Object*)data);
+}
+
+
+static void
+_del(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+{
+   Ecore_Animator *ani = evas_object_data_get(obj, "ani");
+   ecore_animator_del(ani);
+}
+
+
+void
+test_glview_simple(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Evas_Object *win, *bg, *bx, *bt, *gl;
+   Ecore_Animator *ani;
+   GLData *gld = NULL;
+
+   if (!(gld = calloc(1, sizeof(GLData)))) return;
+
+   // Set the engine to opengl_x11
+   elm_engine_set("opengl_x11");
+
+   win = elm_win_add(NULL, "glview simple", ELM_WIN_BASIC);
+   elm_win_title_set(win, "GLView Simple");
+   elm_win_autodel_set(win, 1);
+
+   bg = elm_bg_add(win);
+   elm_win_resize_object_add(win, bg);
+   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_show(bg);
+
+   bx = elm_box_add(win);
+   evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bx);
+   evas_object_show(bx);
+
+   gl = elm_glview_add(win);
+   evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH);
+   elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE);
+   elm_glview_render_policy_set(gl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);
+   elm_glview_init_func_set(gl, _init_gl);
+   elm_glview_del_func_set(gl, _del_gl);
+   elm_glview_resize_func_set(gl, _resize_gl);
+   elm_glview_render_func_set(gl, _draw_gl);
+   elm_box_pack_end(bx, gl);
+   evas_object_show(gl);
+
+   elm_object_focus(gl);
+
+   ani = ecore_animator_add(_anim, gl);
+   gld->glapi = elm_glview_gl_api_get(gl);
+   evas_object_data_set(gl, "ani", ani);
+   evas_object_data_set(gl, "gld", gld);
+   evas_object_event_callback_add(gl, EVAS_CALLBACK_DEL, _del, gl);
+
+   bt = elm_button_add(win);
+   elm_button_label_set(bt, "OK");
+   evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
+   elm_box_pack_end(bx, bt);
+   evas_object_show(bt);
+   evas_object_smart_callback_add(bt, "clicked", _on_done, win);
+
+   evas_object_resize(win, 320, 480);
+   evas_object_show(win);
+}
+#endif
index db62fa6..25384f0 100644 (file)
@@ -1218,9 +1218,12 @@ extern "C" {
    EAPI void             elm_glview_size_get(const Evas_Object *obj, Evas_Coord *width, Evas_Coord *height) EINA_ARG_NONNULL(1);
    EAPI Evas_GL_API     *elm_glview_gl_api_get(const Evas_Object *obj) EINA_ARG_NONNULL(1);
    EAPI Eina_Bool        elm_glview_mode_set(Evas_Object *obj, Elm_GLView_Mode mode) EINA_ARG_NONNULL(1);
-   EAPI Eina_Bool        elm_glview_scale_policy_set(Evas_Object *obj, Elm_GLView_Resize_Policy policy) EINA_ARG_NONNULL(1);
+   EAPI Eina_Bool        elm_glview_resize_policy_set(Evas_Object *obj, Elm_GLView_Resize_Policy policy) EINA_ARG_NONNULL(1);
    EAPI Eina_Bool        elm_glview_render_policy_set(Evas_Object *obj, Elm_GLView_Render_Policy policy) EINA_ARG_NONNULL(1);
-   EAPI void             elm_glview_render_func_set(Evas_Object *obj, Elm_GLView_Func func);
+   EAPI void             elm_glview_init_func_set(Evas_Object *obj, Elm_GLView_Func func) EINA_ARG_NONNULL(1);
+   EAPI void             elm_glview_del_func_set(Evas_Object *obj, Elm_GLView_Func func) EINA_ARG_NONNULL(1);
+   EAPI void             elm_glview_resize_func_set(Evas_Object *obj, Elm_GLView_Func func) EINA_ARG_NONNULL(1);
+   EAPI void             elm_glview_render_func_set(Evas_Object *obj, Elm_GLView_Func func) EINA_ARG_NONNULL(1);
    EAPI void             elm_glview_changed_set(Evas_Object *obj) EINA_ARG_NONNULL(1);
 
    /* box */
index 9d0bfba..1cefec7 100644 (file)
@@ -8,29 +8,33 @@
  *
  * Signals that you can add callbacks for are:
  *
- * "clicked" - This is called when a user has clicked the image
  */
 typedef struct _Widget_Data Widget_Data;
 
 struct _Widget_Data
 {
-   Evas_Object            *glview_image;
+   Evas_Object             *glview_image;
 
-   Elm_GLView_Mode          mode;
+   Elm_GLView_Mode           mode;
    Elm_GLView_Resize_Policy  scale_policy;
-   Elm_GLView_Render_Policy render_policy;
+   Elm_GLView_Render_Policy  render_policy;
 
-   Evas_GL                 *evasgl;
-   Evas_GL_Config           config;
-   Evas_GL_Surface         *surface;
-   Evas_GL_Context         *context;
+   Evas_GL                  *evasgl;
+   Evas_GL_Config            config;
+   Evas_GL_Surface          *surface;
+   Evas_GL_Context          *context;
 
-   Evas_Coord               w, h;
+   Evas_Coord                w, h;
 
-   Elm_GLView_Func          render_func;
-   Ecore_Idle_Enterer      *render_idle_enterer;
+   Elm_GLView_Func           init_func;
+   Elm_GLView_Func           del_func;
+   Elm_GLView_Func           resize_func;
+   Elm_GLView_Func           render_func;
 
-   Eina_Bool                initialized;
+   Ecore_Idle_Enterer       *render_idle_enterer;
+
+   Eina_Bool                 initialized;
+   Eina_Bool                 resized;
 };
 
 static const char *widtype = NULL;
@@ -45,6 +49,13 @@ _del_hook(Evas_Object *obj)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
    if (!wd) return;
+   
+   // Call delete func if it's registered
+   if (wd->del_func) 
+     {
+        evas_gl_make_current(wd->evasgl, wd->surface, wd->context);
+        wd->del_func(obj);
+     }
 
    if (wd->render_idle_enterer) ecore_idle_enterer_del(wd->render_idle_enterer);
 
@@ -107,6 +118,9 @@ _glview_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void
    Evas_Coord w, h;
 
    if (!wd) return;
+
+   wd->resized = EINA_TRUE;
+
    if (wd->scale_policy == ELM_GLVIEW_RESIZE_POLICY_RECREATE)
      {
         evas_object_geometry_get(wd->glview_image, NULL, NULL, &w, &h);
@@ -119,11 +133,13 @@ _glview_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void
         wd->w = w;
         wd->h = h;
         _glview_update_surface(data);
+        /*
         if (wd->render_func)
           {
              evas_gl_make_current(wd->evasgl, wd->surface, wd->context);
              wd->render_func(data);
           }
+          */
      }
 }
 
@@ -137,9 +153,23 @@ _render_cb(void *obj)
    if (!evas_gl_make_current(wd->evasgl, wd->surface, wd->context))
      {
         wd->render_idle_enterer = NULL;
+        ERR("Failed doing make current.\n");
         return EINA_FALSE;
      }
 
+   // Call the init function if it hasn't been called already
+   if (!wd->initialized)
+     {
+        if (wd->init_func) wd->init_func(obj);
+        wd->initialized = EINA_TRUE;
+     }
+
+   if (wd->resized)
+     {
+        if (wd->resize_func) wd->resize_func(obj);
+        wd->resized = EINA_FALSE;
+     }
+
    // Call the render function
    if (wd->render_func) wd->render_func(obj);
 
@@ -183,6 +213,7 @@ _set_render_policy_callback(Evas_Object *obj)
       case ELM_GLVIEW_RENDER_POLICY_ALWAYS:
          // Unset the pixel getter callback if set already
          evas_object_image_pixels_get_callback_set(wd->glview_image, NULL, NULL);
+
          break;
       default:
          ERR("Invalid Render Policy.\n");
@@ -234,16 +265,23 @@ elm_glview_add(Evas_Object *parent)
    evas_object_show(wd->glview_image);
 
    // Initialize variables
-   wd->mode          = 0;
-   wd->scale_policy  = ELM_GLVIEW_RESIZE_POLICY_RECREATE;
-   wd->render_policy = ELM_GLVIEW_RENDER_POLICY_ON_DEMAND;
-   wd->config        = cfg;
-   wd->surface       = NULL;
-
-   wd->w             = 64;
-   wd->h             = 64;
-
+   wd->mode                = 0;
+   wd->scale_policy        = ELM_GLVIEW_RESIZE_POLICY_RECREATE;
+   wd->render_policy       = ELM_GLVIEW_RENDER_POLICY_ON_DEMAND;
+   wd->config              = cfg;
+   wd->surface             = NULL;
+
+   // Initialize it to (64,64)  (It's an arbitrary value)
+   wd->w                   = 64;
+   wd->h                   = 64;
+
+   // Initialize the rest of the values
+   wd->init_func           = NULL;
+   wd->del_func            = NULL;
+   wd->render_func         = NULL;
    wd->render_idle_enterer = NULL;
+   wd->initialized         = EINA_FALSE;
+   wd->resized             = EINA_FALSE;
 
    // Create Context
    if (!wd->context)
@@ -321,12 +359,12 @@ elm_glview_mode_set(Evas_Object *obj, Elm_GLView_Mode mode)
 }
 
 /**
- * Set the scaling policy for the glview object.
+ * Set the resize policy for the glview object.
  *
  * @param obj The glview object.
  * @param policy The scaling policy.
  *
- * By default, the scaling policy is set to ELM_GLVIEW_RESIZE_POLICY_RECREATE.
+ * By default, the resize policy is set to ELM_GLVIEW_RESIZE_POLICY_RECREATE.
  * When resize is called it destroys the previous surface and recreates the newly
  * specified size. If the policy is set to ELM_GLVIEW_RESIZE_POLICY_SCALE, however,
  * glview only scales the image object and not the underlying GL Surface.
@@ -334,7 +372,7 @@ elm_glview_mode_set(Evas_Object *obj, Elm_GLView_Mode mode)
  * @ingroup GLView
  */
 EAPI Eina_Bool
-elm_glview_scale_policy_set(Evas_Object *obj, Elm_GLView_Resize_Policy policy)
+elm_glview_resize_policy_set(Evas_Object *obj, Elm_GLView_Resize_Policy policy)
 {
    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
    Widget_Data *wd = elm_widget_data_get(obj);
@@ -437,6 +475,70 @@ elm_glview_size_get(const Evas_Object *obj, int *width, int *height)
 }
 
 /**
+ * Set the init function that runs once in the main loop.
+ *
+ * @param obj The glview object.
+ * @param func The init function to be registered.
+ *
+ * The registered init function gets called once during the render loop.
+ * 
+ * @ingroup GLView
+ */
+EAPI void
+elm_glview_init_func_set(Evas_Object *obj, Elm_GLView_Func func)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   wd->initialized = EINA_FALSE;
+   wd->init_func = func;
+}
+
+/**
+ * Set the render function that runs in the main loop.
+ *
+ * @param obj The glview object.
+ * @param func The delete function to be registered.
+ *
+ * The registered del function gets called when GLView object is deleted.
+ * 
+ * @ingroup GLView
+ */
+EAPI void
+elm_glview_del_func_set(Evas_Object *obj, Elm_GLView_Func func)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+    if (!wd) return;
+
+   wd->del_func = func;
+}
+
+/**
+ * Set the resize function that gets called when resize happens.
+ *
+ * @param obj The glview object.
+ * @param func The resize function to be registered.
+ *
+ * @ingroup GLView
+ */
+EAPI void
+elm_glview_resize_func_set(Evas_Object *obj, Elm_GLView_Func func)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd = elm_widget_data_get(obj);
+    if (!wd) 
+     {
+        ERR("Invalid Widget Object.\n");
+        return;
+     }
+
+   wd->resize_func = func;
+}
+
+
+/**
  * Set the render function that runs in the main loop.
  *
  * @param obj The glview object.