evas: Evas_3D - ColorPick mechanism finding node and mesh in scene.
authorOleksandr Shcherbina <o.shcherbina@samsung.com>
Thu, 5 Feb 2015 14:34:25 +0000 (15:34 +0100)
committerCedric BAIL <cedric@osg.samsung.com>
Mon, 9 Feb 2015 21:03:26 +0000 (22:03 +0100)
Summary:
Added additional texture and framebuffer for rendering meshes to it.
Added function that return OpenGL id additional texture
Added function that return color from target texture by mouse pick coordinates
Added function that render need meshes to target texture
Added engine wrappers for possibility force render to texture

@feature

Reviewers: Hermet, raster, cedric

Subscribers: cedric

Differential Revision: https://phab.enlightenment.org/D1811

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
src/lib/evas/Evas_Eo.h
src/lib/evas/include/evas_private.h
src/modules/evas/engines/gl_common/evas_gl_3d.c
src/modules/evas/engines/gl_common/evas_gl_3d_common.h
src/modules/evas/engines/gl_common/evas_gl_3d_private.h
src/modules/evas/engines/gl_common/evas_gl_3d_shader.c
src/modules/evas/engines/gl_generic/evas_engine.c

index 39c568ba4a7c31a7ed32935cb9b213b46903ff5c..8fa89b30ba714cef2dd7c9facc375818765e7661 100644 (file)
@@ -487,6 +487,7 @@ typedef enum _Evas_3D_State
    EVAS_3D_STATE_MESH_SHADE_MODE,
    EVAS_3D_STATE_MESH_FOG,
    EVAS_3D_STATE_MESH_BLENDING,
+   EVAS_3D_STATE_MESH_COLOR_PICK,
 
    EVAS_3D_STATE_CAMERA_PROJECTION = 1,
 
@@ -777,7 +778,8 @@ typedef enum _Evas_3D_Shade_Mode
    EVAS_3D_SHADE_MODE_NORMAL_MAP,
    /**< fragment color is defined by its z-coord*/
    EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER,
