d0f1f96d1e75e10ab172c214ff2aa3dc56e80275
[framework/uifw/elementary.git] / src / lib / elm_glview.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5
6 struct _Widget_Data
7 {
8 <<<<<<< HEAD
9    Evas_Object              *glview_image;
10 =======
11    Evas_Object              *glview_image;
12 >>>>>>> remotes/origin/upstream
13
14    Elm_GLView_Mode           mode;
15    Elm_GLView_Resize_Policy  scale_policy;
16    Elm_GLView_Render_Policy  render_policy;
17
18    Evas_GL                  *evasgl;
19    Evas_GL_Config           *config;
20    Evas_GL_Surface          *surface;
21    Evas_GL_Context          *context;
22
23    Evas_Coord                w, h;
24
25    Elm_GLView_Func_Cb        init_func;
26    Elm_GLView_Func_Cb        del_func;
27    Elm_GLView_Func_Cb        resize_func;
28    Elm_GLView_Func_Cb        render_func;
29
30    Ecore_Idle_Enterer       *render_idle_enterer;
31
32    Eina_Bool                 initialized;
33    Eina_Bool                 resized;
34 };
35
36 static const char *widtype = NULL;
37 static void _del_hook(Evas_Object *obj);
38 static void _on_focus_hook(void *data, Evas_Object *obj);
39
40 static const char SIG_FOCUSED[] = "focused";
41 static const char SIG_UNFOCUSED[] = "unfocused";
42
43 static void
44 _del_hook(Evas_Object *obj)
45 {
46    Widget_Data *wd = elm_widget_data_get(obj);
47    if (!wd) return;
48
49    // Call delete func if it's registered
50    if (wd->del_func)
51      {
52         evas_gl_make_current(wd->evasgl, wd->surface, wd->context);
53         wd->del_func(obj);
54      }
55
56    if (wd->render_idle_enterer) ecore_idle_enterer_del(wd->render_idle_enterer);
57
58    if (wd->surface) evas_gl_surface_destroy(wd->evasgl, wd->surface);
59    if (wd->context) evas_gl_context_destroy(wd->evasgl, wd->context);
60    if (wd->config) evas_gl_config_free(wd->config);
61    if (wd->evasgl) evas_gl_free(wd->evasgl);
62
63    free(wd);
64 }
65
66 static void
67 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
68 {
69    Widget_Data *wd = elm_widget_data_get(obj);
70    if (!wd) return;
71
72    if (elm_widget_focus_get(obj))
73      {
74         evas_object_focus_set(wd->glview_image, EINA_TRUE);
75         evas_object_smart_callback_call(obj, SIG_FOCUSED, NULL);
76      }
77    else
78      {
79         evas_object_focus_set(wd->glview_image, EINA_FALSE);
80         evas_object_smart_callback_call(obj, SIG_UNFOCUSED, NULL);
81      }
82 }
83
84 static void
85 _glview_update_surface(Evas_Object *obj)
86 {
87    Widget_Data *wd = elm_widget_data_get(obj);
88    if (!wd) return;
89
90    if (wd->surface)
91      {
92         evas_object_image_native_surface_set(wd->glview_image, NULL);
93         evas_gl_surface_destroy(wd->evasgl, wd->surface);
94         wd->surface = NULL;
95      }
96
97    evas_object_image_size_set(wd->glview_image, wd->w, wd->h);
98
99    if (!wd->surface)
100      {
101         Evas_Native_Surface ns;
102
103         wd->surface = evas_gl_surface_create(wd->evasgl, wd->config,
104                                              wd->w, wd->h);
105         evas_gl_native_surface_get(wd->evasgl, wd->surface, &ns);
106         evas_object_image_native_surface_set(wd->glview_image, &ns);
107         elm_glview_changed_set(obj);
108      }
109 }
110
111 static void
112 _glview_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
113 {
114    Widget_Data *wd = elm_widget_data_get(data);
115    Evas_Coord w, h;
116
117    if (!wd) return;
118
119    wd->resized = EINA_TRUE;
120
121    if (wd->scale_policy == ELM_GLVIEW_RESIZE_POLICY_RECREATE)
122      {
123         evas_object_geometry_get(wd->glview_image, NULL, NULL, &w, &h);
124         if ((w == 0) || (h == 0))
125           {
126              w = 64;
127              h = 64;
128           }
129         if ((wd->w == w) && (wd->h == h)) return;
130         wd->w = w;
131         wd->h = h;
132         _glview_update_surface(data);
133 <<<<<<< HEAD
134         /*
135         if (wd->render_func)
136           {
137              evas_gl_make_current(wd->evasgl, wd->surface, wd->context);
138              wd->render_func(data);
139           }
140           */
141 =======
142 >>>>>>> remotes/origin/upstream
143      }
144 }
145
146 static Eina_Bool
147 _render_cb(void *obj)
148 {
149    Widget_Data *wd = elm_widget_data_get(obj);
150    if (!wd) return EINA_FALSE;
151
152    // Do a make current
153    if (!evas_gl_make_current(wd->evasgl, wd->surface, wd->context))
154      {
155         wd->render_idle_enterer = NULL;
156         ERR("Failed doing make current.\n");
157         return EINA_FALSE;
158      }
159
160    // Call the init function if it hasn't been called already
161    if (!wd->initialized)
162      {
163         if (wd->init_func) wd->init_func(obj);
164         wd->initialized = EINA_TRUE;
165      }
166
167    if (wd->resized)
168      {
169         if (wd->resize_func) wd->resize_func(obj);
170         wd->resized = EINA_FALSE;
171      }
172
173    // Call the render function
174    if (wd->render_func) wd->render_func(obj);
175
176    // Depending on the policy return true or false
177    if (wd->render_policy == ELM_GLVIEW_RENDER_POLICY_ON_DEMAND)
178      return EINA_TRUE;
179    else if (wd->render_policy == ELM_GLVIEW_RENDER_POLICY_ALWAYS)
180      {
181         // Return false so it only runs once
182         wd->render_idle_enterer = NULL;
183         return EINA_FALSE;
184      }
185    else
186      {
187         ERR("Invalid Render Policy.\n");
188         wd->render_idle_enterer = NULL;
189         return EINA_FALSE;
190      }
191    return EINA_TRUE;
192 }
193
194 static void
195 _set_render_policy_callback(Evas_Object *obj)
196 {
197    Widget_Data *wd = elm_widget_data_get(obj);
198
199    switch (wd->render_policy)
200      {
201       case ELM_GLVIEW_RENDER_POLICY_ON_DEMAND:
202          // Delete idle_enterer if it for some reason is around
203          if (wd->render_idle_enterer)
204            {
205               ecore_idle_enterer_del(wd->render_idle_enterer);
206               wd->render_idle_enterer = NULL;
207            }
208
209          // Set pixel getter callback
210          evas_object_image_pixels_get_callback_set
211             (wd->glview_image, (Evas_Object_Image_Pixels_Get_Cb)_render_cb, obj);
212          break;
213       case ELM_GLVIEW_RENDER_POLICY_ALWAYS:
214          // Unset the pixel getter callback if set already
215          evas_object_image_pixels_get_callback_set(wd->glview_image, NULL, NULL);
216
217          break;
218       default:
219          ERR("Invalid Render Policy.\n");
220          return;
221      }
222 }
223
224 EAPI Evas_Object *
225 elm_glview_add(Evas_Object *parent)
226 {
227    Evas_Object *obj;
228    Evas *e;
229    Widget_Data *wd;
230
231    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
232
233    ELM_SET_WIDTYPE(widtype, "glview");
234    elm_widget_type_set(obj, "glview");
235    elm_widget_sub_object_add(parent, obj);
236    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
237    elm_widget_data_set(obj, wd);
238    elm_widget_del_hook_set(obj, _del_hook);
239
240    // Evas_GL
241    wd->evasgl = evas_gl_new(e);
242    if (!wd->evasgl)
243      {
244         ERR("Failed Creating an Evas GL Object.\n");
245         return NULL;
246      }
247
248    // Create a default config
249    wd->config = evas_gl_config_new();
250    if (!wd->config)
251      {
252         ERR("Failed Creating a Config Object.\n");
253         evas_gl_free(wd->evasgl);
254         return NULL;
255      }
256    wd->config->color_format = EVAS_GL_RGB_888;
257
258    // Create image to render Evas_GL Surface
259    wd->glview_image = evas_object_image_filled_add(e);
260    evas_object_image_size_set(wd->glview_image, 1, 1);
261    evas_object_event_callback_add(wd->glview_image, EVAS_CALLBACK_RESIZE,
262                                   _glview_resize, obj);
263    elm_widget_resize_object_set(obj, wd->glview_image);
264    evas_object_show(wd->glview_image);
265
266    // Initialize variables
267    wd->mode                = 0;
268    wd->scale_policy        = ELM_GLVIEW_RESIZE_POLICY_RECREATE;
269    wd->render_policy       = ELM_GLVIEW_RENDER_POLICY_ON_DEMAND;
270    wd->surface             = NULL;
271
272    // Initialize it to (64,64)  (It's an arbitrary value)
273    wd->w                   = 64;
274    wd->h                   = 64;
275
276    // Initialize the rest of the values
277    wd->init_func           = NULL;
278    wd->del_func            = NULL;
279    wd->render_func         = NULL;
280    wd->render_idle_enterer = NULL;
281    wd->initialized         = EINA_FALSE;
282    wd->resized             = EINA_FALSE;
283
284    // Create Context
285    if (!wd->context)
286      {
287         wd->context = evas_gl_context_create(wd->evasgl, NULL);
288         if (!wd->context)
289           {
290              ERR("Error Creating an Evas_GL Context.\n");
291              return NULL;
292           }
293      }
294    return obj;
295 }
296
297 EAPI Evas_GL_API *
298 elm_glview_gl_api_get(const Evas_Object *obj)
299 {
300    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
301    Widget_Data *wd = elm_widget_data_get(obj);
302    if (!wd) return NULL;
303
304    return evas_gl_api_get(wd->evasgl);
305 }
306
307 EAPI Eina_Bool
308 elm_glview_mode_set(Evas_Object *obj, Elm_GLView_Mode mode)
309 {
310    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
311    Widget_Data *wd = elm_widget_data_get(obj);
312    if (!wd) return EINA_FALSE;
313
314    // Set the configs
315    if (mode & ELM_GLVIEW_ALPHA)
316       wd->config->color_format = EVAS_GL_RGBA_8888;
317    else
318       wd->config->color_format = EVAS_GL_RGB_888;
319
320    if (mode & ELM_GLVIEW_DEPTH)
321       wd->config->depth_bits = EVAS_GL_DEPTH_BIT_24;
322    else
323       wd->config->depth_bits = EVAS_GL_DEPTH_NONE;
324
325    if (mode & ELM_GLVIEW_STENCIL)
326       wd->config->stencil_bits = EVAS_GL_STENCIL_BIT_8;
327    else
328       wd->config->stencil_bits = EVAS_GL_STENCIL_NONE;
329
330    if (mode & ELM_GLVIEW_DIRECT)
331       wd->config->options_bits = EVAS_GL_OPTIONS_DIRECT;
332    else
333       wd->config->options_bits = EVAS_GL_OPTIONS_NONE;
334
335    // Check for Alpha Channel and enable it
336    if (mode & ELM_GLVIEW_ALPHA)
337      evas_object_image_alpha_set(wd->glview_image, EINA_TRUE);
338    else
339      evas_object_image_alpha_set(wd->glview_image, EINA_FALSE);
340
341    wd->mode = mode;
342
343    elm_glview_changed_set(obj);
344
345    return EINA_TRUE;
346 }
347
348 EAPI Eina_Bool
349 elm_glview_resize_policy_set(Evas_Object *obj, Elm_GLView_Resize_Policy policy)
350 {
351    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
352    Widget_Data *wd = elm_widget_data_get(obj);
353    if (!wd) return EINA_FALSE;
354
355    if (policy == wd->scale_policy) return EINA_TRUE;
356    switch (policy)
357      {
358       case ELM_GLVIEW_RESIZE_POLICY_RECREATE:
359       case ELM_GLVIEW_RESIZE_POLICY_SCALE:
360          wd->scale_policy = policy;
361          _glview_update_surface(obj);
362          elm_glview_changed_set(obj);
363          return EINA_TRUE;
364       default:
365          ERR("Invalid Scale Policy.\n");
366          return EINA_FALSE;
367      }
368 }
369
370 EAPI Eina_Bool
371 elm_glview_render_policy_set(Evas_Object *obj, Elm_GLView_Render_Policy policy)
372 {
373    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
374    Widget_Data *wd = elm_widget_data_get(obj);
375    if (!wd) return EINA_FALSE;
376
377    if ((policy != ELM_GLVIEW_RENDER_POLICY_ON_DEMAND) &&
378        (policy != ELM_GLVIEW_RENDER_POLICY_ALWAYS))
379      {
380         ERR("Invalid Render Policy.\n");
381         return EINA_FALSE;
382      }
383    if (wd->render_policy == policy) return EINA_TRUE;
384    wd->render_policy = policy;
385    _set_render_policy_callback(obj);
386    _glview_update_surface(obj);
387    return EINA_TRUE;
388 }
389
390 EAPI void
391 <<<<<<< HEAD
392 elm_glview_size_set(Evas_Object *obj, int width, int height)
393 =======
394 elm_glview_size_set(Evas_Object *obj, int w, int h)
395 >>>>>>> remotes/origin/upstream
396 {
397    ELM_CHECK_WIDTYPE(obj, widtype);
398    Widget_Data *wd = elm_widget_data_get(obj);
399    if (!wd) return;
400
401 <<<<<<< HEAD
402    if ((width == wd->w) && (height == wd->h)) return;
403    wd->w = width;
404    wd->h = height;
405 =======
406    if ((w == wd->w) && (h == wd->h)) return;
407    wd->w = w;
408    wd->h = h;
409 >>>>>>> remotes/origin/upstream
410    _glview_update_surface(obj);
411    elm_glview_changed_set(obj);
412 }
413
414 EAPI void
415 <<<<<<< HEAD
416 elm_glview_size_get(const Evas_Object *obj, int *width, int *height)
417 =======
418 elm_glview_size_get(const Evas_Object *obj, int *w, int *h)
419 >>>>>>> remotes/origin/upstream
420 {
421    ELM_CHECK_WIDTYPE(obj, widtype);
422    Widget_Data *wd = elm_widget_data_get(obj);
423    if (!wd) return;
424
425 <<<<<<< HEAD
426    if (width) *width = wd->w;
427    if (height) *height = wd->h;
428 =======
429    if (w) *w = wd->w;
430    if (h) *h = wd->h;
431 >>>>>>> remotes/origin/upstream
432 }
433
434 EAPI void
435 elm_glview_init_func_set(Evas_Object *obj, Elm_GLView_Func_Cb func)
436 {
437    ELM_CHECK_WIDTYPE(obj, widtype);
438    Widget_Data *wd = elm_widget_data_get(obj);
439    if (!wd) return;
440
441    wd->initialized = EINA_FALSE;
442    wd->init_func = func;
443 }
444
445 EAPI void
446 elm_glview_del_func_set(Evas_Object *obj, Elm_GLView_Func_Cb func)
447 {
448    ELM_CHECK_WIDTYPE(obj, widtype);
449    Widget_Data *wd = elm_widget_data_get(obj);
450     if (!wd) return;
451
452    wd->del_func = func;
453 }
454
455 EAPI void
456 elm_glview_resize_func_set(Evas_Object *obj, Elm_GLView_Func_Cb func)
457 {
458    ELM_CHECK_WIDTYPE(obj, widtype);
459    Widget_Data *wd = elm_widget_data_get(obj);
460     if (!wd)
461      {
462         ERR("Invalid Widget Object.\n");
463         return;
464      }
465
466    wd->resize_func = func;
467 }
468
469 EAPI void
470 elm_glview_render_func_set(Evas_Object *obj, Elm_GLView_Func_Cb func)
471 {
472    ELM_CHECK_WIDTYPE(obj, widtype);
473    Widget_Data *wd = elm_widget_data_get(obj);
474    if (!wd) return;
475
476    wd->render_func = func;
477    _set_render_policy_callback(obj);
478 }
479
480 EAPI void
481 elm_glview_changed_set(Evas_Object *obj)
482 {
483    ELM_CHECK_WIDTYPE(obj, widtype);
484    Widget_Data *wd = elm_widget_data_get(obj);
485    if (!wd) return;
486
487    evas_object_image_pixels_dirty_set(wd->glview_image, EINA_TRUE);
488    if (wd->render_policy == ELM_GLVIEW_RENDER_POLICY_ALWAYS)
489      {
490         if (!wd->render_idle_enterer)
491           wd->render_idle_enterer = ecore_idle_enterer_before_add((Ecore_Task_Cb)_render_cb, obj);
492      }
493 }
494
495 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/