Wiki pages gl_2d_tutorial created: 8 tuto pages + 4 images + code c

Signed-off-by: Clément Bénier <clement.benier@openwide.fr>
Signed-off-by: Pierre Le Magourou <pierre.lemagourou@openwide.fr>
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
Clément Bénier 2015-07-07 09:59:43 +02:00 committed by Cedric BAIL
parent 1ec4491c81
commit 5e0f62e4cd
14 changed files with 1616 additions and 1 deletions

View File

@ -0,0 +1,663 @@
#include <Elementary.h>
#include <Evas_GL.h>
typedef struct _GLData GLData;
// GL related data here..
struct _GLData
{
Evas_GL_API *glapi;
GLuint program;
GLuint vtx_shader;
GLuint fgmt_shader;
GLuint vbo;
GLuint vertexID;
GLuint colorID;
GLuint mvpLoc;
GLuint positionLoc;
GLuint colorLoc;
GLfloat model[16], mvp[16];
GLfloat view[16];
GLfloat xangle;
GLfloat yangle;
GLfloat zangle;
Eina_Bool mouse_down : 1;
Eina_Bool initialized : 1;
Evas_Object *slx;
Evas_Object *sly;
Evas_Object *slz;
float slx_value;
float sly_value;
float slz_value;
};
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 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.82578125f, 1.0f,
0.29296875f, 0.66796875f, 0.82578125f, 1.0f,
0.29296875f, 0.66796875f, 0.82578125f, 1.0f,
0.29296875f, 0.66796875f, 0.82578125f, 1.0f,
0.29296875f, 0.66796875f, 0.82578125f, 1.0f,
0.29296875f, 0.66796875f, 0.82578125f, 1.0f,
// Back
0.52734375f, 0.76171875f, 0.72578125f, 1.0f,
0.52734375f, 0.76171875f, 0.72578125f, 1.0f,
0.52734375f, 0.76171875f, 0.72578125f, 1.0f,
0.52734375f, 0.76171875f, 0.72578125f, 1.0f,
0.52734375f, 0.76171875f, 0.72578125f, 1.0f,
0.52734375f, 0.76171875f, 0.72578125f, 1.0f,
// Left
0.0625f, 0.57421875f, 0.62578125f, 1.0f,
0.0625f, 0.57421875f, 0.62578125f, 1.0f,
0.0625f, 0.57421875f, 0.62578125f, 1.0f,
0.0625f, 0.57421875f, 0.62578125f, 1.0f,
0.0625f, 0.57421875f, 0.62578125f, 1.0f,
0.0625f, 0.57421875f, 0.62578125f, 1.0f,
// Top
0.29296875f, 0.66796875f, 0.52578125f, 1.0f,
0.29296875f, 0.66796875f, 0.52578125f, 1.0f,
0.29296875f, 0.66796875f, 0.52578125f, 1.0f,
0.29296875f, 0.66796875f, 0.52578125f, 1.0f,
0.29296875f, 0.66796875f, 0.52578125f, 1.0f,
0.29296875f, 0.66796875f, 0.52578125f, 1.0f,
// Bottom
0.52734375f, 0.76171875f, 0.42578125f, 1.0f,
0.52734375f, 0.76171875f, 0.42578125f, 1.0f,
0.52734375f, 0.76171875f, 0.42578125f, 1.0f,
0.52734375f, 0.76171875f, 0.42578125f, 1.0f,
0.52734375f, 0.76171875f, 0.42578125f, 1.0f,
0.52734375f, 0.76171875f, 0.42578125f, 1.0f
};
static void
customLoadIdentity(float matrix[16])
{
for (int i = 0; i < 16; i++)
matrix[i] = unit_matrix[i];
}
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;
}
static int
init_shaders(GLData *gld)
{
Evas_GL_API *gl = gld->glapi;
GLbyte vertex_shader[] =
"attribute vec4 a_position;\n"
"attribute vec4 a_color;\n"
"uniform mat4 u_mvp_mat;\n"
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_Position = u_mvp_mat*a_position;\n"
" v_color = a_color;\n"
"}";
GLbyte fragment_shader[] =
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_FragColor = v_color;\n"
"}";
GLint compiled;
const char *p = vertex_shader;
//vertex shader
gld->vtx_shader = gl->glCreateShader(GL_VERTEX_SHADER);
gl->glShaderSource(gld->vtx_shader, 1, &p, NULL);
gl->glCompileShader(gld->vtx_shader);
gl->glGetShaderiv(gld->vtx_shader, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
GLint info_len = 0;
gl->glGetShaderiv(gld->vtx_shader, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1)
{
char* info_log = malloc(sizeof(char) * info_len);
gl->glGetShaderInfoLog(gld->vtx_shader, info_len, NULL, info_log);
printf("Error compiling shader:\n%s\n======\n%s\n======\n", info_log, p);
free(info_log);
}
gl->glDeleteShader(gld->vtx_shader);
}
//fragment shader
p = fragment_shader;
gld->fgmt_shader = gl->glCreateShader(GL_FRAGMENT_SHADER);
gl->glShaderSource(gld->fgmt_shader, 1, &p, NULL);
gl->glCompileShader(gld->fgmt_shader);
gl->glGetShaderiv(gld->fgmt_shader, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
GLint info_len = 0;
gl->glGetShaderiv(gld->fgmt_shader, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1)
{
char* info_log = malloc(sizeof(char) * info_len);
gl->glGetShaderInfoLog(gld->fgmt_shader, info_len, NULL, info_log);
printf("Error compiling shader:\n%s\n======\n%s\n======\n", info_log, p);
free(info_log);
}
gl->glDeleteShader(gld->fgmt_shader);
}
gld->program = gl->glCreateProgram();
GLint linked;
// Load the vertex/fragment shaders
gl->glAttachShader(gld->program, gld->vtx_shader);
gl->glAttachShader(gld->program, gld->fgmt_shader);
gl->glDeleteShader(gld->vtx_shader);
gl->glDeleteShader(gld->fgmt_shader);
gl->glBindAttribLocation(gld->program, 0, "a_position");
gl->glLinkProgram(gld->program);
gl->glGetProgramiv(gld->program, GL_LINK_STATUS, &linked);
if (!linked)
{
GLint info_len = 0;
gl->glGetProgramiv(gld->program, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1)
{
char* info_log = malloc(sizeof(char) * info_len);
gl->glGetProgramInfoLog(gld->program, info_len, NULL, info_log);
printf("Error linking program:\n%s\n", info_log);
free(info_log);
}
gl->glDeleteProgram(gld->program);
return 0;
}
gld->mvpLoc = gl->glGetUniformLocation(gld->program, "u_mvp_mat");
gld->positionLoc = gl->glGetAttribLocation(gld->program, "a_position");
gld->colorLoc = gl->glGetAttribLocation(gld->program, "a_color");
return 1;
}
// Callbacks
// intialize callback that gets called once for intialization
static void
_init_gl(Evas_Object *obj)
{
int w, h;
GLData *gld = evas_object_data_get(obj, "gld");
Evas_GL_API *gl = gld->glapi;
elm_glview_size_get(obj, &w, &h);
if (!gld->initialized)
{
if (!init_shaders(gld))
{
printf("Error Initializing Shaders\n");
return;
}
gl->glGenBuffers(1, &gld->vertexID);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->vertexID);
gl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
gl->glGenBuffers(1, &gld->colorID);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->colorID);
gl->glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
gld->initialized = EINA_TRUE;
}
}
// draw callback is where all the main GL rendering happens
static void
_draw_gl(Evas_Object *obj)
{
Evas_GL_API *gl = elm_glview_gl_api_get(obj);
GLData *gld = evas_object_data_get(obj, "gld");
if(!gld) return;
int w, h;
int r, g, b, a;
//scale
double scalex = elm_slider_value_get(gld->slx);
double scaley = elm_slider_value_get(gld->sly);
double scalez = elm_slider_value_get(gld->slz);
r = 255; g = 255; b = 0; a = 0;
elm_glview_size_get(obj, &w, &h);
gl->glClearDepthf(1.0f);
gl->glClearColor(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
gl->glEnable(GL_CULL_FACE);
gl->glViewport(0, 0, w, h);
gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl->glUseProgram(gld->program);
gl->glEnableVertexAttribArray(gld->positionLoc);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->vertexID);
gl->glVertexAttribPointer(gld->positionLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
gl->glEnableVertexAttribArray(gld->colorLoc);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->colorID);
gl->glVertexAttribPointer(gld->colorLoc, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
customLoadIdentity(gld->model);
customRotate(gld->model, gld->xangle, gld->yangle, gld->zangle++);
//scale
customScale(gld->model, scalex, scaley, scalez);
customMutlMatrix(gld->mvp, gld->view, gld->model);
gl->glUniformMatrix4fv(gld->mvpLoc, 1, GL_FALSE, gld->mvp);
gl->glDrawArrays(GL_TRIANGLES, 0, 36);
gl->glFlush();
}
// resize callback gets called every time object is resized
static void
_resize_gl(Evas_Object *obj)
{
int w, h;
GLData *gld = evas_object_data_get(obj, "gld");
Evas_GL_API *gl = gld->glapi;
float aspect;
elm_glview_size_get(obj, &w, &h);
customLoadIdentity(gld->view);
if (w > h)
{
aspect = (float) w / h;
customFrustum(gld->view, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0, -1.0, 1.0);
}
else
{
aspect = (float) h / w;
customFrustum(gld->view, -1.0, 1.0, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
}
}
// delete callback gets called when glview is deleted
static void
_del_gl(Evas_Object *obj)
{
GLData *gld = evas_object_data_get(obj, "gld");
if (!gld)
{
printf("Unable to get GLData. \n");
return;
}
Evas_GL_API *gl = gld->glapi;
gl->glDeleteShader(gld->vtx_shader);
gl->glDeleteShader(gld->fgmt_shader);
gl->glDeleteProgram(gld->program);
evas_object_data_del((Evas_Object*) obj, "..gld");
}
// just need to notify that glview has changed so it can render
static Eina_Bool
_anim(void *data)
{
elm_glview_changed_set(data);
return EINA_TRUE;
}
static void
_mouse_down_cb(void *data, Evas *e , Evas_Object *obj , void *event_info)
{
GLData *gld = data;
gld->mouse_down = EINA_TRUE;
}
static void
_mouse_up_cb(void *data, Evas *e , Evas_Object *obj , void *event_info)
{
GLData *gld = data;
gld->mouse_down = EINA_FALSE;
}
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;
GLData *gld = data;
float dx = 0, dy = 0;
if(gld->mouse_down)
{
dx = ev->cur.canvas.x - ev->prev.canvas.x;
dy = ev->cur.canvas.y - ev->prev.canvas.y;
gld->xangle += dy;
gld->yangle += dx;
}
}
static void
_on_done(void *data, Evas_Object *obj, void *event_info)
{
evas_object_del((Evas_Object*)data);
elm_exit();
}
static void
_del(void *data, Evas *evas, Evas_Object *obj, void *event_info)
{
Ecore_Animator *ani = evas_object_data_get(obj, "ani");
ecore_animator_del(ani);
}
static Eina_Bool
animate_reset_cb(void *data, double pos)
{
GLData *gld = data;
double frame = pos;
float x, y, z;
frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7);
x = gld->slx_value * (1 - frame) + 0.75 * frame;
y = gld->sly_value * (1 - frame) + 0.75 * frame;
z = gld->slz_value * (1 - frame) + 0.75 * frame;
elm_slider_value_set(gld->slx, x);
elm_slider_value_set(gld->sly, y);
elm_slider_value_set(gld->slz, z);
return EINA_TRUE;
}
static void btn_reset_cb(void *data, Evas_Object *obj, void *event_info)
{
GLData *gld = data;
gld->slx_value = elm_slider_value_get(gld->slx);
gld->sly_value = elm_slider_value_get(gld->sly);
gld->slz_value = elm_slider_value_get(gld->slz);
ecore_animator_timeline_add(1, animate_reset_cb, gld);
}
EAPI_MAIN int
elm_main(int argc, char **argv)
{
Evas_Object *win, *bx, *inner_box, *bt, *gl, *btn_reset;
Ecore_Animator *ani;
GLData *gld = NULL;
if (!(gld = calloc(1, sizeof(GLData)))) return 1;
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
win = elm_win_util_standard_add("glview simple", "GLView Simple");
elm_win_autodel_set(win, EINA_TRUE);
bx = elm_box_add(win);
evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(bx);
inner_box = elm_box_add(bx);
evas_object_size_hint_weight_set(inner_box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(inner_box);
//-//-//-// THIS IS WHERE GL INIT STUFF HAPPENS (ALA EGL)
//-//
// create a new glview object
gl = elm_glview_add(win);
gld->glapi = elm_glview_gl_api_get(gl);
evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
// mode is simply for supporting alpha, depth buffering, and stencil
// buffering.
elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH);
// resize policy tells glview what to do with the surface when it
// resizes. ELM_GLVIEW_RESIZE_POLICY_RECREATE will tell it to
// destroy the current surface and recreate it to the new size
elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE);
// render policy tells glview how it would like glview to render
// gl code. ELM_GLVIEW_RENDER_POLICY_ON_DEMAND will have the gl
// calls called in the pixel_get callback, which only gets called
// if the object is visible, hence ON_DEMAND. ALWAYS mode renders
// it despite the visibility of the object.
elm_glview_render_policy_set(gl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);
// initialize callback function gets registered here
elm_glview_init_func_set(gl, _init_gl);
// delete callback function gets registered here
elm_glview_del_func_set(gl, _del_gl);
elm_glview_resize_func_set(gl, _resize_gl);
elm_glview_render_func_set(gl, _draw_gl);
//-//
//-//-//-// END GL INIT BLOB
elm_box_pack_end(bx, gl);
evas_object_show(gl);
elm_object_focus_set(gl, EINA_TRUE);
// animating - just a demo. as long as you trigger an update on the image
// object via elm_glview_changed_set() it will be updated.
//
// NOTE: if you delete gl, this animator will keep running trying to access
// gl so you'd better delete this animator with ecore_animator_del().
ani = ecore_animator_add(_anim, gl);
evas_object_data_set(gl, "ani", ani);
evas_object_data_set(gl, "gld", gld);
evas_object_event_callback_add(gl, EVAS_CALLBACK_DEL, _del, gl);
evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, gld);
evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, gld);
evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, gld);
/* Set rotation variables */
gld->xangle = 45.0f;
gld->yangle = 45.0f;
gld->zangle = 0.0f;
gld->mouse_down = EINA_FALSE;
gld->initialized = EINA_FALSE;
// add an 'OK' button to end the program
bt = elm_button_add(win);
elm_object_text_set(bt, "OK");
evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
elm_box_pack_end(bx, bt);
evas_object_show(bt);
evas_object_smart_callback_add(bt, "clicked", _on_done, win);
// Slider for X-axis scale
gld->slx = elm_slider_add(inner_box);
evas_object_size_hint_align_set(gld->slx, EVAS_HINT_FILL, 0);
elm_slider_horizontal_set(gld->slx, EINA_TRUE);
elm_slider_unit_format_set(gld->slx, "%1.2f units");
elm_slider_indicator_format_set(gld->slx, "%1.2f units");
elm_slider_indicator_show_set(gld->slx, EINA_TRUE);
elm_slider_min_max_set(gld->slx, 0, 1.5);
elm_slider_value_set(gld->slx, 0.75);
evas_object_color_set(gld->slx, 0.0, 0.0, 120, 255);
elm_box_pack_end(inner_box, gld->slx);
evas_object_show(gld->slx);
// Slider for Y-axis scale
gld->sly = elm_slider_add(inner_box);
evas_object_size_hint_align_set(gld->sly, EVAS_HINT_FILL, 0);
elm_slider_horizontal_set(gld->sly, EINA_TRUE);
elm_slider_unit_format_set(gld->sly, "%1.2f units");
elm_slider_indicator_format_set(gld->sly, "%1.2f units");
elm_slider_indicator_show_set(gld->sly, EINA_TRUE);
elm_slider_min_max_set(gld->sly, 0, 1.5);
elm_slider_value_set(gld->sly, 0.75);
evas_object_color_set(gld->sly, 0.0, 0.0, 120, 255);
elm_box_pack_end(inner_box, gld->sly);
evas_object_show(gld->sly);
// Slider for Z-axis scale
gld->slz = elm_slider_add(inner_box);
evas_object_size_hint_align_set(gld->slz, EVAS_HINT_FILL, 0);
elm_slider_horizontal_set(gld->slz, EINA_TRUE);
elm_slider_unit_format_set(gld->slz, "%1.2f units");
elm_slider_indicator_format_set(gld->slz, "%1.2f units");
elm_slider_indicator_show_set(gld->slz, EINA_TRUE);
elm_slider_min_max_set(gld->slz, 0, 1.5);
elm_slider_value_set(gld->slz, 0.75);
evas_object_color_set(gld->slz, 0.0, 0.0, 120, 255);
elm_box_pack_end(inner_box, gld->slz);
evas_object_show(gld->slz);
// Reset button
btn_reset = elm_button_add(inner_box);
elm_object_text_set(btn_reset, "Reset");
evas_object_smart_callback_add(btn_reset, "clicked", btn_reset_cb, gld);
evas_object_size_hint_align_set(btn_reset, EVAS_HINT_FILL, 0);
elm_box_pack_end(inner_box, btn_reset);
evas_object_show(btn_reset);
evas_object_resize(inner_box, 100, 100);
evas_object_move(inner_box, 0, 5);
evas_object_resize(bx, 800, 800);
evas_object_resize(win, 800, 800);
evas_object_show(win);
// run the mainloop and process events and callbacks
elm_run();
free(gld);
elm_shutdown();
return 0;
}
ELM_MAIN()