-
+   /**< rendering to additional frame bufer*/
+   EVAS_3D_SHADE_MODE_COLOR_PICK,
 } Evas_3D_Shade_Mode;
 
 /**
index 673b6aab77ea5e2e9dcb72fc996ceb848d72e97c..e0f8171e261d548e187f6be6ca7161e9385be386 100644 (file)
@@ -340,6 +340,9 @@ struct _Evas_3D_Mesh
 
    Evas_Color              fog_color;
    Eina_Bool               fog_enabled :1;
+
+   double                  color_pick_key;
+   Eina_Bool               color_pick_enabled :1;
 };
 
 struct _Evas_3D_Texture
@@ -376,6 +379,9 @@ struct _Evas_3D_Scene_Public_Data
    Eina_List        *light_nodes;
    Eina_List        *mesh_nodes;
    Eina_Bool        shadows_enabled :1;
+   Eina_Bool        color_pick_enabled :1;
+   Eina_Hash        *node_mesh_colors;
+   Eina_Hash        *colors_node_mesh;
 };
 
 struct _Evas_3D_Pick_Data
@@ -1319,6 +1325,10 @@ struct _Evas_Func
    void *(*image_drawable_set)           (void *data, void *image, void *drawable);
 
    void  (*drawable_scene_render)        (void *data, void *drawable, void *scene_data);
+   Eina_Bool (*drawable_scene_render_to_texture) (void *data, void *drawable, void *scene_data);
+
+   int (*drawable_texture_color_pick_id_get) (void *drawable);
+   double (*drawable_texture_pixel_color_get) (unsigned int tex EINA_UNUSED, int x, int y, void *drawable);
 
    void *(*texture_new)                  (void *data);
    void  (*texture_free)                 (void *data, void *texture);
index 4f045d29e770f1fb5cf5bb860b952a17032a5ffd..ee464f4d34b9d1ce78e513f4e2c271845131c11c 100644 (file)
@@ -1,6 +1,23 @@
 #include "evas_gl_private.h"
 #include "evas_gl_3d_private.h"
 
+#define RENDER_MESH_NODE_ITERATE_BEGIN(param)                                                      \
+   Evas_Mat4          matrix_mv;                                                                   \
+   Evas_Mat4          matrix_mvp;                                                                  \
+   Eina_Iterator     *it;                                                                          \
+   void              *ptr;                                                                         \
+   evas_mat4_multiply(&matrix_mv, matrix_##param, &pd_mesh_node->data.mesh.matrix_local_to_world); \
+   evas_mat4_multiply(&matrix_mvp, &pd->projection, &matrix_mv);                                   \
+   it = eina_hash_iterator_data_new(pd_mesh_node->data.mesh.node_meshes);                          \
+   while (eina_iterator_next(it, &ptr))                                                            \
+     {                                                                                             \
+        Evas_3D_Node_Mesh *nm = (Evas_3D_Node_Mesh *)ptr;                                          \
+        Evas_3D_Mesh_Data *pdmesh = eo_data_scope_get(nm->mesh, EVAS_3D_MESH_CLASS);
+
+#define RENDER_MESH_NODE_ITERATE_END \
+   }                                 \
+   eina_iterator_free(it);
+
 void
 e3d_texture_param_update(E3D_Texture *texture)
 {
@@ -407,7 +424,7 @@ E3D_Drawable *
 e3d_drawable_new(int w, int h, int alpha, GLenum depth_format, GLenum stencil_format)
 {
    E3D_Drawable  *drawable = NULL;
-   GLuint         tex, fbo, texDepth;
+   GLuint         tex, fbo, texDepth, texcolorpick, color_pick_fb_id;
    GLuint         depth_stencil_buf = 0;
    GLuint         depth_buf = 0;
    GLuint         stencil_buf = 0;
@@ -435,6 +452,18 @@ e3d_drawable_new(int w, int h, int alpha, GLenum depth_format, GLenum stencil_fo
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, w, h, 0, GL_RED, GL_UNSIGNED_SHORT, 0);
 #endif
 
+   glGenTextures(1, &texcolorpick);
+   glBindTexture(GL_TEXTURE_2D, texcolorpick);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+#ifndef GL_GLES
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, w, h, 0, GL_RED, GL_UNSIGNED_SHORT, 0);
+#endif
+
+   glGenFramebuffers(1, &color_pick_fb_id);
+
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
@@ -511,6 +540,8 @@ e3d_drawable_new(int w, int h, int alpha, GLenum depth_format, GLenum stencil_fo
    drawable->tex = tex;
    drawable->fbo = fbo;
    drawable->depth_stencil_buf = depth_stencil_buf;
+   drawable->texcolorpick = texcolorpick;
+   drawable->color_pick_fb_id = color_pick_fb_id;
    drawable->depth_buf = depth_buf;
    drawable->stencil_buf = stencil_buf;
    drawable->texDepth = texDepth;
@@ -522,9 +553,13 @@ error:
 
    if (tex)
      glDeleteTextures(1, &tex);
+   if (texcolorpick)
+     glDeleteTextures(1, &texcolorpick);
 
    if (fbo)
      glDeleteFramebuffers(1, &fbo);
+   if (color_pick_fb_id)
+     glDeleteFramebuffers(1, &color_pick_fb_id);
 
    if (depth_stencil_buf)
      {
@@ -595,6 +630,12 @@ e3d_drawable_texture_id_get(E3D_Drawable *drawable)
    return drawable->tex;
 }
 
+GLuint
+e3d_drawable_texture_color_pick_id_get(E3D_Drawable *drawable)
+{
+   return drawable->texcolorpick;
+}
+
 GLenum
 e3d_drawable_format_get(E3D_Drawable *drawable)
 {
@@ -1105,6 +1146,12 @@ _mesh_draw_data_build(E3D_Draw_Data *data,
    if (pdmesh->shadowed)
         data->flags |= E3D_SHADER_FLAG_SHADOWED;
 
+   if (pdmesh->color_pick_enabled)
+     {
+        data->flags |= E3D_SHADER_FLAG_COLOR_PICK_ENABLED;
+        data->color_pick_key = pdmesh->color_pick_key;
+     }
+
    data->blending = pdmesh->blending;
    data->blend_sfactor = pdmesh->blend_sfactor;
    data->blend_dfactor = pdmesh->blend_dfactor;
@@ -1141,6 +1188,10 @@ _mesh_draw_data_build(E3D_Draw_Data *data,
      {
         BUILD(vertex_attrib,     VERTEX_POSITION,     EINA_TRUE);
      }
+   else if (pdmesh->shade_mode == EVAS_3D_SHADE_MODE_COLOR_PICK)
+     {
+        BUILD(vertex_attrib,     VERTEX_POSITION,     EINA_TRUE);
+     }
    else if (pdmesh->shade_mode == EVAS_3D_SHADE_MODE_DIFFUSE)
      {
         BUILD(vertex_attrib,     VERTEX_POSITION,     EINA_TRUE);
@@ -1256,32 +1307,18 @@ void _shadowmap_render(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3D_S
 
    EINA_LIST_FOREACH(data->mesh_nodes, l, n)
      {
-        Evas_Mat4          matrix_mv;
-        Evas_Mat4          matrix_mvp;
-        Eina_Iterator     *it;
-        void              *ptr;
-
         Evas_3D_Node_Data *pd_mesh_node = eo_data_scope_get(n, EVAS_3D_NODE_CLASS);
 
         if (evas_is_sphere_in_frustum(&pd_mesh_node->bsphere, planes))
           {
-
-             evas_mat4_multiply(&matrix_mv, matrix_light_eye, &pd_mesh_node->data.mesh.matrix_local_to_world);
-             evas_mat4_multiply(&matrix_mvp, &pd->projection,
-                           &matrix_mv);
-
-             it = eina_hash_iterator_data_new(pd_mesh_node->data.mesh.node_meshes);
-
-             while (eina_iterator_next(it, &ptr))
+             RENDER_MESH_NODE_ITERATE_BEGIN(light_eye)
                {
-                  Evas_3D_Node_Mesh *nm = (Evas_3D_Node_Mesh *)ptr;
-                  Evas_3D_Mesh_Data *pdmesh = eo_data_scope_get(nm->mesh, EVAS_3D_MESH_CLASS);
                   shade_mode = pdmesh->shade_mode;
                   pdmesh->shade_mode = EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER;
                   _mesh_draw(renderer, nm->mesh, nm->frame, light, matrix_light_eye, &matrix_mv, &matrix_mvp, &matrix_mvp);
                   pdmesh->shade_mode = shade_mode;
                }
-             eina_iterator_free(it);
+             RENDER_MESH_NODE_ITERATE_END
           }
      }
 
@@ -1367,3 +1404,98 @@ e3d_drawable_scene_render(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3
      }
    e3d_renderer_flush(renderer);
 }
+
+Eina_Bool
+e3d_drawable_scene_render_to_texture(E3D_Drawable *drawable, E3D_Renderer *renderer,
+                                     Evas_3D_Scene_Public_Data *data)
+{
+   const Evas_Mat4  *matrix_eye;
+   Evas_3D_Shade_Mode shade_mode;
+   Eina_Stringshare *tmp;
+   Eina_Iterator *itmn;
+   void *ptrmn;
+   Eina_List *repeat_node = NULL;
+   Evas_Color c = {0, 0, 0}, *unic_color = NULL;
+
+   glBindFramebuffer(GL_FRAMEBUFFER, drawable->color_pick_fb_id);
+   glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                          GL_TEXTURE_2D, drawable->texcolorpick, 0);
+#ifdef GL_GLES
+   glBindTexture(GL_TEXTURE_2D, drawable->depth_stencil_buf);
+   glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                               GL_TEXTURE_2D, drawable->depth_stencil_buf, 0);
+#else
+   glBindRenderbuffer(GL_RENDERBUFFER, drawable->depth_stencil_buf);
+   glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                             GL_RENDERBUFFER, drawable->depth_stencil_buf);
+#endif
+
+   e3d_renderer_clear(renderer, &c);
+
+   Evas_3D_Node_Data *pd_camera_node = eo_data_scope_get(data->camera_node, EVAS_3D_NODE_CLASS);
+   matrix_eye = &pd_camera_node->data.camera.matrix_world_to_eye;
+   Evas_3D_Camera_Data *pd = eo_data_scope_get(pd_camera_node->data.camera.camera, EVAS_3D_CAMERA_CLASS);
+
+   itmn = eina_hash_iterator_data_new(data->colors_node_mesh);
+
+   while (eina_iterator_next(itmn, &ptrmn))
+     {
+        Evas_3D_Node      *n;
+        Eina_Array *arr = NULL;
+
+        arr = (Eina_Array *)ptrmn;
+        n = (Evas_3D_Node *)eina_array_data_get(arr, 0);
+        /*To avoid repeatedly render mesh*/
+        if (!repeat_node)
+          repeat_node = eina_list_append(repeat_node, (void*)n);
+        else
+          {
+             if (eina_list_data_find(repeat_node, (void *)n))
+               continue;
+             else
+               repeat_node = eina_list_append(repeat_node, (void *)n);
+          }
+        Evas_3D_Node_Data *pd_mesh_node = eo_data_scope_get(n, EVAS_3D_NODE_CLASS);
+        RENDER_MESH_NODE_ITERATE_BEGIN(eye)
+          {
+             if (pdmesh->color_pick_enabled)
+               {
+                  tmp = eina_stringshare_printf("%p %p", n, nm->mesh);
+                  unic_color = (Evas_Color *)eina_hash_find(data->node_mesh_colors, tmp);
+                  if (unic_color)
+                    {
+                       pdmesh->color_pick_key = unic_color->r;
+                       shade_mode = pdmesh->shade_mode;
+                       pdmesh->shade_mode = EVAS_3D_SHADE_MODE_COLOR_PICK;
+                       _mesh_draw(renderer, nm->mesh, nm->frame, NULL, matrix_eye, &matrix_mv,
+                                  &matrix_mvp, NULL);
+                       pdmesh->shade_mode = shade_mode;
+                    }
+                  eina_stringshare_del(tmp);
+               }
+          }
+        RENDER_MESH_NODE_ITERATE_END
+     }
+
+   eina_iterator_free(itmn);
+   eina_list_free(repeat_node);
+   glBindFramebuffer(GL_FRAMEBUFFER, drawable->fbo);
+   return EINA_TRUE;
+}
+
+double
+e3d_drawable_texture_pixel_color_get(GLuint tex EINA_UNUSED, int x, int y,
+                            void *drawable)
+{
+   E3D_Drawable *d = (E3D_Drawable *)drawable;
+   GLuint pixel;
+
+   glBindFramebuffer(GL_FRAMEBUFFER, d->color_pick_fb_id);
+   /*TODO Bottle neck - get more effective getting pixels from openGL*/
+   glReadPixels(x, y, 1, 1, GL_RED, GL_UNSIGNED_SHORT, &pixel);
+   glBindFramebuffer(GL_FRAMEBUFFER, d->fbo);
+   return (double)pixel / USHRT_MAX;
+}
+
+#undef RENDER_MESH_NODE_ITERATE_BEGIN
+#undef RENDER_MESH_NODE_ITERATE_END
index ceba63e5f051366aee4481d4236d1e683f6c167c..f119b40c460bfb1addce495ede92cead5997e3ae 100644 (file)
@@ -28,8 +28,11 @@ void                 e3d_texture_filter_get(const E3D_Texture *texture, Evas_3D_
 E3D_Drawable        *e3d_drawable_new(int w, int h, int alpha, GLenum depth_format, GLenum stencil_format);
 void                 e3d_drawable_free(E3D_Drawable *drawable);
 void                 e3d_drawable_scene_render(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3D_Scene_Public_Data *data);
+Eina_Bool            e3d_drawable_scene_render_to_texture(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3D_Scene_Public_Data *data);
 void                 e3d_drawable_size_get(E3D_Drawable *drawable, int *w, int *h);
 GLuint               e3d_drawable_texture_id_get(E3D_Drawable *drawable);
+GLuint               e3d_drawable_texture_color_pick_id_get(E3D_Drawable *drawable);
+double               e3d_drawable_texture_pixel_color_get(GLuint tex EINA_UNUSED, int x, int y, void *drawable);
 GLenum               e3d_drawable_format_get(E3D_Drawable *drawable);
 
 /* Renderer */
index 75a76acb31d552e50f190ce1ef37c8c699526c53..6d956f554dcce80e5dfeceb0653e4d68db5bf0ab 100644 (file)
@@ -37,7 +37,7 @@ typedef unsigned long         E3D_Shader_Flag;
 #define E3D_SHADER_FLAG_NORMAL_TEXTURE_BLEND    (1 << 28)
 #define E3D_SHADER_FLAG_FOG_ENABLED             (1 << 29)
 #define E3D_SHADER_FLAG_SHADOWED                (1 << 30)
-
+#define E3D_SHADER_FLAG_COLOR_PICK_ENABLED      (1 << 31)
 
 static inline Eina_Bool
 _flags_need_tex_coord(E3D_Shader_Flag flags)
@@ -100,6 +100,7 @@ struct _E3D_Draw_Data
         Evas_Color  specular;
    } light;
    Evas_Color fog_color;
