diff --git a/src/examples/evas/Makefile.am b/src/examples/evas/Makefile.am index f0e8ae8b7f..72fd97f47f 100644 --- a/src/examples/evas/Makefile.am +++ b/src/examples/evas/Makefile.am @@ -243,6 +243,7 @@ evas-aspect-hints.c \ evas-box.c \ evas-buffer-simple.c \ evas-events.c \ +evas-3d-fog.c \ evas-hints.c \ evas-images.c \ evas-images2.c \ diff --git a/src/examples/evas/Makefile.examples b/src/examples/evas/Makefile.examples index f91d14f48f..be10cd57cd 100644 --- a/src/examples/evas/Makefile.examples +++ b/src/examples/evas/Makefile.examples @@ -9,6 +9,7 @@ EXAMPLES= evas-aspect-hints \ evas-box \ evas-buffer-simple \ evas-events \ + evas-3d-fog.c \ evas-hints \ evas-images \ evas-images2 \ diff --git a/src/examples/evas/evas-3d-fog.c b/src/examples/evas/evas-3d-fog.c new file mode 100644 index 0000000000..300b30a86d --- /dev/null +++ b/src/examples/evas/evas-3d-fog.c @@ -0,0 +1,319 @@ +/** + * Example illustrating usage of fog effect. + * + * @verbatim + * gcc -o evas-3d-fog evas-3d-fog.c `pkg-config --libs --cflags evas ecore ecore-evas eo`-lm + * @endverbatim + */ + +#define EFL_EO_API_SUPPORT +#define EFL_BETA_API_SUPPORT + +#include +#include +#include +#include +#include + +#define WIDTH 1024 +#define HEIGHT 1024 +#define FOG_COLOR 0.5, 0.5, 0.5 +#define FOG_FACTOR 0.2 + +static double pi = 3.14159265359; + +typedef struct _Scene_Data +{ + Eo *scene; + Eo *root_node; + Eo *camera_node; + Eo *light_node; + Eo *mesh_node; + Eo *mesh_node1; + + Eo *camera; + Eo *light; + Eo *mesh; + Eo *mesh1; + Eo *material; +} Scene_Data; + +typedef struct _vec3 +{ + float x; + float y; + float z; +} vec3; + +typedef struct _vec4 +{ + float x; + float y; + float z; + float w; +} vec4; + +Ecore_Evas *ecore_evas = NULL; +Evas *evas = NULL; +Eo *background = NULL; +Eo *image = NULL; + + +static void +_on_delete(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static void +_on_canvas_resize(Ecore_Evas *ee) +{ + int w, h; + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + + evas_object_resize(background, w, h); + eo_do(background, evas_obj_size_set(w, h)); + eo_do(image, evas_obj_size_set(w, h)); +} + +static Eina_Bool +_animate_scene(void *data) +{ + static float angle = 0.0f; + Scene_Data *scene = (Scene_Data *)data; + + angle += 0.5; + + eo_do(scene->mesh_node, + evas_3d_node_orientation_angle_axis_set(angle, 0.0, 1.0, 0.0)); + + if (angle > 360.0) angle -= 360.0f; + + return EINA_TRUE; +} + +static void +_camera_setup(Scene_Data *data) +{ + data->camera = eo_add(EVAS_3D_CAMERA_CLASS, evas); + + eo_do(data->camera, + evas_3d_camera_projection_perspective_set(60.0, 1.0, 2.0, 50.0)); + + data->camera_node = + eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_CAMERA)); + + eo_do(data->camera_node, + evas_3d_node_camera_set(data->camera), + evas_3d_node_position_set(0.0, 0.0, 10.0), + evas_3d_node_look_at_set(EVAS_3D_SPACE_PARENT, 0.0, 0.0, 0.0, + EVAS_3D_SPACE_PARENT, 0.0, 1.0, 0.0)); + + eo_do(data->root_node, evas_3d_node_member_add(data->camera_node)); +} + +static void +_light_setup(Scene_Data *data) +{ + data->light = eo_add(EVAS_3D_LIGHT_CLASS, evas); + eo_do(data->light, + evas_3d_light_ambient_set(0.2, 0.2, 0.2, 1.0), + evas_3d_light_diffuse_set(1.0, 1.0, 1.0, 1.0), + evas_3d_light_specular_set(1.0, 1.0, 1.0, 1.0)); + + data->light_node = + eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_LIGHT)); + eo_do(data->light_node, + evas_3d_node_light_set(data->light), + evas_3d_node_position_set(0.0, 0.0, 10.0), + evas_3d_node_look_at_set(EVAS_3D_SPACE_PARENT, 0.0, 0.0, 0.0, + EVAS_3D_SPACE_PARENT, 0.0, 1.0, 0.0)); + eo_do(data->root_node, evas_3d_node_member_add(data->light_node)); +} + +static void +_set_ball(Eo *mesh, double r, double x, double y, double z, int p, Evas_3D_Material *material) +{ + int vcount, icount, vccount, i, j; + double dtheta, dfi, sinth, costh, fi, theta, sinfi, cosfi; + unsigned short *indices, *index; + + icount = p * p * 6; + vccount = p + 1; + vcount = vccount * vccount; + + dtheta = pi / p; + dfi = 2 * pi / p; + + vec3 *vertices = malloc(sizeof(vec3) * vcount); + vec3 *normals = malloc(sizeof(vec3) * vcount); + + for (j = 0; j < vccount; j++) + { + theta = j * dtheta; + sinth = sin(theta); + costh = cos(theta); + for (i = 0; i < vccount; i++) + { + fi = i * dfi; + sinfi = sin(fi); + cosfi = cos(fi); + vertices[i + j * vccount].x = r * sinth * cosfi + x; + vertices[i + j * vccount].y = r * sinth * sinfi + y; + vertices[i + j * vccount].z = r * costh + z; + + normals[i + j * vccount].x = sinth * cosfi; + normals[i + j * vccount].y = sinth * sinfi; + normals[i + j * vccount].z = costh; + } + } + + indices = malloc(sizeof(short) * icount); + index = &indices[0]; + + for(j = 0; j < p; j++) + for(i = 0; i < p; i++) + { + *index++ = (unsigned short)(i + vccount * j); + *index++ = i + vccount * (j + 1); + *index++ = i + 1 + vccount * (j + 1); + + *index++ = i + vccount * j; + *index++ = i + 1 + vccount * j; + *index++ = i + vccount * (j + 1) + 1; + } + + eo_do(mesh, evas_3d_mesh_vertex_count_set(vcount), + evas_3d_mesh_frame_add(0); + evas_3d_mesh_frame_vertex_data_set(0, EVAS_3D_VERTEX_POSITION, + sizeof(vec3), &vertices[0]); + evas_3d_mesh_frame_vertex_data_set(0, EVAS_3D_VERTEX_NORMAL, + sizeof(vec3), &normals[0]); + evas_3d_mesh_index_data_set(EVAS_3D_INDEX_FORMAT_UNSIGNED_SHORT, + icount , &indices[0]); + evas_3d_mesh_vertex_assembly_set(EVAS_3D_VERTEX_ASSEMBLY_TRIANGLES); + evas_3d_mesh_shade_mode_set(EVAS_3D_SHADE_MODE_PHONG); + evas_3d_mesh_frame_material_set(0, material)); +} + + +static void +_mesh_setup(Scene_Data *data) +{ + data->material = eo_add(EVAS_3D_MATERIAL_CLASS, evas); + + eo_do(data->material, + evas_3d_material_enable_set(EVAS_3D_MATERIAL_AMBIENT, EINA_TRUE), + evas_3d_material_enable_set(EVAS_3D_MATERIAL_DIFFUSE, EINA_TRUE), + evas_3d_material_enable_set(EVAS_3D_MATERIAL_SPECULAR, EINA_TRUE), + + evas_3d_material_color_set(EVAS_3D_MATERIAL_AMBIENT, 0.2, 0.2, 0.2, 1.0), + evas_3d_material_color_set(EVAS_3D_MATERIAL_DIFFUSE, 0.8, 0.8, 0.8, 1.0), + evas_3d_material_color_set(EVAS_3D_MATERIAL_SPECULAR, 1.0, 1.0, 1.0, 1.0), + evas_3d_material_shininess_set(100.0)); + + data->mesh = eo_add(EVAS_3D_MESH_CLASS, evas); + data->mesh1 = eo_add(EVAS_3D_MESH_CLASS, evas); + + + _set_ball(data->mesh, 1, 4, 0, 0, 100, data->material); + _set_ball(data->mesh1, 2, 0, 0, 0, 100, data->material); + + data->mesh_node = + eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_MESH)); + + eo_do(data->root_node, evas_3d_node_member_add(data->mesh_node)); + eo_do(data->mesh_node, evas_3d_node_mesh_add(data->mesh)); + + data->mesh_node1 = + eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_MESH)); + + eo_do(data->root_node, evas_3d_node_member_add(data->mesh_node1)); + eo_do(data->mesh_node1, evas_3d_node_mesh_add(data->mesh1)); + + eo_do(data->mesh, evas_3d_mesh_fog_enable_set(EINA_TRUE), evas_3d_mesh_fog_color_set(FOG_COLOR, FOG_FACTOR)); + eo_do(data->mesh1, evas_3d_mesh_fog_enable_set(EINA_TRUE), evas_3d_mesh_fog_color_set(FOG_COLOR, FOG_FACTOR)); +} + +static void +_scene_setup(Scene_Data *data) +{ + data->scene = eo_add(EVAS_3D_SCENE_CLASS, evas); + + eo_do(data->scene, + evas_3d_scene_size_set(WIDTH, HEIGHT); + evas_3d_scene_background_color_set(FOG_COLOR, 1)); + + data->root_node = + eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_NODE)); + + _camera_setup(data); + _light_setup(data); + _mesh_setup(data); + + eo_do(data->scene, + evas_3d_scene_root_node_set(data->root_node), + evas_3d_scene_camera_node_set(data->camera_node)); +} + +int +main(void) +{ + + //Unless Evas 3D supports Software renderer, we set gl backened forcely. + setenv("ECORE_EVAS_ENGINE", "opengl_x11", 1); + Scene_Data data; + Ecore_Animator *anim; + + if (!ecore_evas_init()) return 0; + + ecore_evas = ecore_evas_new("opengl_x11", 10, 10, WIDTH, HEIGHT, NULL); + + if (!ecore_evas) return 0; + + ecore_evas_callback_delete_request_set(ecore_evas, _on_delete); + ecore_evas_callback_resize_set(ecore_evas, _on_canvas_resize); + ecore_evas_show(ecore_evas); + + evas = ecore_evas_get(ecore_evas); + + _scene_setup(&data); + + /* Add a background rectangle objects. */ + background = eo_add(EVAS_RECTANGLE_CLASS, evas); + eo_unref(background); + eo_do(background, + evas_obj_color_set(0, 0, 0, 255), + evas_obj_size_set(WIDTH, HEIGHT), + evas_obj_visibility_set(EINA_TRUE)); + + /* Add an image object for 3D scene rendering. */ + image = evas_object_image_filled_add(evas); + + eo_do(image, + evas_obj_size_set(WIDTH, HEIGHT), + evas_obj_visibility_set(EINA_TRUE)); + + /* Set the image object as render target for 3D scene. */ + eo_do(image, evas_obj_image_scene_set(data.scene)); + + + /* Add animation timer callback. */ + ecore_animator_frametime_set(0.008); + anim = ecore_animator_add(_animate_scene, &data); + + /* Enter main loop. */ + ecore_main_loop_begin(); + + ecore_evas_free(ecore_evas); + ecore_evas_shutdown(); + ecore_animator_del(anim); + + return 0; +} diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h index c4f740edeb..5f20e3fbbe 100644 --- a/src/lib/evas/Evas_Eo.h +++ b/src/lib/evas/Evas_Eo.h @@ -466,6 +466,7 @@ typedef enum _Evas_3D_State EVAS_3D_STATE_MESH_INDEX_DATA, EVAS_3D_STATE_MESH_VERTEX_ASSEMBLY, EVAS_3D_STATE_MESH_SHADE_MODE, + EVAS_3D_STATE_MESH_FOG, EVAS_3D_STATE_CAMERA_PROJECTION = 1, diff --git a/src/lib/evas/canvas/evas_3d_mesh.c b/src/lib/evas/canvas/evas_3d_mesh.c index 25e9ddeef2..c90876d3be 100644 --- a/src/lib/evas/canvas/evas_3d_mesh.c +++ b/src/lib/evas/canvas/evas_3d_mesh.c @@ -742,6 +742,36 @@ _evas_3d_mesh_vertex_assembly_get(Eo *obj EINA_UNUSED, Evas_3D_Mesh_Data *pd) return pd->assembly; } +EOLIAN static void +_evas_3d_mesh_fog_color_set(Eo *obj, Evas_3D_Mesh_Data *pd, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a) +{ + evas_color_set(&pd->fog_color, r, g, b, a); + eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_MESH_FOG, NULL)); +} + +EOLIAN static void +_evas_3d_mesh_fog_color_get(Eo *obj EINA_UNUSED, Evas_3D_Mesh_Data *pd, + Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a) +{ + if (r) *r = pd->fog_color.r; + if (g) *g = pd->fog_color.g; + if (b) *b = pd->fog_color.b; + if (a) *a = pd->fog_color.a; +} + +EOLIAN static void +_evas_3d_mesh_fog_enable_set(Eo *obj, Evas_3D_Mesh_Data *pd, Eina_Bool enabled) +{ + pd->fog_enabled = enabled; + eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_MESH_FOG, NULL)); +} + +EOLIAN static Eina_Bool +_evas_3d_mesh_fog_enable_get(Eo *obj, Evas_3D_Mesh_Data *pd) +{ + return pd->fog_enabled; +} + EOLIAN static void _evas_3d_mesh_file_set(Eo *obj, Evas_3D_Mesh_Data *pd, Evas_3D_Mesh_File_Type type, const char *file, const char *key EINA_UNUSED) { diff --git a/src/lib/evas/canvas/evas_3d_mesh.eo b/src/lib/evas/canvas/evas_3d_mesh.eo index e7409d0ffe..c65cb34950 100644 --- a/src/lib/evas/canvas/evas_3d_mesh.eo +++ b/src/lib/evas/canvas/evas_3d_mesh.eo @@ -310,6 +310,48 @@ class Evas_3D_Mesh (Evas_3D_Object, Evas.Common_Interface) return int; } + fog_color_set { + /* + Set the fog color and density for the given mesh. + @ingroup Evas_3D_Mesh + */ + params { + @in Evas_Real r; /*@ The red component of the fog color.*/ + @in Evas_Real g; /*@ The green component of the fog color.*/ + @in Evas_Real b; /*@ The blue component of the fog color.*/ + @in Evas_Real a; /*@ The transparency of fog.*/ + } + } + fog_color_get { + /* + Set the fog color and density for the given mesh. + @ingroup Evas_3D_Mesh + */ + params { + @out Evas_Real r; /*@ Pointer to receive red component of the fog color.*/ + @out Evas_Real g; /*@ Pointer to receive green component of the fog color.*/ + @out Evas_Real b; /*@ Pointer to receive blue component of the fog color.*/ + @out Evas_Real a; /*@ Pointer to receive transparency of fog.*/ + } + } + fog_enable_set { + /* + Enable or disable fog effect for given mesh. + @ingroup Evas_3D_Mesh + */ + params { + @in Eina_Bool enabled; /*@ The red component of the fog color.*/ + } + } + fog_enable_get { + /* + Get fog effect status for the given mesh. + @ingroup Evas_3D_Mesh + */ + return Eina_Bool; + params { + } + } } properties { shade_mode { diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 6cdce715ad..2adac27c39 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -246,7 +246,10 @@ struct _Evas_3D_Mesh Evas_3D_Vertex_Assembly assembly; - Eina_Hash *nodes; + Eina_Hash *nodes; + + Evas_Color fog_color; + Eina_Bool fog_enabled :1; }; struct _Evas_3D_Texture diff --git a/src/modules/evas/engines/gl_common/evas_gl_3d.c b/src/modules/evas/engines/gl_common/evas_gl_3d.c index 3a746b639f..1511ef9cd3 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_3d.c +++ b/src/modules/evas/engines/gl_common/evas_gl_3d.c @@ -1084,6 +1084,11 @@ _mesh_draw_data_build(E3D_Draw_Data *data, if (pdmesh->frames == NULL) return EINA_FALSE; + if (pdmesh->fog_enabled) + { + data->flags |= E3D_SHADER_FLAG_FOG_ENABLED; + data->fog_color = pdmesh->fog_color; + } data->mode = pdmesh->shade_mode; data->assembly = pdmesh->assembly; data->vertex_count = pdmesh->vertex_count; diff --git a/src/modules/evas/engines/gl_common/evas_gl_3d_private.h b/src/modules/evas/engines/gl_common/evas_gl_3d_private.h index 2eb5bf48b4..b2da02b686 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_3d_private.h +++ b/src/modules/evas/engines/gl_common/evas_gl_3d_private.h @@ -35,6 +35,7 @@ typedef unsigned long E3D_Shader_Flag; #define E3D_SHADER_FLAG_SPECULAR_TEXTURE_BLEND (1 << 26) #define E3D_SHADER_FLAG_EMISSION_TEXTURE_BLEND (1 << 27) #define E3D_SHADER_FLAG_NORMAL_TEXTURE_BLEND (1 << 28) +#define E3D_SHADER_FLAG_FOG_ENABLED (1 << 29) static inline Eina_Bool _flags_need_tex_coord(E3D_Shader_Flag flags) @@ -90,6 +91,7 @@ struct _E3D_Draw_Data Evas_Color diffuse; Evas_Color specular; } light; + Evas_Color fog_color; }; struct _E3D_Texture diff --git a/src/modules/evas/engines/gl_common/evas_gl_3d_shader.c b/src/modules/evas/engines/gl_common/evas_gl_3d_shader.c index c575899c9b..e86ecb1643 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_3d_shader.c +++ b/src/modules/evas/engines/gl_common/evas_gl_3d_shader.c @@ -44,6 +44,8 @@ typedef enum _E3D_Uniform E3D_UNIFORM_MATERIAL_SPECULAR, E3D_UNIFORM_MATERIAL_EMISSION, E3D_UNIFORM_MATERIAL_SHININESS, + E3D_UNIFORM_FOG_FACTOR, + E3D_UNIFORM_FOG_COLOR, E3D_UNIFORM_COUNT, } E3D_Uniform; @@ -497,6 +499,12 @@ _fragment_shader_string_variable_add(E3D_Shader_String *shader, if (_flags_need_tex_coord(flags)) ADD_LINE("varying vec2 vTexCoord;"); + if (flags & E3D_SHADER_FLAG_FOG_ENABLED) + { + ADD_LINE("uniform float uFogFactor;"); + ADD_LINE("uniform vec4 uFogColor;"); + } + /* Materials. */ if (flags & E3D_SHADER_FLAG_DIFFUSE) { @@ -1067,6 +1075,14 @@ _fragment_shader_string_get(E3D_Shader_String *shader, ADD_LINE("fragmentNormalMap();"); } + if (flags & E3D_SHADER_FLAG_FOG_ENABLED) + { + ADD_LINE("float z = gl_FragCoord.z / gl_FragCoord.w;"); + ADD_LINE("float fogFactor = exp2( -uFogFactor * uFogFactor * z * z * 1.44 );"); + ADD_LINE("fogFactor = clamp(fogFactor, 0.0, 1.0);"); + ADD_LINE("gl_FragColor = mix(uFogColor, gl_FragColor, fogFactor );"); + } + ADD_LINE("}"); } @@ -1234,6 +1250,8 @@ static const char *uniform_names[] = "uMaterialSpecular", "uMaterialEmission", "uMaterialShininess", + "uFogFactor", + "uFogColor" }; static inline void @@ -1394,6 +1412,12 @@ _uniform_upload(E3D_Uniform u, GLint loc, const E3D_Draw_Data *data) case E3D_UNIFORM_MATERIAL_SHININESS: glUniform1f(loc, data->shininess); break; + case E3D_UNIFORM_FOG_FACTOR: + glUniform1f(loc, data->fog_color.a); + break; + case E3D_UNIFORM_FOG_COLOR: + glUniform4f(loc, data->fog_color.r, data->fog_color.g, data->fog_color.b, 1); + break; default: ERR("Invalid uniform ID."); break;