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.

             


SVN revision: 60517
This commit is contained in:
Carsten Haitzler 2011-06-20 10:55:02 +00:00
parent 43954a560d
commit be21f7e4ea
6 changed files with 505 additions and 64 deletions

View 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 \

View 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

View 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,9 +173,18 @@ 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)
{
@ -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)
{
GLData *gld = evas_object_data_get(obj, "gld");
gears_init(gld);
}
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->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;
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);
if (!gld->initialized)
{
gears_init(gld);
gld->initialized = 1;
}
// 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);
}

View File

@ -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

View 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 */

View 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->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;
// 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);
@ -436,6 +474,70 @@ elm_glview_size_get(const Evas_Object *obj, int *width, int *height)
if (height) *height = wd->h;
}
/**
* 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.
*