BIN
media/cube.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
media/cube_matrix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
media/gl_cube.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
media/gl_cube_example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -48,6 +48,7 @@ Go check the current available version of EFL on each distro/platform:
* [[tutorial/menu_tutorial|Menu Tutorial]]
* [[tutorial/naviframe_tutorial|Naviframe Tutorial]]
* [[tutorial/popup_tutorial|Popup Tutorial]]
* [[tutorial/gl_2d_tutorial|GL 2D Tutorial]]
----
@ -66,4 +67,4 @@ improving our API references a lot.
* [[https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/index.html|EFL]]
* [[https://build.enlightenment.org/job/nightly_elm_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/index.html|Elementary]]
* [[https://build.enlightenment.org/job/base_pyefl_build/lastSuccessfulBuild/artifact/build/sphinx/html/index.html|Python Bindings]]
* [[https://build.enlightenment.org/job/base_pyefl_build/lastSuccessfulBuild/artifact/build/sphinx/html/index.html|Python Bindings]]

View File

@ -0,0 +1,132 @@
~~Title: Creating the Cube - GL 2D Tutorial~~
//**__previous page__: **//[[/tutorial/gl2d/rendering_cube|Rendering the Cube]].
==== Animating the Cube ====
''Ecore_Animator'' is used to create an animation.
<code c>
// just need to notify that glview has changed so it can render
static Eina_Bool
_anim(void *data)
{
elm_glview_changed_set(data);
return EINA_TRUE;
}
</code>
Next 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. To make the cube rotate on
one axis, take z, and allow the user to interact with the mouse to make the
cube rotate on the two other axes x and y. In order 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 task from the repetitive rendering loop. For such purpose, add a
Boolean variable which tells whether the initialization is already done.
<code c>
struct _GLData
{
GLfloat xangle;
GLfloat yangle;
GLfloat zangle;
Eina_Bool mouse_down : 1;
Eina_Bool initialized : 1;
} GLData;
</code>
Here are the modifications that must be done to the rendering loop for
animation.
First, lighten the recurrent rendering process by adding an initialization
step:
<code c>
if (!gld->initialized)
{
if (!init_shaders(gld))
{
printf("Error Initializing Shaders\n");
return;
}
//generate the buffers for the vertex positions and colors
gl->glGenBuffers(1, &gld->vertexID);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->vertexID);
gl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
gl->glGenBuffers(1, &gld->colorID);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->colorID);
gl->glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
gld->initialized = EINA_TRUE;
}
</code>
Before drawing the vertices, the rotation angle for the model-view matrix must
be incremented for every tick.
<code c>
customLoadIdentity(gld->model);
customRotate(gld->model, gld->xangle, gld->yangle, gld->zangle++);
customMutlMatrix(gld->mvp, gld->view, gld->model);
</code>
This makes the cube rotate automatically. The next thing is to 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:
This makes the cube rotate automatically. The next thing is to 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:
<code c>
static void
_mouse_down_cb(void *data, Evas *e , Evas_Object *obj , void *event_info)
{
GLData *gld = data;
gld->mouse_down = EINA_TRUE;
}
static void
_mouse_up_cb(void *data, Evas *e , Evas_Object *obj , void *event_info)
{
GLData *gld = data;
gld->mouse_down = EINA_FALSE;
}
</code>
When the mouse is down, calculate the new rotation angle with the mouse
movement along the x and y axis:
<code c>
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;
GLData *gld = data;
float dx = 0, dy = 0;
if(gld->mouse_down)
{
dx = ev->cur.canvas.x - ev->prev.canvas.x;
dy = ev->cur.canvas.y - ev->prev.canvas.y;
gld->xangle += dy;
gld->yangle += dx;
}
}
</code>
Define the mouse events callbacks when creating the image canvas:
<code c>
evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, gld);
evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, gld);
evas_object_event_callback_add(gl, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, gld);
</code>
\\
//**__next page__: **//[[/tutorial/gl2d/widget_interaction|Implementing Widget Interaction]]

View File

@ -0,0 +1,87 @@
~~Title: Basic Application - GL 2D Tutorial~~
==== Creating the Basic Application ====
This tutorial demonstrates how to create a multicolored 3D rotating cube using
OpenGL ES 2.0 API provided by GLView library. Several concepts are explained,
such as the cube geometry, the initialization phase of the model, the
adjustment of this very model frame by frame, and the way to design the OpenGL
ES rendering loop.
First create a basic application as explained in the Basic application
tutorial. This provides a basic UI application skeleton which already makes
available the window object that contains the GLView canvas. Here an example
below :
<code c>
#include <Elementary.h>
#include <Evas_GL.h>
#include <stdio.h>
EAPI_MAIN int
elm_main(int argc, char **argv)
{
Evas_Object *win, *box, *gl;
Ecore_Animator *ani;
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
win = elm_win_util_standard_add("glview simple", "GLView Simple");
elm_win_autodel_set(win, EINA_TRUE);
evas_object_resize(win, 320, 480);
evas_object_show(win);
// run the mainloop and process events and callbacks
elm_run();
elm_shutdown();
return 0;
}
ELM_MAIN()
</code>
=== OpenGL ES Canvas ===
To develop a GL application, you have to call
''elm_config_accel_preference_set()'' before creating a window which makes an
application to use GPU.
<code c>
elm_config_accel_preference_set("opengl");
</code>
To call GL functions, you can get the Evas_GL instance from
''elm_glview_gl_api_get'' function, then you can call the OpenGL ES function
with the instance.
<code c>
gl = elm_glview_add(win);
Evas_GL_API *glapi = elm_glview_gl_api_get(gl);
evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
</code>
The next thing to do is to set the GLView mode.
elm_glview_mode_set(Evas_Object *obj, Elm_GLView_Mode mode) supports alpha,
depth, stencil, MSAA, and client_side_rotation.
<code c>
// mode is simply for supporting alpha, depth buffering, and stencil
// buffering.
elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH);
</code>
To set up callbacks:
<code c>
// initialize callback function gets registered here
elm_glview_init_func_set(gl, _init_gl);
// delete callback function gets registered here
elm_glview_del_func_set(gl, _del_gl);
elm_glview_resize_func_set(gl, _resize_gl);
elm_glview_render_func_set(gl, _draw_gl);
ani = ecore_animator_add(_anim, gl);
</code>
\\
| Callback for initialisation | ''_init_gl'' | 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. |
| Callback for resizing | ''_resize_gl'' | The resize callback is called whenever the GLView widget is resized and depends on policy set. A common action to take here is to reset the viewport. \\ ''elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE)'' \\ resize policy tells glview what to do with the surface when it resizes. ELM_GLVIEW_RESIZE_POLICY_RECREATE will tell it to destroy the current surface and recreate it to the new size |
| Callback for drawing | ''_draw_gl'' | The drawing 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(gl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND)'' \\ Another policy is ELM_GLVIEW_POLICY_ALWAYS, which requests render always even when it is not visible. So 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 | ''_del_gl'' | 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. |
| Add an animator | ''_anim_gl'' | The application above is technically working but the scene does not get updated unless the object is marked as such. Games might want to use an animator to have a regular update of the scene. \\ Any other event can be used to refresh the view, for example user input if the view needs to be updated. |
//**__next page__: **//[[/tutorial/gl2d/creating_cube|Creating the Cube]]

