Page Example

GLView11Cube Sample Overview

Mobile native

The GLView11Cube sample demonstrates how you can use GLView to create a 3D cube using OpenGL ES 1.1.

Note
The application presented in this overview is not a full Tizen application, since it does not use the Application Framework. The application simply starts and runs.

This sample extends the functionality of OpenGL ES 1.1 on the Tizen platform to create spinning 3D cubes. OpenGL ES is a standard specification defining a cross-language, cross-platform API for writing applications that produce 2D and 3D computer graphics. OpenGL ES 1.1 is light-weight but powerful for hardware acceleration, improves image quality with multi-texture support, and optimizes to increase performance while reducing memory bandwidth usage to save power. GLView can support the surface for 3D rendering.

Figure: GLView11Cube

GLView11Cube

Initializing the Application

The easiest tool to use OpenGL ES within an EFL application is to rely on the Elementary GLView component.

Current GLView can support both GLES 2.0 and 1.1. GLView with the GLES 1.1 basic application has a similar format as the other GLView application.

Create a basic application:

#include <Evas_GL.h>
#include <Elementary.h>
#include <efl_extension.h>
#include <dlog.h>

The GLView application should include the header files as the <Evas_GL.h> and <Elementary.h>. The <efl_extension.h> header file is for key events and the <dlog.h> header file is for the logs view.

#define S(a) evas_object_show(a)

#define SX(a) do 
{
   evas_object_size_hint_align_set(a, EVAS_HINT_FILL, EVAS_HINT_FILL);
   evas_object_size_hint_weight_set(a, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_show(a);
} while (0)

#define SF(a) do 
{
   evas_object_size_hint_align_set(a, EVAS_HINT_FILL, EVAS_HINT_FILL);
   evas_object_size_hint_weight_set(a, 0.00001, 0.00001);
   evas_object_show(a);
} while (0)

static bool
app_create(void *data)
{
   Evas_Object *o, *t;
   appdata_s *ad = (appdata_s*)data;

   // Force OpenGL engine
   elm_config_accel_preference_set("opengl");

   // Add a window
   ad->win = o = elm_win_add(NULL,"glview", ELM_WIN_BASIC);
   evas_object_smart_callback_add(o, "delete,request", _close_cb, ad);
   evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, _win_resize_cb, ad);
   eext_object_event_callback_add(o, EEXT_CALLBACK_BACK, _close_cb, ad);
   S(o);

   // Add a background
   ad->bg = o = elm_bg_add(ad->win);
   elm_win_resize_object_add(ad->win, ad->bg);
   elm_bg_color_set(o, 68, 68, 68);
   S(o);

   // Add a resize conformant
   ad->conform = o = elm_conformant_add(ad->win);
   elm_win_resize_object_add(ad->win, ad->conform);
   SX(o);

   ad->table = t = elm_table_add(ad->win);
   S(t);

   o = elm_label_add(ad->win);
   elm_object_text_set(o, "Gles 1.1 Cube");
   elm_table_pack(t, o, 1, 0, 3, 1);
   SF(o);

   o = elm_button_add(ad->win);
   elm_object_text_set(o, "Quit");
   evas_object_smart_callback_add(o, "clicked", _close_cb, ad);
   elm_table_pack(t, o, 1, 9, 3, 1);
   SF(o);

   ad->glview = o = _glview_create(ad);
   SX(o);

   // Add an animator to call _anim_cb_() every (1/60) seconds
   // _anim_cb() indicates that glview has changed, which eventually triggers
   // function (draw_gl() here) to redraw glview surface
   
   ecore_animator_frametime_set(1.0 / 60.0);
   ad->anim = ecore_animator_add(_anim_cb, ad);
   evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_DEL, _destroy_anim, ad->anim);

   return true;
}

To set the GL rendering engine, the application calls the elm_config_accel_preference_set("opengl") function with the special string:

static Evas_Object*
_glview_create(appdata_s *ad)
{
   Evas_Object *obj;

   // Create a GLView with an OpenGL ES 1.1 context
   obj = elm_glview_version_add(ad->win, EVAS_GL_GLES_1_X);
   elm_table_pack(ad->table, obj, 1, 1, 3, 1);
   evas_object_data_set(obj, APPDATA_KEY, ad);

   elm_glview_mode_set(obj, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH);
   elm_glview_resize_policy_set(obj, ELM_GLVIEW_RESIZE_POLICY_RECREATE);
   elm_glview_render_policy_set(obj, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);

   elm_glview_init_func_set(obj, init_gles);
   elm_glview_del_func_set(obj, destroy_gles);
   elm_glview_resize_func_set(obj, resize_gl);
   elm_glview_render_func_set(obj, draw_gl);

   return obj;
}

