From f6338cac2a1c6d504ad6e1dce66b8bb8ef1f5dfe Mon Sep 17 00:00:00 2001 From: DaeKwang Ryu Date: Thu, 31 Dec 2015 09:39:47 +0900 Subject: [PATCH] [Graphics] modify GLView tutorial to EvasGL tutorial Change-Id: Ibb6d96721a1ebf8cdc8b7873436252b98652eb38 Signed-off-by: DaeKwang Ryu --- .../html/native/graphics/opengl_tutorial_n.htm | 1665 ++------------------ 1 file changed, 154 insertions(+), 1511 deletions(-) diff --git a/org.tizen.tutorials/html/native/graphics/opengl_tutorial_n.htm b/org.tizen.tutorials/html/native/graphics/opengl_tutorial_n.htm index b44c69f..28fbec3 100644 --- a/org.tizen.tutorials/html/native/graphics/opengl_tutorial_n.htm +++ b/org.tizen.tutorials/html/native/graphics/opengl_tutorial_n.htm @@ -23,16 +23,13 @@

Content

    -
  • GLView component +
  • EvasGL Tutorial
  • Using OpenGL ES Extensions
  • @@ -51,29 +48,23 @@

    OpenGL ES: Using OpenGL ES Graphics

    -

    This tutorial demonstrates how you can handle OpenGL ES graphics with the GLView component and EvasGL.

    +

    This tutorial demonstrates how you can handle OpenGL ES graphics with the GLView component EvasGL. Before reading this page, it is recommended to read OpenGL ES Guide page first.

    Warm-up

    Become familiar with the OpenGL ES API basics by learning about:

    -

    Creating a Basic Application

    +

    EvasGL Tutorial

    -

    This tutorial demonstrates how you can create a multicolored 3D rotating cube using the OpenGL ES 2.0 API provided by the GLView library. Several concepts are explained, such as the cube geometry, the initialization phase of the model, the adjustment of the model frame by frame, and the way to design the OpenGL ES rendering loop.

    -

    To create the basic application:

    -
      -
    1. Create a basic application as explained in the Hello World example.

      -

      The basic UI application skeleton already makes available the window object that contains the GLView canvas.

      -
    2. -
    3. Build the environment: - -

      Define the application data structure that holds all the objects pertinent for the GLView application:

      -
        -
      • win: Application window
      • -
      • conform: Conformant object for the indicator
      • -
      • glview: GLView object
      • -
      • main_box: Box object which contains glview and inner_box
      • -
      • inner_box: Box object for the toolbox
      • -
      -
      -typedef struct 
      -appdata 
      -{
      -   Evas_Object *win;
      -   Evas_Object *conform;
      -   Evas_Object *glview;
      -
      -   Evas_Object *main_box;
      -   Evas_Object *inner_box;
      -} appdata_s;
      -
    4. - -
    5. +

      This tutorial assumes that the application uses EvasGL directly instead of using the GLView. (If the application uses a GLView, EvasGL is created internally.)

      -

      Create the OpenGL ES canvas:

      -
        -
      1. -

        When developing an application with Elementary, you can create a window by using the Elementary utility function.

        -

        To develop a GL application, you have to call the elm_config_accel_preference_set() function before creating a window which makes an application to use the GPU.

        -
        -elm_config_accel_preference_set("opengl"); 
        -ad->win = elm_win_util_standard_add("GLView Example", "GLView Example");
        -
      2. -
      3. -

        Create the GLView and prepare the application to call the GL functions:

        -
        -ad->glview = elm_glview_add(ad->main_box);
        +

        First, you can declare the global variable using the EVAS_GL_GLOBAL_GLES2_DEFINE() macro. Then, create an EvasGL and use EVAS_GL_GLOBAL_GLES2_USE(evasgl, evasgl context). This is similar to the GLView macro. Both macros help you to call GL functions directly.

        -

        There are 2 different methods to call GL functions:

        +

        Now, you can call GL functions. For more detailed information, see the Evas_GL_GLES2_Helpers.h file.

        -
        • Use Elementary GL Helper functions. You have to include the Elementary_GL_Helpers.h header file and define a global variable using ELEMENTARY_GLVIEW_GLOBAL_DEFINE(). Before calling GL functions, write ELEMENTARY_GLVIEW_GLOBAL_USE(). -

          This tutorial uses this method.

          -#include <Elementary_GL_Helpers.h>
          -ELEMENTARY_GLVIEW_GLOBAL_DEFINE();
          +#include <app.h>
          +#include <Evas_GL_GLES2_Helpers.h>
           
          -static void 
          -create_gl_canvas(appdata_s *ad) 
          -{
          -   ad->glview = elm_glview_add(ad->main_box);
          -   ELEMENTARY_GLVIEW_GLOBAL_USE(ad->glview);
          -}
          +// This code is to be placed at the beginning of any function using GLES 2.0 APIs
          +// When using this macro, you can call all glFunctions without changing their code
          +// For details, see Evas_GL_GLES2_Helpers.h
          +EVAS_GL_GLOBAL_GLES2_DEFINE();
          +
          -static void -draw_gl(Evas_Object *obj) -{ -   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -}
        • +

          Declaration of EvasGL Objects

          -
        • Get the Evas_GL instance from the elm_glview_gl_api_get() function, and call the OpenGL ES functions with the instance:

          +

          This is how to define the application data structure to hold all the objects for your EvasGL application:

          -ad->glview = elm_glview_add(ad->main_box);
          -Evas_GL_API *glapi = elm_glview_gl_api_get(ad->glview);
          -glapi->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        -
      4. -
      5. -

        Set the GLView mode. The elm_glview_mode_set() function supports alpha, depth, stencil, MSAA, and client-side rotation.

        +typedef struct appdata +{ +   Evas_Object *win; +   Evas_Object *img; -
        -elm_glview_mode_set(ad->glview, ELM_GLVIEW_DEPTH);
        -
      6. -
      7. -

        Set up callbacks:

        -
          -
        • Callback for initialization -

          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, just as the 3 other callbacks.

          -
          -elm_glview_init_func_set(ad->glview, init_gl);
          -
          -
        • -
        • Callback for resizing -

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

          -
          -elm_glview_resize_func_set(ad->glview, resize_gl);
          -
          -
        • -
        • Callback for drawing -

          The drawing callback is called whenever a new frame has to be drawn.

          -
          -elm_glview_render_func_set(ad->glview, draw_gl);
          -
          -

          The exact moment when this function is called depends on the policy set when calling.

          +   Evas_GL *evasgl; +   Evas_GL_Context *ctx; +   Evas_GL_Surface *sfc; +   Evas_GL_Config *cfg; +   Evas_Coord sfc_w; +   Evas_Coord sfc_h; -
          -elm_glview_render_policy_set(glview, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);
          +   unsigned int program; +   unsigned int vtx_shader; +   unsigned int fgmt_shader; +   unsigned int vbo; +} appdata_s; -

          Another policy is ELM_GLVIEW_POLICY_ALWAYS, which always requests render, even when it is not visible. So the on demand policy is probably what you are looking for. 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. Here it covers the whole window.

          -
        • -
        • Callback for deleting -

          The delete callback is triggered when the GLView is being destroyed, from the main loop, and no other callback can be called on the same object afterwards.

          -
          -elm_glview_del_func_set(ad->glview, del_gl);
          -
          -
        • +
            +
          • Evas_Object *win: Application window.
          • +
          • Evas_Object *img: OpenGL ES canvas.
          • +
          • Evas_GL *evasgl: EvasGL Object for rendering gl in Evas.
          • +
          • Evas_GL_Context *ctx: EvasGL Context object, a GL rendering context in Evas GL.
          • +
          • Evas_GL_Surface *sfc: EvasGL Surface object, a GL rendering target in Evas GL.
          • +
          • Evas_GL_Config *cfg: EvasGL Surface configuration object for surface creation.
          - -
        • Add an animator. -

          The application above is technically working but the scene does not get updated unless the object is marked as such. Games may want to use an animator to have a regular update of the scene.

          -
          -ad->ani = ecore_animator_add(animate_cb, ad->glview);
          -

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

          -
        • -
      -
    6. -
    +

    Creating the Elm Window and EvasGL

    -

    Creating a Cube

    - -

    Creating and coloring the cube can be separated into 2 distinct tasks: define the vertices and then add the colors to the faces.

    +

    To create the Elm window and EvasGL:

    +
      +
    1. Creating a window and a EvasGL. +

      For developing an application with Elementary, you create a window by using the Elementary utility function, elm_win_util_standard_add(). To develop a GL application, you have to call elm_config_accel_preference_set() before creating the window. It makes an application use the GPU. See the following code. +

      +
      +Evas_Object *win;
       
      -  

      Figure: Cube

      -

      Cube

      -

      To create and color the cube:

      -
        -
      1. Declare an array that stores the vertices of the cube to make it look like the drawing above.

        -
        -static const float 
        -vertices[] =
        -{
        -   // Front
        -   -0.5f, 0.5f, 0.5f,
        -   -0.5f, -0.5f, 0.5f,
        -   0.5f, 0.5f, 0.5f,
        -   0.5f, 0.5f, 0.5f,
        -   -0.5f, -0.5f, 0.5f,
        -   0.5f, -0.5f, 0.5f,
        -   // Right
        -   0.5f, 0.5f, 0.5f,
        -   0.5f, -0.5f, 0.5f,
        -   0.5f, 0.5f, -0.5f,
        -   0.5f, 0.5f, -0.5f,
        -   0.5f, -0.5f, 0.5f,
        -   0.5f, -0.5f, -0.5f,
        -   // Back
        -   0.5f, 0.5f, -0.5f,
        -   0.5f, -0.5f, -0.5f,
        -   -0.5f, 0.5f, -0.5f,
        -   -0.5f, 0.5f, -0.5f,
        -   0.5f, -0.5f, -0.5f,
        -   -0.5f, -0.5f, -0.5f,
        -   // Left
        -   -0.5f, 0.5f, -0.5f,
        -   -0.5f, -0.5f, -0.5f,
        -   -0.5f, 0.5f, 0.5f,
        -   -0.5f, 0.5f, 0.5f,
        -   -0.5f, -0.5f, -0.5f,
        -   -0.5f, -0.5f, 0.5f,
        -   // Top
        -   -0.5f, 0.5f, -0.5f,
        -   -0.5f, 0.5f, 0.5f,
        -   0.5f, 0.5f, -0.5f,
        -   0.5f, 0.5f, -0.5f,
        -   -0.5f, 0.5f, 0.5f,
        -   0.5f, 0.5f, 0.5f,
        -   // Bottom
        -   -0.5f, -0.5f, 0.5f,
        -   -0.5f, -0.5f, -0.5f,
        -   0.5f, -0.5f, 0.5f,
        -   0.5f, -0.5f, 0.5f,
        -   -0.5f, -0.5f, -0.5f,
        -   0.5f, -0.5f, -0.5f
        -};
        +// To use OpenGL ES, the application must switch on hardware acceleration
        +// To enable that, call elm_config_accel_preference_set() with "opengl"
        +// before creating the Elm window
        +// This function is supported since 2.3.
        +elm_config_accel_preference_set("opengl");
        +// Creating Elm window
        +ad->win = elm_win_util_standard_add("Evas_GL Example", "Evas_GL Example");
         
        -

        Figure: Cube matrix

        -

        Cube matrix

        +

        You can create your EvasGL handler using the evas_gl_new(Evas * e) function. This initializer takes as a parameter the Evas canvas on which OpenGL ES is to be used. When developing an application with Elementary, use the canvas of your window:

        +
        ad->evasgl = evas_gl_new(evas_object_evas_get(ad->win));
        -

        Each triangle is defined with 3 point coordinates, 3 vertices for each triangle, 2 triangles per face and 6 faces. There are 36 vertices is total.

        -
      2. -
      3. -

        Specify a color for each face of the cube. Each color is represented in the RGBA format for the corresponding vertex, where each component is ranged from 0 to 1 where 1 is the maximum value. For example, in 32-byte color space, the RGB color of (16, 147, 237) is translated as (0.0625, 0.57421875, 0.92578125). The A of RGBA stands for the alpha channel, which represents the transparency of the color. All colors defined in this tutorial are opaque to make it simpler, so each alpha value is set to 1.0. In this example, different variants of blue are used for the faces of the cube.

        -

        Specify the colors of the cube into an array dedicated to this vertex:

        -
        -static const float 
        -colors[] =
        -{
        -   // Front
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   // Right
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   // Back
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   // Left
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   0.0625f, 0.57421875f, 0.92578125f, 1.0f,
        -   // Top
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f,
        -   // Bottom
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f,
        -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f
        -};
        -
        +

        To free the memory allocated to this handler, use the evas_gl_free(Evas_GL *evas_gl) function.

      4. -
      - -

      Drawing the Cube with GLView

      +
    2. Create a surface. -

      After the model is initialized, create functionality to manipulate the scene. OpenGL ES 2.0 provided by GLView requires more preliminary work than the previous version of the library, but it gives you more power and flexibility, although this example does not take much benefit.

      -

      To draw the cube with GLView and use mathematical functions for matrices:

      +

      You must allocate a new config object to fill the surface out using the evas_gl_config_new() function. As long as Evas creates a config object for the user, it takes care of the backward compatibility issue. Once you have your config object, you can specify the surface settings:

      -
        -
      1. -

        Declare additional global variables for tasks specific to OpenGL ES 2.0. A program object is needed, an identifier for the vertices buffer, and another for the colors. Variables are also required to ensure the connection with the shader language:

        -
          -
        • mvpLoc: Identifier for model-view-projection matrix
        • -
        • positionLoc: Identifier for the vertex position
        • -
        • colorLoc: Identifier for the vertex color
        • -
        -

        Declare all these variables in the appdata object as static variables so that each function can use variables and that they exist for the whole duration of the program:

        -
        -typedef struct 
        -appdata 
        -{
        -   unsigned int program;
        -   unsigned int vtx_shader;
        -   unsigned int fgmt_shader;
        -   unsigned int vertexID;
        -   unsigned int colorID;
        -   unsigned int mvpLoc;
        -   unsigned int positionLoc;
        -   unsigned int colorLoc;
        -}
        -
        -
      2. -
      3. -

        Since OpenGL ES 2.0, some functions for matrix transformations have been removed. Define 3 matrices (projection matrix, model-view matrix, and a combination of these) to allow you to perform any transformations on the initial vertices matrix.

        -
          -
        • Create the matrix multiplication function. -

          Define a function that is able to return the inner product of 2 matrices. This function reproduces the behavior of the glMultMatrix() function available in OpenGL ES 1.1. This function is very useful since almost every matrix transformation can be translated as multiplications of matrices.

          -

          The function takes 3 parameters, 1 is for the result and the other 2 matrices are operands.

          -static void
          -customMutlMatrix(float matrix[16], const float matrix0[16], const float matrix1[16])
          -{
          -   int i, row, column;
          -   float temp[16];
          -   for (column = 0; column < 4; column++) 
          -   {
          -      for (row = 0; row < 4; row++) 
          -      {
          -         temp[column * 4 + row] = 0.0f;
          -         for (i = 0; i < 4; i++)
          -            temp[column * 4 + row] += matrix0[i * 4 + row] * matrix1[column * 4 + i];
          -      }
          -   }
          -   for (i = 0; i < 16; i++)
          -      matrix[i] = temp[i];
          -}
          +appdata_s *ad;
          +ad->cfg = evas_gl_config_new();
          +ad->cfg->color_format = EVAS_GL_RGBA_8888; // Surface Color Format
          +ad->cfg->depth_bits = EVAS_GL_DEPTH_BIT_24; // Surface Depth Format
          +ad->cfg->stencil_bits = EVAS_GL_STENCIL_NONE; // Surface Stencil Format
          +ad->cfg->options_bits = EVAS_GL_OPTIONS_NONE; // Configuration options (here, no extra options)
           
          -
        • -
        • Create the matrix identity function. -

          Implement a function equivalent to the glLoadIdentity() function that replaces the current matrix with the identity matrix.

          -
          -const float 
          -unit_matrix[] = 
          -{
          -   1.0f, 0.0f, 0.0f, 0.0f,
          -   0.0f, 1.0f, 0.0f, 0.0f,
          -   0.0f, 0.0f, 1.0f, 0.0f,
          -   0.0f, 0.0f, 0.0f, 1.0f
          -}
           
          -static void
          -customLoadIdentity(float matrix[16])
          -{
          -   for (int i = 0; i < 16; i++)
          -      matrix[i] = unit_matrix[i];
          -}
          -
          -
        • -
        • Create the matrix projection function. -

          Since the glFrustum() function has been deprecated, implement a function that produces perspective projection matrices that are used to transform from eye coordinate space to clip coordinate space. This matrix projects a portion of the space (the "frustum") to your screen. Many caveats apply (such as normalized device coordinates and perspective divide), but that is the idea.

          -
          -static int
          -customFrustum(float result[16], 
          -              const float left, const float right, 
          -              const float bottom, const float top, 
          -              const float near, const float far)
          -{
          -   if ((right - left) == 0.0f || (top - bottom) == 0.0f || (far - near) == 0.0f) 
          -      return 0;
          -
          -   result[0] = 2.0f / (right - left);
          -   result[1] = 0.0f;
          -   result[2] = 0.0f;
          -   result[3] = 0.0f;
          -
          -   result[4] = 0.0f;
          -   result[5] = 2.0f / (top - bottom);
          -   result[6] = 0.0f;
          -   result[7] = 0.0f;
          -
          -   result[8] = 0.0f;
          -   result[9] = 0.0f;
          -   result[10] = -2.0f / (far - near);
          -   result[11] = 0.0f;
          -
          -   result[12] = -(right + left) / (right - left);
          -   result[13] = -(top + bottom) / (top - bottom);
          -   result[14] = -(far + near) / (far - near);
          -   result[15] = 1.0f;
          -
          -   return 1;
          -}
          -
          -
        • -
        • Create the matrix scaling function. -

          The deprecated glScale() function represents a non-uniform scaling along the X, Y, and Z axes. The 3 parameters indicate the desired scale factor along each of the 3 axes.

          -
          -const float 
          -scale_matrix[] = 
          -{
          -   x, 0.0f, 0.0f, 0.0f,
          -   0.0f, y, 0.0f, 0.0f,
          -   0.0f, 0.0f, z, 0.0f,
          -   0.0f, 0.0f, 0.0f, 1.0f
          -}
          -
          -

          The following example shows the implementation of the matrix scaling function:

          -
          static void
          -customScale(float matrix[16], const float sx, const float sy, const float sz)
          -{ 
          -   matrix[0]  *= sx; 
          -   matrix[1]  *= sx; 
          -   matrix[2]  *= sx; 
          -   matrix[3]  *= sx; 
          -
          -   matrix[4]  *= sy; 
          -   matrix[5]  *= sy; 
          -   matrix[6]  *= sy; 
          -   matrix[7]  *= sy; 
          -
          -   matrix[8]  *= sz; 
          -   matrix[9]  *= sz; 
          -   matrix[10] *= sz; 
          -   matrix[11] *= sz; 
          -}
          -
          -
        • +

          Once we have configured the surface behavior, we must initialize the surface using evas_gl_surface_create(Evas_GL* evas_gl, Evas_GL_Config * cfg, int w, int h). This function takes the given Evas_GL object as the first parameter and the pixel format, and configuration of the rendering surface as the second parameter. The last two parameters are the width and height of the surface, which we recover directly from the window.

          -
        • Create the matrix rotation function. -

          Define a function to represent a rotation by the vector (X Y Z). The current matrix is multiplied by a rotation matrix.

          -
          -static void
          -customRotate(float matrix[16], const float anglex, const float angley, const floatanglez)
          -{
          -   const float pi = 3.141592f;
          -   float temp[16];
          -   float rz = 2.0f * pi * anglez / 360.0f;
          -   float rx = 2.0f * pi * anglex / 360.0f;
          -   float ry = 2.0f * pi * angley / 360.0f;
          -   float sy = sinf(ry);
          -   float cy = cosf(ry);
          -   float sx = sinf(rx);
          -   float cx = cosf(rx);
          -   float sz = sinf(rz);
          -   float cz = cosf(rz);
          -
          -   customLoadIdentity(temp);
          -
          -   temp[0] = cy * cz - sx * sy * sz;
          -   temp[1] = cz * sx * sy + cy * sz;
          -   temp[2] = -cx * sy;
          -
          -   temp[4] = -cx * sz;
          -   temp[5] = cx * cz;
          -   temp[6] = sx;
          -
          -   temp[8] = cz * sy + cy * sx * sz;
          -   temp[9] = -cy * cz * sx + sy * sz;
          -   temp[10] = cx * cy;
          -
          -   customMultMatrix(matrix, matrix, temp);
          -}
          -
          -
        • -
        -
      4. -
      5. Create the shader: -
          -
        1. -

          Define the source for the shader using a string array. First build a vertex shader, which is used to a medium precision for float values. Then build a uniform matrix with dimensions 4x4 intended to hold the model-view-projection matrix. In addition, create 2 vector attributes which have 4 components for the vertex position and the color. Finally, the varying v_color variable can be accessed from the fragment shader.

          -

          In the main function of the shader, initialize the position of the current vertex, gl_Position, with the product of the vertex position and the model-view-projection matrix, to normalize the position for the target screen. The pixel color is calculated by the varying variable from the vertex shader.

          -

          In the fragment shader, declare a varying variable, and set the color of the pixel with this interpolated color.

          -static const char 
          -vertex_shader[] =
          -   "precision mediump float;"
          -   "uniform mat4 u_mvpMat;"
          -   "attribute vec4 a_position;"
          -   "attribute vec4 a_color;"
          -   "varying vec4 v_color;"
          -   "void main()"
          -   "{"
          -      "gl_Position = u_mvpMat * a_position;"
          -      "v_color = a_color;"
          -   "}";
          -
          -static const char 
          -fragment_shader[] =
          -   "varying lowp vec4 v_color;"
          -   "void main()"
          -   "{"
          -      "gl_FragColor = v_color;"
          -   "}";
          +Evas_Coord w, h;
          +evas_object_geometry_get(ad->win, NULL, NULL, &w, &h);
          +ad->sfc = evas_gl_surface_create(ad->evasgl, ad->cfg, w, h);
           
          -
        2. -
        3. -

          Create the shaders, attach the source code defined above, and compile the program object:

          -
          -static void
          -initShaders(void* data)
          -{
          -   const char *p;
          -   appdata_s *ad = data;
           
          -   p = vertex_shader;
          -   ad->vtx_shader = glCreateShader(GL_VERTEX_SHADER);
          -   glShaderSource(ad->vtx_shader, 1, &p, NULL);
          -   glCompileShader(ad->vtx_shader);
          -
          -   p = fragment_shader;
          -   ad->fgmt_shader = glCreateShader(GL_FRAGMENT_SHADER);
          -   glShaderSource(ad->fgmt_shader, 1, &p, NULL);
          -   glCompileShader(ad->fgmt_shader);
          -
          -
        4. -
        5. -

          Once the shaders are ready, instantiate the program object and link the shaders. If the linking succeeds, you can destroy the shaders afterwards (using the glDeleteShader() function). Since they are inside the program object, it is pointless to keep them in memory.

          -
          -   ad->program = glCreateProgram();
          +

          To manually delete a GL surface, use the evas_gl_surface_destroy(Evas_GL *evas_gl, Evas_GL_Surface *surf) function.

        6. -   glAttachShader(ad->program, ad->vtx_shader); -   glAttachShader(ad->program, ad->fgmt_shader); +
        7. Create a context. -   glDeleteShader(ad->vtx_shader); -   glDeleteShader(ad->fgmt_shader); +

          Create a context for Evas_GL using the evas_gl_context_create(Evas_GL * evas_gl, Evas_GL_Context * share_ctx) function. You can merge the context with a higher context definition you must pass as a second parameter.

          -   glLinkProgram(ad->program); -
    3. -
    4. -
    5. -

      For shader process, create identifiers for the attribute variables used in the shader program. Create an identifier for the model-view-projection matrix, another one for the current vertex position, and a last one for the vertex color.

      -
      -   ad->mvpLoc = glGetUniformLocation(ad->program, "u_mvpMat");
      -   ad->positionLoc = glGetAttribLocation(ad->program, "a_position");
      -   ad->colorLoc = glGetAttribLocation(ad->program, "a_color");
      -
      -
    6. -
    7. -

      Generate the buffers for the vertex positions and colors:

      -   glGenBuffers(1, &ad->vertexID);
      -   glBindBuffer(GL_ARRAY_BUFFER, ad->vertexID);
      -   glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
      +ad->ctx = evas_gl_context_create(ad->evasgl, NULL);
       
      -   glGenBuffers(1, &ad->colorID);
      -   glBindBuffer(GL_ARRAY_BUFFER, ad->colorID);
      -   glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
      -}
      +// This macro sets the global variable holding the GL API,
      +// so that it is available to the application
      +// Use it right after setting up the GL context object
      +// For details, see Evas_GL_GLES2_Helpers.h
      +EVAS_GL_GLOBAL_GLES2_USE(ad->evasgl, ad->ctx);
       
      -
    8. -
    9. -

      Allocate memory for the matrix and load a unit matrix into it. Define the value that is used to build the perspective projection matrix with the customFrustum() function. Multiply this resulting matrix with a resizing matrix, so the model is correctly adjusted to the screen.

      -
      -float aspect;
      -customLoadIdentity(view);
       
      -if (w > h) 
      -{
      -   aspect = (float)w/h;
      -   customFrustum(view, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0, -1.0, 1.0);
      -}
      -else 
      -{
      -   aspect = (float)h/w;
      -   customFrustum(view, -1.0, 1.0, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
      -}
      -
      -
    10. -
    - +

    To delete the context later, use the evas_gl_context_destroy(Evas_GL *evas_gl, Evas_GL_Context *ctx) function. To delete the entire configuration object, use the evas_gl_config_free(Evas_GL_Config *cfg) function instead.

    + -

    Rendering the Cube

    +

    Getting OpenGL ES APIs

    -

    To render the cube:

    -
      -
    1. -

      Set the viewport at 0,0 corresponding to the bottom left edge of the window, and the height and width of the GL surface. Clear the depth and the color buffers to the values that were selected during initialization. Call the glUseProgram() function to trigger the shader program.

      -
      -glViewport(0, 0, w, h);
      -glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      +

      If you want to get the API of OpenGL ES, you can get the API for rendering OpenGL ES with the evas_gl_api_get(Evas_GL *evas_gl_)function. This function returns a structure that contains all the OpenGL ES functions you can use to render in Evas. These functions consist of all the standard OpenGL ES 2.0 functions and any extra ones Evas has decided to provide in addition. If you have your code ported to OpenGL ES 2.0, it is easy to render to Evas.

      -glUseProgram(ad->program); -
      -
    2. -
    3. -

      Bind the position and color identifiers to the buffers defined above:

      -
      -glEnableVertexAttribArray(ad->positionLoc);
      -glBindBuffer(GL_ARRAY_BUFFER, ad->vertexID);
      -glVertexAttribPointer(ad->positionLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
      +

      If you already use a global macro, such as EVAS_GL_GLOBAL_GLES2_XXX, you need not get the APIs.

      -glEnableVertexAttribArray(ad->colorLoc); -glBindBuffer(GL_ARRAY_BUFFER, ad->colorID); -glVertexAttribPointer(ad->colorLoc, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); -
      -
    4. -
    5. -

      Initialize and calculate the transformation matrix of the model-view matrix by calling the customRotate() function. This makes the cube view rotate a little for a better perspective. Once the model-view matrix is ready to display, multiply the projection matrix with the model-view matrix.

      -customLoadIdentity(model);
      -customRotate(ad->model, 45.0f, 45.0f, 0.0f);
      -customMutlMatrix(ad->mvp, ad->view, ad->model);
      -
      -
    6. -
    7. -

      Load the model-view-projection matrix into the shader and call the glDrawArrays() function to draw the model:

      -
      -glUniformMatrix4fv(ad->mvpLoc, 1, GL_FALSE, mvp);
      -glDrawArrays(GL_TRIANGLES, 0, 36);
      -glFlush();
      -
      -
    8. -
    +Evas_GL_API *glapi; +glapi = evas_gl_api_get(ad->evasgl); -

    Figure: Static cube

    -

    Static cube

    -

    Animating the Cube

    +

    Callbacks

    -

    To animate the cube:

    -
      -
    1. -

      Use the Ecore_Animator to create an animation.

      - -

      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.

      +

      Now that we have configured the EvasGL environment, we declare a UI component in which all the OpenGL ES transformation takes place. In the example below, we selected the image component because it provides callbacks that allow us to play with the mouse events and coordinates, and we set up an image object that inherits the size of the parent window.

      -static Eina_Bool
      -animate_cb(void *data)
      -{
      -   elm_glview_changed_set(data);
      -
      -   return EINA_TRUE;
      -}
      -
      -static void
      -create_gl_canvas(appdata_s *ad)
      -{
      -   ad->ani = ecore_animator_add(animate_cb, ad->glview);
      -}
      +ad->img = evas_object_image_filled_add(evas_object_evas_get(ad->win));
      -static void -app_pause(void *data) -{ -   appdata_s *ad = data; -   ecore_animator_freeze(ad->ani); -} +

      We define the "OpenGL ES main loop" function that is called every time the program attempts to have pixels from the image. We put all the OpenGL ES statements in charge of rendering the scene in this callback.

      -static void -app_resume(void *data) -{ -   appdata_s *ad = data; -   ecore_animator_thaw(ad->ani); -} - -
    2. -
    3. -

      Define the global variables which are used as parameters of the rendering process. Add parameters to the application data object that are used to control the scaling and the rotation of the cube. Make the cube rotate on 1 axis (Z), and allow the user to interact with the mouse to make the cube rotate on the other axes (X and Y). To figure out whether the user is holding the mouse down, add a Boolean variable to have this information. Operations, such as shader initialization or program compilation, are not required at each tick of the animation loop. For better performance, isolate such tasks from the repetitive rendering loop. For such purpose, add a Boolean variable which tells whether the initialization is already done.

      -
      -typedef struct 
      -appdata 
      -{
      -   float xangle;
      -   float yangle;
      -   float zangle;
      -   Eina_Bool mouse_down: 1;
      -   Eina_Bool initialized: 1;
      -}  appdata_s;
      -
      -
    4. -
    5. Modify the rendering loop for animation.

      -
        -
      • -

        Lighten the recurrent rendering process by adding an initialization step:

        -if (ad->initialized) 
        -{
        -   initShaders(ad);
        -   ad->initialized = EINA_TRUE;
        -}
        -
        -
      • -
      • -

        Before drawing the vertices, the rotation angle for the model-view matrix must be incremented for every tick. This makes the cube rotate automatically.

        -
        -customLoadIdentity(ad->model);
        -customRotate(ad->model, ad->xangle, ad->yangle, ad->zangle++);
        -customMutlMatrix(ad->mvp, ad->view, ad->model);
        -
        -
      • -
      -
    6. -
    7. -

      Use the mouse to drag the cube around. To do so, add callbacks for mouse events. The first callback defines whether the user is holding the mouse down while moving the cursor around.

      -
      -static void
      -mouse_down_cb(void *data, Evas *e , Evas_Object *obj , void *event_info)
      -{
      -   appdata_s *ad = data;
      -   ad->mouse_down = EINA_TRUE;
      -}
      +evas_object_image_pixels_get_callback_set(ad->img, img_pixels_get_cb, ad);
      -static void -mouse_up_cb(void *data, Evas *e , Evas_Object *obj , void *event_info) -{ -   appdata_s *ad = data; -   ad->mouse_down = EINA_FALSE; -} - +

      To define a function that takes care of the drawing using EvasGL (called the OpenGL ES main loop), use:

      -

      When the mouse is down, calculate the new rotation angle with the mouse movement along the X and Y axis:

       static void
      -mouse_move_cb(void *data, Evas *e , Evas_Object *obj , void *event_info)
      +img_pixels_get_cb(void *data, Evas_Object *obj)
       {
      -   Evas_Event_Mouse_Move *ev;
      -   ev = (Evas_Event_Mouse_Move *)event_info;
          appdata_s *ad = data;
      -   float dx = 0, dy = 0;
       
      -   if (ad->mouse_down) 
      -   {
      -      dx = ev->cur.canvas.x - ev->prev.canvas.x;
      -      dy = ev->cur.canvas.y - ev->prev.canvas.y;
      -      ad->xangle += dy;
      -      ad->yangle += dx;
      -   }
      -}
      -
      -
    8. -
    9. -

      Define the mouse event callbacks when creating the image canvas:

      -
      -evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_MOUSE_DOWN, mouse_down_cb, ad);
      -evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_MOUSE_UP, mouse_up_cb, ad);
      -evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_MOUSE_MOVE, mouse_move_cb, ad);
      -
      -
    10. -
    +   // Rendering process +   evas_gl_make_current(ad->evasgl, ad->sfc, ad->ctx); +   // Because the surface size can be changed, set the viewport in this callback +   glViewport(0, 0, ad->sfc_w, ad->sfc_h); +   // Paint it blue +   glClearColor(0.2, 0.2, 0.6, 1.0); +   glClear(GL_COLOR_BUFFER_BIT); +   // The usual OpenGL ES draw commands come here +   // draw_scene(); +} -

    Implementing UI Component Interaction

    +

    At every tick, we must set the given context as a current context for the given surface using evas_gl_make_current(Evas_GL *evas_gl, Evas_GL_Surface *surf, Evas_GL_Context *ctx).

    -

    To control some aspects of the rendering, implement UI component interaction (in this use case, sliders):

    -
      -
    1. -

      Use sliders to control the shape of the cube. Declare 3 sliders to play with the scaling coordinates of the cube.

      -
      -typedef struct 
      -appdata 
      -{
      -   Evas_Object *slx;
      -   Evas_Object *sly;
      -   Evas_Object *slz;
      -}
      -
      -
    2. -
    3. -

      Build and show the sliders when rendering the UI. The sliders accept values in a range from 0.0 to 1.5. They control the scaling of each axis of the cube.

      -
      -// Slider for X axis scale
      -ad->slx = elm_slider_add(ad->inner_box);
      -evas_object_size_hint_align_set(ad->slx, EVAS_HINT_FILL, 0);
      -elm_slider_horizontal_set(ad->slx, EINA_TRUE);
      -elm_slider_unit_format_set(ad->slx, "%1.2f units");
      -elm_slider_indicator_format_set(ad->slx, "%1.2f units");
      -elm_slider_indicator_show_set(ad->slx, EINA_TRUE);
      -elm_slider_min_max_set(ad->slx, 0, 1.5);
      -elm_slider_value_set(ad->slx, 0.75);
      -evas_object_color_set(ad->slx, 0.0, 0.0, 120, 255);
      -elm_box_pack_end(ad->inner_box, ad->slx);
      -evas_object_show(ad->slx);
      -
      -// Slider for Y axis scale
      -ad->sly = elm_slider_add(ad->inner_box);
      -evas_object_size_hint_align_set(ad->sly, EVAS_HINT_FILL, 0);
      -elm_slider_horizontal_set(ad->sly, EINA_TRUE);
      -elm_slider_unit_format_set(ad->sly, "%1.2f units");
      -elm_slider_indicator_format_set(ad->sly, "%1.2f units");
      -elm_slider_indicator_show_set(ad->sly, EINA_TRUE);
      -elm_slider_min_max_set(ad->sly, 0, 1.5);
      -elm_slider_value_set(ad->sly, 0.75);
      -evas_object_color_set(ad->sly, 0.0, 0.0, 120, 255);
      -elm_box_pack_end(ad->inner_box, ad->sly);
      -evas_object_show(ad->sly);
      -
      -// Slider for Z axis scale
      -ad->slz = elm_slider_add(ad->inner_box);
      -evas_object_size_hint_align_set(ad->slz, EVAS_HINT_FILL, 0);
      -elm_slider_horizontal_set(ad->slz, EINA_TRUE);
      -elm_slider_unit_format_set(ad->slz, "%1.2f units");
      -elm_slider_indicator_format_set(ad->slz, "%1.2f units");
      -elm_slider_indicator_show_set(ad->slz, EINA_TRUE);
      -elm_slider_min_max_set(ad->slz, 0, 1.5);
      -elm_slider_value_set(ad->slz, 0.75);
      -evas_object_color_set(ad->slz, 0.0, 0.0, 120, 255);
      -elm_box_pack_end(ad->inner_box, ad->slz);
      -evas_object_show(ad->slz);
      -
      -
    4. -
    5. -

      Use the actual sliders's values and pass them to the scaling function in the rendering loop:

      -
      double scalex = elm_slider_value_get(ad->slx);
      -double scaley = elm_slider_value_get(ad->sly);
      -double scalez = elm_slider_value_get(ad->slz);
      -
      -customLoadIdentity(ad->model);
      -customRotate(ad->model, ad->xangle, ad->yangle, ad->zangle++);
      -customScale(ad->model, scalex, scaley, scalez);
      -customMutlMatrix(ad->mvp, ad->view, ad->model);
      -
      -
    6. -
    +

    You can use the Ecore_Animator to define the OpenGL ES main loop. To do so, create a callback that is called on every animation tick. This animation callback is used only to mark the image as "dirty", meaning that it needs an update next time Evas renders. It calls the pixel get callback that redraws the scene.

    -

    Implementing Effects

    +

    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.

    -

    To implement effects:

    -
      -
    1. -

      Create a button that resets the scene by putting the background color to black and makes the cube bounce back to its original scale. Add the button to the application data object.

      -
      -typedef struct 
      -appdata 
      -{
      -   Evas_Object *button;
      -}
      -
      -
    2. -
    3. -

      Add the button to the UI:

      -
      -elm_object_text_set(ad->button, "Reset");
      -elm_box_pack_start(ad->reset_vbox, ad->button);
      -evas_object_smart_callback_add(ad->button, "clicked", btn_reset_cb, ad);
      -elm_box_pack_end(ad->inner_box, ad->button);
      -evas_object_show(ad->button);
      -
      -
    4. -
    5. -

      Declare a callback that resets the variables that have influence on the drawing of the cube. In addition, animate the sliders when they get back to their original position using the Ecore_Animator.

      -typedef struct 
      -appdata 
      -{
      -   float slx_value;
      -   float sly_value;
      -   float slz_value;
      -} appdata_s;
      -
       static Eina_Bool
      -animate_reset_cb(void *data, double pos)
      +animate_cb(void *data)
       {
      -   appdata_s *ad = data;
      -   double frame = pos;
      -   float x, y, z;
      -
      -   frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7);
      -   x = ad->slx_value*(1-frame) + 0.75*frame;
      -   y = ad->sly_value*(1-frame) + 0.75*frame;
      -   z = ad->slz_value*(1-frame) + 0.75*frame;
      -
      -   elm_slider_value_set(ad->slx, x);
      -   elm_slider_value_set(ad->sly, y);
      -   elm_slider_value_set(ad->slz, z);
      +   Evas_Object *img = data;
      +   evas_object_image_pixels_dirty_set(img, EINA_TRUE);
       
      -   return EINA_TRUE;
      +   return ECORE_CALLBACK_RENEW;
       }
       
      -static void
      -btn_reset_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
      -{
      -   appdata_s *ad = data;
      -   ad->slx_value = elm_slider_value_get(ad->slx);
      -   ad->sly_value = elm_slider_value_get(ad->sly);
      -   ad->slz_value = elm_slider_value_get(ad->slz);
      -   ecore_animator_timeline_add(1, animate_reset_cb, ad);
      -}
      -
      -
    6. -
    +ecore_animator_add(animate_cb, ad->img); -

    Viewing the Entire Cube Source

    +

    You can define several other callbacks that have an impact on the drawing depending on the mouse, resize, and deletion events.

    -

    The following code snippet contains the full code of the cube example. The details are explained in the other use cases.

    -// Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
    +evas_object_event_callback_add(ad->img, EVAS_CALLBACK_DEL, img_del_cb, ad);
    +evas_object_event_callback_add(ad->img, EVAS_CALLBACK_MOUSE_DOWN, mouse_down_cb, ad);
    +evas_object_event_callback_add(ad->img, EVAS_CALLBACK_MOUSE_UP, mouse_up_cb, ad);
    +evas_object_event_callback_add(ad->img, EVAS_CALLBACK_MOUSE_MOVE, mouse_move_cb, ad);
    +evas_object_event_callback_add(ad->win, EVAS_CALLBACK_RESIZE, win_resize_cb, ad);
    -#include <app.h> -#include <Elementary.h> -#include <Elementary_GL_Helpers.h> -#include <efl_extension.h> -#include <dlog.h> - -#if !defined(PACKAGE) -#define PACKAGE "org.tizen.glviewtutorial" -#endif - -ELEMENTARY_GLVIEW_GLOBAL_DEFINE(); - -typedef struct -appdata -{ -   // Elm_UI components -   Evas_Object *win; -   Evas_Object *conform; -   Evas_Object *glview; -   Evas_Object *main_box; -   Evas_Object *inner_box; -   Evas_Object *slx; -   Evas_Object *sly; -   Evas_Object *slz; -   Evas_Object *button; -   Ecore_Animator *ani; - -   unsigned int program; -   unsigned int vtx_shader; -   unsigned int fgmt_shader; -   unsigned int vertexID; -   unsigned int colorID; -   unsigned int mvpLoc; -   unsigned int positionLoc; -   unsigned int colorLoc; -   float model[16], mvp[16]; -   float view[16]; -   float xangle; -   float yangle; -   float zangle; -   Eina_Bool mouse_down: 1; -   Eina_Bool initialized: 1; - -   float slx_value; -   float sly_value; -   float slz_value; -} appdata_s; - - -static const float -vertices[] = -{ -   // Front -   -0.5f, 0.5f, 0.5f, -   -0.5f, -0.5f, 0.5f, -   0.5f, 0.5f, 0.5f, -   0.5f, 0.5f, 0.5f, -   -0.5f, -0.5f, 0.5f, -   0.5f, -0.5f, 0.5f, -   // Right -   0.5f, 0.5f, 0.5f, -   0.5f, -0.5f, 0.5f, -   0.5f, 0.5f, -0.5f, -   0.5f, 0.5f, -0.5f, -   0.5f, -0.5f, 0.5f, -   0.5f, -0.5f, -0.5f, -   // Back -   0.5f, 0.5f, -0.5f, -   0.5f, -0.5f, -0.5f, -   -0.5f, 0.5f, -0.5f, -   -0.5f, 0.5f, -0.5f, -   0.5f, -0.5f, -0.5f, -   -0.5f, -0.5f, -0.5f, -   // Left -   -0.5f, 0.5f, -0.5f, -   -0.5f, -0.5f, -0.5f, -   -0.5f, 0.5f, 0.5f, -   -0.5f, 0.5f, 0.5f, -   -0.5f, -0.5f, -0.5f, -   -0.5f, -0.5f, 0.5f, -   // Top -   -0.5f, 0.5f, -0.5f, -   -0.5f, 0.5f, 0.5f, -   0.5f, 0.5f, -0.5f, -   0.5f, 0.5f, -0.5f, -   -0.5f, 0.5f, 0.5f, -   0.5f, 0.5f, 0.5f, -   // Bottom -   -0.5f, -0.5f, 0.5f, -   -0.5f, -0.5f, -0.5f, -   0.5f, -0.5f, 0.5f, -   0.5f, -0.5f, 0.5f, -   -0.5f, -0.5f, -0.5f, -   0.5f, -0.5f, -0.5f -}; - -static const float -colors[] = -{ -   // Front -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   // Right -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   // Back -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   // Left -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   0.0625f, 0.57421875f, 0.92578125f, 1.0f, -   // Top -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   0.29296875f, 0.66796875f, 0.92578125f, 1.0f, -   // Bottom -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f, -   0.52734375f, 0.76171875f, 0.92578125f, 1.0f -}; - -// Vertex shader source -static const char -vertex_shader[] = -   "precision mediump float;" -   "uniform mat4 u_mvpMat;" -   "attribute vec4 a_position;" -   "attribute vec4 a_color;" -   "varying vec4 v_color;" -   "void main()" -   "{" -   "   gl_Position = u_mvpMat * a_position;" -   "   v_color = a_color;" -   "}"; - -// Fragment shader source -static const char -fragment_shader[] = -   "varying lowp vec4 v_color;" -   "void main()" -   "{" -   "   gl_FragColor = v_color;" -   "}"; - -static void -customLoadIdentity(float matrix[16]) -{ -   matrix[0] = 1.0f; -   matrix[1] = 0.0f; -   matrix[2] = 0.0f; -   matrix[3] = 0.0f; - -   matrix[4] = 0.0f; -   matrix[5] = 1.0f; -   matrix[6] = 0.0f; -   matrix[7] = 0.0f; - -   matrix[8] = 0.0f; -   matrix[9] = 0.0f; -   matrix[10] = 1.0f; -   matrix[11] = 0.0f; - -   matrix[12] = 0.0f; -   matrix[13] = 0.0f; -   matrix[14] = 0.0f; -   matrix[15] = 1.0f; -} - -static void -customMutlMatrix(float matrix[16], const float matrix0[16], const float matrix1[16]) -{ -   int i, row, column; -   float temp[16]; -   for (column = 0; column < 4; column++) -   { -      for (row = 0; row < 4; row++) -      { -         temp[column * 4 + row] = 0.0f; -         for (i = 0; i < 4; i++) -            temp[column * 4 + row] += matrix0[i * 4 + row] * matrix1[column * 4 + i]; -      } -   } -   for (i = 0; i < 16; i++) -      matrix[i] = temp[i]; -} - -static void -customScale(float matrix[16], const float sx, const float sy, const float sz) -{ -   matrix[0] *= sx; -   matrix[1] *= sx; -   matrix[2] *= sx; -   matrix[3] *= sx; - -   matrix[4] *= sy; -   matrix[5] *= sy; -   matrix[6] *= sy; -   matrix[7] *= sy; - -   matrix[8] *= sz; -   matrix[9] *= sz; -   matrix[10] *= sz; -   matrix[11] *= sz; -} - -static void -customRotate(float matrix[16], const float anglex, const float angley, const float anglez) -{ -   const float pi = 3.141592f; -   float temp[16]; -   float rz = 2.0f * pi * anglez / 360.0f; -   float rx = 2.0f * pi * anglex / 360.0f; -   float ry = 2.0f * pi * angley / 360.0f; -   float sy = sinf(ry); -   float cy = cosf(ry); -   float sx = sinf(rx); -   float cx = cosf(rx); -   float sz = sinf(rz); -   float cz = cosf(rz); - -   customLoadIdentity(temp); - -   temp[0] = cy * cz - sx * sy * sz; -   temp[1] = cz * sx * sy + cy * sz; -   temp[2] = -cx * sy; - -   temp[4] = -cx * sz; -   temp[5] = cx * cz; -   temp[6] = sx; - -   temp[8] = cz * sy + cy * sx * sz; -   temp[9] = -cy * cz * sx + sy * sz; -   temp[10] = cx * cy; - -   customMutlMatrix(matrix, matrix, temp); -} - -static int -customFrustum(float result[16], const float left, const float right, const float bottom, const float top, const float near, const float far) -{ -   if ((right - left) == 0.0f || (top - bottom) == 0.0f || (far - near) == 0.0f) return 0; - -   result[0] = 2.0f / (right - left); -   result[1] = 0.0f; -   result[2] = 0.0f; -   result[3] = 0.0f; - -   result[4] = 0.0f; -   result[5] = 2.0f / (top - bottom); -   result[6] = 0.0f; -   result[7] = 0.0f; - -   result[8] = 0.0f; -   result[9] = 0.0f; -   result[10] = -2.0f / (far - near); -   result[11] = 0.0f; - -   result[12] = -(right + left) / (right - left); -   result[13] = -(top + bottom) / (top - bottom); -   result[14] = -(far + near) / (far - near); -   result[15] = 1.0f; - -   return 1; -} +

    Because the window size can be changed, you must set a resize callback for the window. In addition, you must recreate an Evas_GL_Surface in the resize callback and reset the viewport size with the new window size:

    +
     static void
    -initShaders(void* data)
    +win_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
     {
    -   const char *p;
        appdata_s *ad = data;
     
    -   p = vertex_shader;
    -   ad->vtx_shader = glCreateShader(GL_VERTEX_SHADER);
    -   glShaderSource(ad->vtx_shader, 1, &p, NULL);
    -   glCompileShader(ad->vtx_shader);
    -
    -   p = fragment_shader;
    -   ad->fgmt_shader = glCreateShader(GL_FRAGMENT_SHADER);
    -   glShaderSource(ad->fgmt_shader, 1, &p, NULL);
    -   glCompileShader(ad->fgmt_shader);
    -
    -   ad->program = glCreateProgram();
    -
    -   glAttachShader(ad->program, ad->vtx_shader);
    -   glAttachShader(ad->program, ad->fgmt_shader);
    -
    -   glDeleteShader(ad->vtx_shader);
    -   glDeleteShader(ad->fgmt_shader);
    -
    -   glLinkProgram(ad->program);
    -
    -   ad->mvpLoc     = glGetUniformLocation(ad->program, "u_mvpMat");
    -   ad->positionLoc = glGetAttribLocation(ad->program, "a_position");
    -   ad->colorLoc   = glGetAttribLocation(ad->program, "a_color");
    -}
    -
    -static void 
    -init_gl(Evas_Object *obj) 
    -{
    -   int w, h;
    -   appdata_s *ad = evas_object_data_get(obj, "ad");
    -
    -   elm_glview_size_get(obj, &w, &h);
    -
    -   if (!ad->initialized) 
    +   if (ad->sfc)
        {
    -      initShaders(ad);
    -
    -      glGenBuffers(1, &ad->vertexID);
    -      glBindBuffer(GL_ARRAY_BUFFER, ad->vertexID);
    -      glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    -
    -      glGenBuffers(1, &ad->colorID);
    -      glBindBuffer(GL_ARRAY_BUFFER, ad->colorID);
    -      glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
    -
    -      ad->initialized = EINA_TRUE;
    +      evas_object_image_native_surface_set(ad->img, NULL);
    +      evas_gl_surface_destroy(ad->evasgl, ad->sfc);
    +      ad->sfc = NULL;
        }
    -}
    -
    -void 
    -resize_gl(Evas_Object *obj) 
    -{
    -   int w, h;
    -   float aspect;
    -   appdata_s *ad = evas_object_data_get(obj, "ad");
    -
    -   elm_glview_size_get(obj, &w, &h);
    -   customLoadIdentity(ad->view);
    -
    -   if (w > h) 
    -   {
    -      aspect = (float) w / h;
    -      customFrustum(ad->view, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0, -1.0, 1.0);
    -   } 
    -   else 
    -   {
    -      aspect = (float) h / w;
    -      customFrustum(ad->view, -1.0, 1.0, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
    -   }
    -}
    -
    -static void 
    -draw_gl(Evas_Object *obj) 
    -{
    -   int w, h;
    -   appdata_s *ad = evas_object_data_get(obj, "ad");
     
    -   double scalex = elm_slider_value_get(ad->slx);
    -   double scaley = elm_slider_value_get(ad->sly);
    -   double scalez = elm_slider_value_get(ad->slz);
    +   evas_object_geometry_get(obj, NULL, NULL, &ad->sfc_w, &ad->sfc_h);
    +   evas_object_image_size_set(ad->img, ad->sfc_w, ad->sfc_h);
    +   evas_object_resize(ad->img, ad->sfc_w, ad->sfc_h);
    +   evas_object_show(ad->img);
     
    -   elm_glview_size_get(obj, &w, &h);
    -
    -   glClearDepthf(1.0f);
    -   glClearColor(0.0, 0.0, 0.0, 1.0);
    -   glEnable(GL_CULL_FACE);
    -
    -   glViewport(0, 0, w, h);
    -   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    -
    -   glUseProgram(ad->program);
    -
    -   glEnableVertexAttribArray(ad->positionLoc);
    -   glBindBuffer(GL_ARRAY_BUFFER, ad->vertexID);
    -   glVertexAttribPointer(ad->positionLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
    -
    -   glEnableVertexAttribArray(ad->colorLoc);
    -   glBindBuffer(GL_ARRAY_BUFFER, ad->colorID);
    -   glVertexAttribPointer(ad->colorLoc, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
    -
    -   customLoadIdentity(ad->model);
    -   customRotate(ad->model, ad->xangle, ad->yangle, ad->zangle++);
    -   customScale(ad->model, scalex, scaley, scalez);
    -   customMutlMatrix(ad->mvp, ad->view, ad->model);
    -
    -   glUniformMatrix4fv(ad->mvpLoc, 1, GL_FALSE, ad->mvp);
    -   glDrawArrays(GL_TRIANGLES, 0, 36);
    -
    -   glFlush();
    -}
    -
    -static void 
    -del_gl(Evas_Object *obj) 
    -{
    -   appdata_s *ad = evas_object_data_get(obj, "ad");
    -
    -   glDeleteShader(ad->vtx_shader);
    -   glDeleteShader(ad->fgmt_shader);
    -   glDeleteProgram(ad->program);
    -
    -   evas_object_data_del((Evas_Object*) obj, "ad");
    -}
    -
    -static Eina_Bool 
    -animate_cb(void *data) 
    -{
    -   elm_glview_changed_set(data);
    -
    -   return EINA_TRUE;
    -}
    -
    -static void 
    -del_animate_cb(void *data, Evas *evas, Evas_Object *obj, void *event_info) 
    -{
    -   appdata_s *ad = data;
    -   ecore_animator_del(ad->ani);
    -}
    -
    -static void 
    -mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) 
    -{
    -   appdata_s *ad = data;
    -   ad->mouse_down = EINA_TRUE;
    -}
    -
    -static void 
    -mouse_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) 
    -{
    -   Evas_Event_Mouse_Move *ev;
    -   ev = (Evas_Event_Mouse_Move *) event_info;
    -   appdata_s *ad = data;
    -   float dx = 0, dy = 0;
    -
    -   if (ad->mouse_down) 
    +   if (!ad->sfc)
        {
    -      dx = ev->cur.canvas.x - ev->prev.canvas.x;
    -      dy = ev->cur.canvas.y - ev->prev.canvas.y;
    -      ad->xangle += dy;
    -      ad->yangle += dx;
    -   }
    -}
    -
    -static void 
    -mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) 
    -{
    -   appdata_s *ad = data;
    -   ad->mouse_down = EINA_FALSE;
    -}
    +      Evas_Native_Surface ns;
     
    -static Eina_Bool 
    -animate_reset_cb(void *data, double pos) 
    -{
    -   appdata_s *ad = data;
    -   double frame = pos;
    -   float x, y, z;
    -
    -   frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7);
    -   x = ad->slx_value * (1 - frame) + 0.75 * frame;
    -   y = ad->sly_value * (1 - frame) + 0.75 * frame;
    -   z = ad->slz_value * (1 - frame) + 0.75 * frame;
    -
    -   elm_slider_value_set(ad->slx, x);
    -   elm_slider_value_set(ad->sly, y);
    -   elm_slider_value_set(ad->slz, z);
    -
    -   return EINA_TRUE;
    -}
    -
    -static void 
    -btn_reset_cb(void *data, Evas_Object *obj, void *event_info) 
    -{
    -   appdata_s *ad = data;
    -   ad->slx_value = elm_slider_value_get(ad->slx);
    -   ad->sly_value = elm_slider_value_get(ad->sly);
    -   ad->slz_value = elm_slider_value_get(ad->slz);
    -   ecore_animator_timeline_add(1, animate_reset_cb, ad);
    -}
    -
    -static void 
    -win_back_cb(void *data, Evas_Object *obj, void *event_info) 
    -{
    -   appdata_s *ad = data;
    -   // Let the window go to the hidden state
    -   elm_win_lower(ad->win);
    -}
    -
    -static void
    -win_delete_request_cb(void *data, Evas_Object *obj, void *event_info)
    -{
    -   ui_app_exit();
    -}
    -
    -static void 
    -create_base_gui(appdata_s *ad) 
    -{
    -   // Window
    -   elm_config_accel_preference_set("opengl");
    -   ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
    -   elm_win_autodel_set(ad->win, EINA_TRUE);
    -
    -   if (elm_win_wm_rotation_supported_get(ad->win)) 
    -   {
    -      int rots[4] = {0, 90, 180, 270};
    -      elm_win_wm_rotation_available_rotations_set(ad->win, (const int *) (&rots), 4);
    +      ad->sfc = evas_gl_surface_create(ad->evasgl, ad->cfg, ad->sfc_w, ad->sfc_h);
    +      evas_gl_native_surface_get(ad->evasgl, ad->sfc, &ns);
    +      evas_object_image_native_surface_set(ad->img, &ns);
    +      evas_object_image_pixels_dirty_set(ad->img, EINA_TRUE);
        }
    +}
    -   evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL); -   eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad); - -   elm_win_conformant_set(ad->win, EINA_TRUE); -   elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW); -   elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_TRANSPARENT); - -   ad->conform = elm_conformant_add(ad->win); -   evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); -   elm_win_resize_object_add(ad->win, ad->conform); -   evas_object_show(ad->conform); - -   ad->main_box = elm_box_add(ad->conform); -   evas_object_size_hint_weight_set(ad->main_box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); -   evas_object_show(ad->main_box); - -   elm_object_content_set(ad->conform, ad->main_box); - -   // Show the window after the base GUI is set up -   evas_object_show(ad->win); -} - -static void -create_gl_canvas(appdata_s *ad) -{ -   // Create and initialize GLView -   ad->glview = elm_glview_add(ad->main_box); -   ELEMENTARY_GLVIEW_GLOBAL_USE(ad->glview); -   evas_object_size_hint_align_set(ad->glview, EVAS_HINT_FILL, EVAS_HINT_FILL); -   evas_object_size_hint_weight_set(ad->glview, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - -   // Request a surface with alpha and a depth buffer -   elm_glview_mode_set(ad->glview, ELM_GLVIEW_DEPTH); - -   // The resize policy tells GLView what to do with the surface when it -   // resizes. ELM_GLVIEW_RESIZE_POLICY_RECREATE tells it to -   // destroy the current surface and recreate it to the new size -   elm_glview_resize_policy_set(ad->glview, ELM_GLVIEW_RESIZE_POLICY_RECREATE); - -   // The render policy sets how GLView must render GL code. -   // ELM_GLVIEW_RENDER_POLICY_ON_DEMAND has the GL callback -   // called only when the object is visible. -   // ELM_GLVIEW_RENDER_POLICY_ALWAYS causes the callback to be -   // called even if the object were hidden -   elm_glview_render_policy_set(ad->glview, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND); - -   // The initialize callback function gets registered here -   elm_glview_init_func_set(ad->glview, init_gl); - -   // The delete callback function gets registered here -   elm_glview_del_func_set(ad->glview, del_gl); - -   // The resize callback function gets registered here -   elm_glview_resize_func_set(ad->glview, resize_gl); - -   // The render callback function gets registered here -   elm_glview_render_func_set(ad->glview, draw_gl); - -   // Add the GLView to the box and show it -   elm_box_pack_end(ad->main_box, ad->glview); -   evas_object_show(ad->glview); - -   // This adds an animator so that the app regularly -   // triggers updates of the GLView using elm_glview_changed_set() -   // -   // NOTE: If you delete GL, this animator keeps running trying to access -   // GL so this animator needs to be deleted with ecore_animator_del() -   ad->ani = ecore_animator_add(animate_cb, ad->glview); -   evas_object_data_set(ad->glview, "ad", ad); -   evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_DEL, del_animate_cb, ad->glview); -   evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_MOUSE_DOWN, mouse_down_cb, ad); -   evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_MOUSE_UP, mouse_up_cb, ad); -   evas_object_event_callback_add(ad->glview, EVAS_CALLBACK_MOUSE_MOVE, mouse_move_cb, ad); - -   // Set rotation variables -   ad->xangle = 45.0f; -   ad->yangle = 45.0f; -   ad->zangle = 0.0f; -   ad->mouse_down = EINA_FALSE; -   ad->initialized = EINA_FALSE; -} - -static void -create_toolbox(appdata_s *ad) -{ -   ad->inner_box = elm_box_add(ad->main_box); -   evas_object_size_hint_align_set(ad->inner_box, EVAS_HINT_FILL, 0); -   elm_box_horizontal_set(ad->inner_box, EINA_FALSE); -   elm_box_homogeneous_set(ad->inner_box, EINA_FALSE); -   elm_box_pack_end(ad->main_box, ad->inner_box); -   evas_object_show(ad->inner_box); - -   // Slider for X axis scale -   ad->slx = elm_slider_add(ad->inner_box); -   evas_object_size_hint_align_set(ad->slx, EVAS_HINT_FILL, 0); -   elm_slider_horizontal_set(ad->slx, EINA_TRUE); -   elm_slider_unit_format_set(ad->slx, "%1.2f units"); -   elm_slider_indicator_format_set(ad->slx, "%1.2f units"); -   elm_slider_indicator_show_set(ad->slx, EINA_TRUE); -   elm_slider_min_max_set(ad->slx, 0, 1.5); -   elm_slider_value_set(ad->slx, 0.75); -   evas_object_color_set(ad->slx, 0.0, 0.0, 120, 255); -   elm_box_pack_end(ad->inner_box, ad->slx); -   evas_object_show(ad->slx); - -   // Slider for Y axis scale -   ad->sly = elm_slider_add(ad->inner_box); -   evas_object_size_hint_align_set(ad->sly, EVAS_HINT_FILL, 0); -   elm_slider_horizontal_set(ad->sly, EINA_TRUE); -   elm_slider_unit_format_set(ad->sly, "%1.2f units"); -   elm_slider_indicator_format_set(ad->sly, "%1.2f units"); -   elm_slider_indicator_show_set(ad->sly, EINA_TRUE); -   elm_slider_min_max_set(ad->sly, 0, 1.5); -   elm_slider_value_set(ad->sly, 0.75); -   evas_object_color_set(ad->sly, 0.0, 0.0, 120, 255); -   elm_box_pack_end(ad->inner_box, ad->sly); -   evas_object_show(ad->sly); - -   // Slider for Z axis scale -   ad->slz = elm_slider_add(ad->inner_box); -   evas_object_size_hint_align_set(ad->slz, EVAS_HINT_FILL, 0); -   elm_slider_horizontal_set(ad->slz, EINA_TRUE); -   elm_slider_unit_format_set(ad->slz, "%1.2f units"); -   elm_slider_indicator_format_set(ad->slz, "%1.2f units"); -   elm_slider_indicator_show_set(ad->slz, EINA_TRUE); -   elm_slider_min_max_set(ad->slz, 0, 1.5); -   elm_slider_value_set(ad->slz, 0.75); -   evas_object_color_set(ad->slz, 0.0, 0.0, 120, 255); -   elm_box_pack_end(ad->inner_box, ad->slz); -   evas_object_show(ad->slz); - -   // Reset button -   ad->button = elm_button_add(ad->inner_box); -   elm_object_text_set(ad->button, "Reset"); -   evas_object_smart_callback_add(ad->button, "clicked", btn_reset_cb, ad); -   evas_object_size_hint_align_set(ad->button, EVAS_HINT_FILL, 0); -   elm_box_pack_end(ad->inner_box, ad->button); -   evas_object_show(ad->button); -} - -static bool -app_create(void *data) -{ -   // Hook to take necessary actions before main event loop starts -   // Initialize UI resources and application's data -   // If this function returns true, the main loop of application starts -   // If this function returns false, the application is terminated -   appdata_s *ad = data; - -   create_base_gui(ad); -   create_gl_canvas(ad); -   create_toolbox(ad); - -   return true; -} - -static void -app_control(app_control_h app_control, void *data) -{ -   // Handle the launch request -} - -static void -app_pause(void *data) -{ -   appdata_s *ad = data; -   ecore_animator_freeze(ad->ani); -} - -static void -app_resume(void *data) -{ -   appdata_s *ad = data; -   ecore_animator_thaw(ad->ani); -} - -static void -app_terminate(void *data) -{ -   // Release all resources -} +

    Setting a Surface into the Image Object

    -int -main(int argc, char *argv[]) -{ -   appdata_s ad = {0,}; -   int ret = 0; -   ui_app_lifecycle_callback_s event_callback = {0,}; - -   event_callback.create = app_create; -   event_callback.terminate = app_terminate; -   event_callback.pause = app_pause; -   event_callback.resume = app_resume; -   event_callback.app_control = app_control; - -   ret = ui_app_main(argc, argv, &event_callback, &ad); -   if (ret != APP_ERROR_NONE) -   { -      dlog_print(DLOG_ERROR, PACKAGE, "The application failed to start, and returned %d", ret); -   } +

    We can also fill in the native Surface information from the given EvasGL surface. For example, to adapt the surface to the target image when the size of the canvas changes, use the following code.

    -   return ret; -} - +
    +Evas_Native_Surface ns;
    +evas_gl_native_surface_get(ad->evasgl, ad->sfc, &ns);
    +evas_object_image_native_surface_set(ad->img, &ns);

    Using OpenGL ES Extensions

    -- 2.7.4