View File

@ -0,0 +1,128 @@
~~Title: Creating the Cube - GL 2D Tutorial~~
//**__previous page__: **//[[/tutorial/gl2d/basic_application|Creating the
Basic Application]].
==== Creating the Cube ====
Creating and coloring the cube can be separated into two distinct tasks:
define the vertices and then add the colors to the faces.
{{ :cube.png }}
Declare an array that stores the vertices of the cube in order to make it
look as the drawing above.
<code c>
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
};
</code>
{{ :cube_matrix.png }}
Each triangle is defined with three point coordinates, three vertices for each
triangle, two triangles per face and six faces, so there are 36 vertices is
total.
The next step is to 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:
<code c>
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
};
</code>
//**__next page__: **//[[/tutorial/gl2d/drawing_cube|Drawing the Cube with GLView]]

View File

@ -0,0 +1,403 @@
~~Title: Drawing the Cube - GL 2D Tutorial~~
//**__previous page__: **//[[/tutorial/gl2d/creating_cube|Creating the Cube]]
==== Drawing the Cube with GLView ====
=== Mathematical Functions for Matrices ===
After the model is initialized, create functionality to manipulate the scene.
OpenGL ES 2.0 provided by GLView requires more preliminary work that the
previous version of the library, but gives more power and flexibility,
although our example does not take much benefit.
First, declare additional global variables for specific OpenGL ES 2.0 tasks: a
program object, an identifier for the vertices buffer and
another for the colors. Add also three variables to ensure the
connection with the shader language:
* ''mvpLoc'' is an identifier for model-view-projection matrix.
* ''positionLoc'' is an identifier for the vertex position.
* ''colorLoc'' is an identifier for the vertex color.
Declare all these variables in the ''GLData'' object:
<code c>
struct _GLData
{
GLuint program;
GLuint vtx_shader;
GLuint fgmt_shader;
GLuint vbo;
GLuint vertexID;
GLuint colorID;
GLuint mvpLoc;
GLuint positionLoc;
GLuint colorLoc;
}
</code>
Since OpenGL ES 2.0, some functions for matrix transformations have been
removed. Define three matrix functions to use: projection matrix, model-view
matrix, and a combination of these allows you to perform any transformations
on the initial vertices matrix.
== Matrix Multiplication Function (glMultMatrix) ==
First, define a function that is able to return the inner product of two
matrices. This function reproduces the behavior of ''glMultMatrix()''
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 three arguments, one is for the result and the other 2
matrices are operands:
<code c>
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];
}
</code>
== Matrix Identity Function (glLoadIdentity) ==
Implement a function equivalent to ''glLoadIdentity()'' that replaces the current
matrix with the identity matrix:
<code c>
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];
}
</code>
== Matrix Projection Function (glFrustum) ==
Since ''glFrustum'' has been depreciated, 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 "fustum") to your screen. Many caveats apply (normalized device
coordinates, perspective divide, etc), but that is the idea:
<code c>
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;
}
</code>
== Matrix Scaling Function (glScale) ==
Depreciated ''glScale()'' function represents a non-uniform scaling along the x,
y, and z axes. The three parameters indicate the desired scale factor along
each of the three axes:
<code c>
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
}
</code>
Here is the implementation of the matrix scaling function:
<code c>
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;
}
</code>
== Matrix Rotation Function (glRotate) ==
Define a function to represent a rotation by the vector (x y z). The current
matrix is multiplied by a rotation matrix:
<code c>
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);
}
</code>
=== Create the Shader ===
Define the source for the shader using a ''GLbyte'' array. First comes out 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. Also create two vector attributes which have 4 components for the
vertex position and the color. This varying variable v_color 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, in order 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, then set the color of the
pixel with this interpolated color.
<code c>
GLbyte vertex_shader[] =
"attribute vec4 a_position;\n"
"attribute vec4 a_color;\n"
"uniform mat4 u_mvp_mat;\n"
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_Position = u_mvp_mat*a_position;\n"
" v_color = a_color;\n"
"}";
GLbyte fragment_shader[] =
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_FragColor = v_color;\n"
"}";
</code>
Create the shaders, attach the source code that is just defined and compile
the program object:
<code c>
static int
init_shaders(GLData *gld)
{
Evas_GL_API *gl = gld->glapi;
GLbyte vertex_shader[] =
"attribute vec4 a_position;\n"
"attribute vec4 a_color;\n"
"uniform mat4 u_mvp_mat;\n"
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_Position = u_mvp_mat*a_position;\n"
" v_color = a_color;\n"
"}";
GLbyte fragment_shader[] =
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_FragColor = v_color;\n"
"}";
GLint compiled;
const char *p;
/*vertex_shader*/
p = vertex_shader;
gld->vtx_shader = gl->glCreateShader(GL_VERTEX_SHADER);
gl->glShaderSource(gld->vtx_shader, 1, &p, NULL); //get vertex_shader source
gl->glCompileShader(gld->vtx_shader); //compile
//get compile status
gl->glGetShaderiv(gld->vtx_shader, GL_COMPILE_STATUS, &compiled);
//if NULL: error
if (!compiled)
{
GLint info_len = 0;
gl->glGetShaderiv(gld->vtx_shader, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1)
{
char* info_log = malloc(sizeof(char) * info_len);
gl->glGetShaderInfoLog(gld->vtx_shader, info_len, NULL, info_log);
printf("Error compiling shader:\n%s\n======\n%s\n======\n", info_log, p);
free(info_log);
}
gl->glDeleteShader(gld->vtx_shader);
}
/*fragment_shader*/
p = fragment_shader;
gld->fgmt_shader = gl->glCreateShader(GL_FRAGMENT_SHADER);
gl->glShaderSource(gld->fgmt_shader, 1, &p, NULL);
gl->glCompileShader(gld->fgmt_shader);
//get compile status
gl->glGetShaderiv(gld->fgmt_shader, GL_COMPILE_STATUS, &compiled);
//if NULL: error
if (!compiled)
{
GLint info_len = 0;
gl->glGetShaderiv(gld->fgmt_shader, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1)
{
char* info_log = malloc(sizeof(char) * info_len);
gl->glGetShaderInfoLog(gld->fgmt_shader, info_len, NULL, info_log);
printf("Error compiling shader:\n%s\n======\n%s\n======\n", info_log, p);
free(info_log);
}
gl->glDeleteShader(gld->fgmt_shader);
}
</code>
Once the shaders are ready, instantiate the program object and link the
shaders. If the linking succeeds, you can destroy the shaders afterwards
(using ''glDeleteShader''). Since they are inside the program object, so it is
pointless to keep them in memory.
<code c>
gld->program = gl->glCreateProgram();
GLint linked;
// Load the vertex/fragment shaders
gl->glAttachShader(gld->program, gld->vtx_shader);
gl->glAttachShader(gld->program, gld->fgmt_shader);
gl->glDeleteShader(gld->vtx_shader);
gl->glDeleteShader(gld->fgmt_shader);
gl->glBindAttribLocation(gld->program, 0, "a_position");
gl->glLinkProgram(gld->program);
gl->glGetProgramiv(gld->program, GL_LINK_STATUS, &linked);
if (!linked)
{
GLint info_len = 0;
gl->glGetProgramiv(gld->program, GL_INFO_LOG_LENGTH, &info_len);
if (info_len > 1)
{
char* info_log = malloc(sizeof(char) * info_len);
gl->glGetProgramInfoLog(gld->program, info_len, NULL, info_log);
printf("Error linking program:\n%s\n", info_log);
free(info_log);
}
gl->glDeleteProgram(gld->program);
return 0;
}
</code>
For shader process, create identifiers for the attribute variables used in the
shader program. First create an identifier for the model-view-projection
matrix, another one for the current vertex position, and a last one for the
vertex color.
<code c>
gld->mvpLoc = gl->glGetUniformLocation(gld->program, "u_mvp_mat");
gld->positionLoc = gl->glGetAttribLocation(gld->program, "a_position");
gld->colorLoc = gl->glGetAttribLocation(gld->program, "a_color");
</code>
Finally, generate the buffers for the vertex positions and colors.
<code c>
gl->glGenBuffers(1, &gld->vertexID);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->vertexID);
gl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
gl->glGenBuffers(1, &gld->colorID);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->colorID);
gl->glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
gld->initialized = EINA_TRUE;
</code>
Allocate memory for the matrix and load a unit matrix into it. Then define the
value that is used in order to build the perspective projection matrix. The
''customFrustum()'' function is used for it. Multiply this resulting matrix
with a resizing matrix, so the model is correctly adjusted to the screen.
<code c>
float aspect;
elm_glview_size_get(obj, &w, &h);
customLoadIdentity(gld->view);
if (w > h)
{
aspect = (float) w / h;
customFrustum(gld->view, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0, -1.0, 1.0);
}
else
{
aspect = (float) h / w;
customFrustum(gld->view, -1.0, 1.0, -1.0 * aspect, 1.0 * aspect, -1.0, 1.0);
}
</code>
\\
//**__next page__: **//[[/tutorial/gl2d/rendering_cube|Rendering the Cube]]

