From: raster Date: Mon, 20 Jun 2011 10:55:02 +0000 (+0000) Subject: Upon reviewing the elm_glview, I've realized a few issues and mistakes that i've X-Git-Tag: REL_F_I9500_20120323_1~17^2~2528 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d28cd8357a8ad84ee91b00fcc87fca868f90b1b2;p=framework%2Fuifw%2Felementary.git Upon reviewing the elm_glview, I've realized a few issues and mistakes that i've 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 --- diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 3b59fb1..229592a 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -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 \ diff --git a/src/bin/test.c b/src/bin/test.c index 66bf32a..34eaaa9 100644 --- a/src/bin/test.c +++ b/src/bin/test.c @@ -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 diff --git a/src/bin/test_glview.c b/src/bin/test_glview.c index 33450dd..3f495e1 100644 --- a/src/bin/test_glview.c +++ b/src/bin/test_glview.c @@ -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 index 0000000..ad24fe4 --- /dev/null +++ b/src/bin/test_glview_simple.c @@ -0,0 +1,288 @@ +#include +#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 diff --git a/src/lib/Elementary.h.in b/src/lib/Elementary.h.in index db62fa6..25384f0 100644 --- a/src/lib/Elementary.h.in +++ b/src/lib/Elementary.h.in @@ -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 */ diff --git a/src/lib/elm_glview.c b/src/lib/elm_glview.c index 9d0bfba..1cefec7 100644 --- a/src/lib/elm_glview.c +++ b/src/lib/elm_glview.c @@ -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.