+   double color_pick_key;
 };
 
 struct _E3D_Texture
@@ -126,13 +127,14 @@ struct _E3D_Drawable
    GLenum   format;
    GLenum   depth_format;
    GLenum   stencil_format;
-
    GLuint   tex;
    GLuint   fbo;
    GLuint   depth_stencil_buf;
    GLuint   depth_buf;
    GLuint   stencil_buf;
    GLuint   texDepth;
+   GLuint texcolorpick;
+   GLuint color_pick_fb_id;
 };
 
 /* Texture internal functions. */
index c036aa18400e3e1bb787cd83504a64a4c26fb13f..e042c83b8310f6227f58a6282280b20953a8a2f5 100644 (file)
@@ -49,6 +49,7 @@ typedef enum _E3D_Uniform
    E3D_UNIFORM_MATERIAL_SHININESS,
    E3D_UNIFORM_FOG_FACTOR,
    E3D_UNIFORM_FOG_COLOR,
+   E3D_UNIFORM_COLOR_PICK,
 
    E3D_UNIFORM_COUNT,
 } E3D_Uniform;
@@ -526,6 +527,9 @@ _fragment_shader_string_variable_add(E3D_Shader_String *shader,
         ADD_LINE("uniform sampler2D uShadowMap;");
      }
 