View File

@ -0,0 +1,53 @@
~~Title: Implementing Effects - GL 2D Tutorial~~
//**__previous page__: **//[[/tutorial/gl2d/widget_interaction|Implementing Widget Interaction]]
==== Implementing Effects ====
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
GUI:
<code c>
Evas_Object *btn_reset;
btn_reset = elm_button_add(inner_box);
elm_object_text_set(btn_reset, "Reset");
evas_object_smart_callback_add(btn_reset, "clicked", btn_reset_cb, gld);
evas_object_size_hint_align_set(btn_reset, EVAS_HINT_FILL, 0);
elm_box_pack_end(inner_box, btn_reset);
evas_object_show(btn_reset);
</code>
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 ''Ecore_Animator''.
<code c>
static Eina_Bool
animate_reset_cb(void *data, double pos)
{
GLData *gld = data;
double frame = pos;
float x, y, z;
frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_BOUNCE, 1.8, 7);
x = gld->slx_value * (1 - frame) + 0.75 * frame;
y = gld->sly_value * (1 - frame) + 0.75 * frame;
z = gld->slz_value * (1 - frame) + 0.75 * frame;
elm_slider_value_set(gld->slx, x);
elm_slider_value_set(gld->sly, y);
elm_slider_value_set(gld->slz, z);
return EINA_TRUE;
}
static void btn_reset_cb(void *data, Evas_Object *obj, void *event_info)
{
GLData *gld = data;
gld->slx_value = elm_slider_value_get(gld->slx);
gld->sly_value = elm_slider_value_get(gld->sly);
gld->slz_value = elm_slider_value_get(gld->slz);
ecore_animator_timeline_add(1, animate_reset_cb, gld);
}
</code>
\\
//**__The whole code__: **//{{ code_c/tutorial/gl2d/gl_2d.c }}