To create GLView with GLES 1.1, use the elm_glview_version_add() function with the specific version (EVAS_GL_GLES_1_X). The current GLView can support both GLES 2.0 and 1.1.

Setting up Callbacks

To set up callbacks:

  1. Set the initialization callback.

    The initialization callback is called when the GLView is first created, after a valid OpenGL ES context and surface have been created. This is called from the main loop, as are the 3 other callbacks.

    #include <Elementary_GL_Helpers.h>

    The <Elementary_GL_Helpers.h> header file provides a set of convenient functions and macros. To use these functions and macros, include the header file in the application.

    void
    init_gles(Evas_Object *obj)
    {
       int w, h;
       appdata_s *ad;
    
       ELEMENTARY_GLVIEW_USE(obj);
       ad = evas_object_data_get(obj, APPDATA_KEY);
    
       glGenTextures(2, ad->tex_ids);
    
       // Create and map texture 1
       glBindTexture(GL_TEXTURE_2D, ad->tex_ids[0]);
       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, IMAGE_4444_128_128_1);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
       // Create and map texture 2
       glBindTexture(GL_TEXTURE_2D, ad->tex_ids[1]);
       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, IMAGE_565_128_128_1);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
       ad->current_tex_index = 0;
    
       glShadeModel(GL_SMOOTH);
    
       glEnable(GL_CULL_FACE);
       glCullFace(GL_BACK);
    
       glEnable(GL_DEPTH_TEST);
       glDepthFunc(GL_LESS);
    
       elm_glview_size_get(obj, &w, &h);
       set_perspective(obj, 60.0f, w, h, 1.0f, 400.0f);
    }
    

    In the GLES 1.1 sample, 2 textures are created and mapped in this function.

  2. Set the resize callback.

    The resize callback is called whenever the GLView component is resized. A common action to take here is to reset the viewport and matrix mode.

    void resize_gl(Evas_Object *obj)
    {
       int w, h;
    
       elm_glview_size_get(obj, &w, &h);
       set_perspective(obj, 60.0f, w, h, 1.0f, 400.0f);
    }
    
  3. Set the draw callback.

    The draw callback is called whenever a new frame has to be drawn. The exact moment when this function is called depends on the policy set when calling.

    elm_glview_render_policy_set(glview, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);

    Another policy is ELM_GLVIEW_POLICY_ALWAYS.

    The application can now draw anything using GL primitives when this callback is triggered. All draw operations are restricted to the surface of the GLView object previously created. The following example covers the whole window:

    void draw_gl(Evas_Object *obj)
    {
       ELEMENTARY_GLVIEW_USE(obj);
    
       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
       glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    
       draw_cube1(obj);
       draw_cube2(obj);
    }
    
  4. Set the delete callback.

    The delete callback is triggered when the GLView is destroyed from the main loop, and no other callback can be called on the same object afterwards. In GELS 1.1, 2 textures are deleted.

    void
    destroy_gles(Evas_Object *obj)
    {
       appdata_s *ad;
    
       ELEMENTARY_GLVIEW_USE(obj);
       ad = evas_object_data_get(obj, APPDATA_KEY);
    
       if (ad->tex_ids[0])
       {
          glDeleteTextures(1, &(ad->tex_ids[0]));
          ad->tex_ids[0] = 0;
       }
    
       if (ad->tex_ids[1])
       {
          glDeleteTextures(1, &(ad->tex_ids[1]));
          ad->tex_ids[1] = 0;
       }
    }
    
  5. Add an animator.

    The application above is technically working but the scene does not get updated unless the object is marked as such. Games usually use an animator to update the scene regularly. The following example shows the default update refresh rate.

    The animator callback function is also triggered when the display is off. Use the ecore_animator_freeze() and ecore_animator_thaw() functions in the app_pause_cb and app_resume_cb callbacks for power saving.

    static Eina_Bool
    _anim_cb(void *data)
    {
       appdata_s *ad = data;
    
       elm_glview_changed_set(ad->glview);
    
       return ECORE_CALLBACK_RENEW;
    }
    
    static void
    app_pause(void *data)
    {
       appdata_s *ad = data;
       ecore_animator_freeze(ad->anim);
    }
    
    static void
    app_resume(void *data)
    {
       appdata_s *ad = data;
       ecore_animator_thaw(ad->anim);
    }
    

    Any other event can be used to refresh the view, for example, the user input if the view does not need to be updated.

Note
OpenGL ES 1.1 application can be implemented in Tizen. However, if OpenGL ES 1.1 and OpenGL ES 2.0 are used together, they cannot be used in the same file.