+       if (flags & E3D_SHADER_FLAG_COLOR_PICK_ENABLED)
+         ADD_LINE("uniform float uColorPick;");
+
    /* Materials. */
    if (flags & E3D_SHADER_FLAG_DIFFUSE)
      {
@@ -1151,6 +1155,11 @@ _fragment_shader_string_get(E3D_Shader_String *shader,
         ADD_LINE("gl_FragColor = mix(uFogColor, gl_FragColor, fogFactor );");
      }
 
+   if (mode == EVAS_3D_SHADE_MODE_COLOR_PICK)
+     {
+       ADD_LINE("gl_FragColor = vec4(uColorPick);");
+     }
+
    ADD_LINE("}");
 }
 
@@ -1321,7 +1330,8 @@ static const char *uniform_names[] =
    "uMaterialEmission",
    "uMaterialShininess",
    "uFogFactor",
-   "uFogColor"
+   "uFogColor",
+   "uColorPick"
 };
 
 static inline void
@@ -1498,6 +1508,9 @@ _uniform_upload(E3D_Uniform u, GLint loc, const E3D_Draw_Data *data)
       case E3D_UNIFORM_FOG_COLOR:
          glUniform4f(loc, data->fog_color.r, data->fog_color.g, data->fog_color.b, 1);
          break;