View File

@ -0,0 +1,55 @@
~~Title: Rendering the Cube - GL 2D Tutorial~~
//**__previous page__: **//[[/tutorial/gl2d/drawing_cube|Drawing the Cube with GLView]]
==== Rendering the Cube ====
The viewport is set 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. Then
call the ''glUseProgram()'' function in order to trigger the shader program.
In ''draw_gl'' callback :
<code c>
gl->glViewport(0, 0, w, h);
gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl->glUseProgram(gld->program);
</code>
Also bind the position and color identifiers to the buffers defined above.
<code c>
gl->glEnableVertexAttribArray(gld->positionLoc);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->vertexID);
gl->glVertexAttribPointer(gld->positionLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
gl->glEnableVertexAttribArray(gld->colorLoc);
gl->glBindBuffer(GL_ARRAY_BUFFER, gld->colorID);
gl->glVertexAttribPointer(gld->colorLoc, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
</code>
After this, 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.
<code c>
customLoadIdentity(gld->model);
customRotate(gld->model, gld->xangle, gld->yangle, gld->zangle);
customMutlMatrix(gld->mvp, gld->view, gld->model);
</code>
Then load the model-view-projection matrix into the shader and call
''glDrawArrays()'' to draw the model.
<code c>
gl->glUniformMatrix4fv(gld->mvpLoc, 1, GL_FALSE, gld->mvp);
gl->glDrawArrays(GL_TRIANGLES, 0, 36);
gl->glFlush();
</code>
You now are the proud owner of a nice cube!
{{ :gl_cube.png?500 }}
\\
//**__next page__: **//[[/tutorial/gl2d/animating_cube|Animating the Cube]]

View File

@ -0,0 +1,74 @@
~~Title: Widget Interaction - GL 2D Tutorial~~
//**__previous page__: **//[[/tutorial/gl2d/animating_cube|Animating the Cube]]
==== Implementing Widget Interaction ====
Consider using widget to control some aspects of the rendering. For example,
use some sliders to control the shape of the cube. Declare 3 sliders to play
with the scaling coordinates of the cube.
struct _GLData
{
Evas_Object *slx;
Evas_Object *sly;
Evas_Object *slz;
}
When rendering the GUI, build and show the sliders. Those accept values in a
range from 0.0 to 1.5 and control the scaling of each axis of the cube.
<code c>
// Slider for X-axis scale
gld->slx = elm_slider_add(inner_box);
evas_object_size_hint_align_set(gld->slx, EVAS_HINT_FILL, 0);
elm_slider_horizontal_set(gld->slx, EINA_TRUE);
elm_slider_unit_format_set(gld->slx, "%1.2f units");
elm_slider_indicator_format_set(gld->slx, "%1.2f units");
elm_slider_indicator_show_set(gld->slx, EINA_TRUE);
elm_slider_min_max_set(gld->slx, 0, 1.5);
elm_slider_value_set(gld->slx, 0.75);
evas_object_color_set(gld->slx, 0.0, 0.0, 120, 255);
elm_box_pack_end(inner_box, gld->slx);
evas_object_show(gld->slx);
// Slider for Y-axis scale
gld->sly = elm_slider_add(inner_box);
evas_object_size_hint_align_set(gld->sly, EVAS_HINT_FILL, 0);
elm_slider_horizontal_set(gld->sly, EINA_TRUE);
elm_slider_unit_format_set(gld->sly, "%1.2f units");
elm_slider_indicator_format_set(gld->sly, "%1.2f units");
elm_slider_indicator_show_set(gld->sly, EINA_TRUE);
elm_slider_min_max_set(gld->sly, 0, 1.5);
elm_slider_value_set(gld->sly, 0.75);
evas_object_color_set(gld->sly, 0.0, 0.0, 120, 255);
elm_box_pack_end(inner_box, gld->sly);
evas_object_show(gld->sly);
// Slider for Z-axis scale
gld->slz = elm_slider_add(inner_box);
evas_object_size_hint_align_set(gld->slz, EVAS_HINT_FILL, 0);
elm_slider_horizontal_set(gld->slz, EINA_TRUE);
elm_slider_unit_format_set(gld->slz, "%1.2f units");
elm_slider_indicator_format_set(gld->slz, "%1.2f units");
elm_slider_indicator_show_set(gld->slz, EINA_TRUE);
elm_slider_min_max_set(gld->slz, 0, 1.5);
elm_slider_value_set(gld->slz, 0.75);
evas_object_color_set(gld->slz, 0.0, 0.0, 120, 255);
elm_box_pack_end(inner_box, gld->slz);
evas_object_show(gld->slz);
</code>
Then use the actual the values of sliders and pass them to the scaling function in
the rendering loop, ''_draw_gl'':
<code c>
double scalex = elm_slider_value_get(gld->slx);
double scaley = elm_slider_value_get(gld->sly);
double scalez = elm_slider_value_get(gld->slz);
customLoadIdentity(gld->model);
customRotate(gld->model, gld->xangle, gld->yangle, gld->zangle++);
customScale(gld->model, scalex, scaley, scalez);
customMutlMatrix(gld->mvp, gld->view, gld->model);
</code>
\\
//**__next page__: **//[[/tutorial/gl2d/effects|Implementing Effects]]

View File

@ -0,0 +1,19 @@
~~Title: GL 2D Tutorial~~
==== GL 2D Tutorial ====
This tutorial demonstrates how you can handle OpenGL ES graphics with the
GLView widget and EvasGL.
=== Table of Contents ===
* [[/tutorial/gl2d/basic_application|Creating the Basic Application]]
* [[/tutorial/gl2d/creating_cube|Creating the Cube]]
* [[/tutorial/gl2d/drawing_cube|Drawing the Cube with GLView]]
* [[/tutorial/gl2d/rendering_cube|Rendering the Cube]]
* [[/tutorial/gl2d/animating_cube|Animating the Cube]]
* [[/tutorial/gl2d/widget_interaction|Implementing Widget Interaction]]
* [[/tutorial/gl2d/effects|Implementing Effects]]
Gl 2D example: {{ :gl_cube_example.png?600 }}
//**__The whole code__: **//{{ code_c/tutorial/gl2d/gl_2d.c }}