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 39c568b..8fa89b3 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 673b6aa..e0f8171 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 4f045d2..ee464f4 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 ceba63e..f119b40 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 75a76ac..6d956f5 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 c036aa1..e042c83 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 e280fdd..082ac0d 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);