+      case E3D_UNIFORM_COLOR_PICK:
+         glUniform1f(loc, data->color_pick_key);
+         break;
       default:
          ERR("Invalid uniform ID.");
          break;
index e280fddf91caff974a600dbd993e7de7eebd2e6d..082ac0d92191e2e8245b6e73213176f090ea245a 100644 (file)
@@ -1836,6 +1836,35 @@ eng_drawable_scene_render(void *data, void *drawable, void *scene_data)
    e3d_drawable_scene_render(drawable, renderer, scene_data);
 }
 
+static int
+eng_drawable_texture_color_pick_id_get(void *drawable)
+{
+   return e3d_drawable_texture_color_pick_id_get((E3D_Drawable *)drawable);
+}
+
+static double
+eng_drawable_texture_pixel_color_get(GLuint tex EINA_UNUSED, int x, int y, void *drawable)
+{
+   return e3d_drawable_texture_pixel_color_get(tex, x, y, drawable);
+}
+
+static Eina_Bool
+eng_drawable_scene_render_to_texture(void *data, void *drawable, void *scene_data)
+{
+   Evas_Engine_GL_Context *gl_context;
+   Render_Engine_GL_Generic *re = data;
+   E3D_Renderer *renderer = NULL;
+
+   re->window_use(re->software.ob);
+   gl_context = re->window_gl_context_get(re->software.ob);
+   evas_gl_common_context_flush(gl_context);
+
+   eng_context_3d_use(data);
+   renderer = eng_renderer_3d_get(data);
+
+   return e3d_drawable_scene_render_to_texture((E3D_Drawable *)drawable, renderer, scene_data);
+}
+
 static void *
 eng_texture_new(void *data EINA_UNUSED)
 {
@@ -2045,6 +2074,10 @@ module_open(Evas_Module *em)
 
    ORD(drawable_scene_render);
 
+   ORD(drawable_texture_color_pick_id_get);
+   ORD(drawable_texture_pixel_color_get);
+   ORD(drawable_scene_render_to_texture);
+
    ORD(texture_new);
    ORD(texture_free);
    ORD(texture_data_set);