From dc0b144cf09deba3a5a6fe746f0130b67b5bf64b Mon Sep 17 00:00:00 2001 From: Oleksandr Shcherbina Date: Wed, 11 Feb 2015 17:44:42 +0100 Subject: [PATCH] evas: Evas_3D - mechanism for finding node by color pick. Summary: See first part https://phab.enlightenment.org/D1811 (backend, gl) Add get/set for color pick mode at evas_3d_mesh and evas_3d_scene Add evas_3d_node_color_node_mesh_collect function to collect data at force rendering Add state flag for scene to avoid useless force rendering in case scene wasn't changed Add functionality for color pick in evas_3d_scene_pick method Reviewers: Hermet, raster, cedric Reviewed By: cedric Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D1956 Signed-off-by: Cedric BAIL --- src/lib/evas/Evas_Eo.h | 1 + src/lib/evas/canvas/evas_3d_mesh.c | 17 ++++++ src/lib/evas/canvas/evas_3d_mesh.eo | 21 +++++++ src/lib/evas/canvas/evas_3d_node.c | 71 +++++++++++++++++++++++ src/lib/evas/canvas/evas_3d_scene.c | 109 +++++++++++++++++++++++++++++++++-- src/lib/evas/canvas/evas_3d_scene.eo | 21 +++++++ src/lib/evas/include/evas_private.h | 8 ++- 7 files changed, 242 insertions(+), 6 deletions(-) diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h index 8fa89b3..033ada2 100644 --- a/src/lib/evas/Evas_Eo.h +++ b/src/lib/evas/Evas_Eo.h @@ -468,6 +468,7 @@ typedef enum _Evas_3D_State EVAS_3D_STATE_SCENE_BACKGROUND_COLOR, EVAS_3D_STATE_SCENE_SIZE, EVAS_3D_STATE_SCENE_SHADOWS_ENABLED, + EVAS_3D_STATE_SCENE_UPDATED, EVAS_3D_STATE_TEXTURE_DATA = 1, EVAS_3D_STATE_TEXTURE_WRAP, diff --git a/src/lib/evas/canvas/evas_3d_mesh.c b/src/lib/evas/canvas/evas_3d_mesh.c index ddbf619..4430438 100644 --- a/src/lib/evas/canvas/evas_3d_mesh.c +++ b/src/lib/evas/canvas/evas_3d_mesh.c @@ -120,6 +120,9 @@ _mesh_init(Evas_3D_Mesh_Data *pd) pd->blend_sfactor = EVAS_3D_BLEND_ONE; pd->blend_dfactor = EVAS_3D_BLEND_ZERO; pd->blending = EINA_FALSE; + + pd->color_pick_key = -1.0; + pd->color_pick_enabled = EINA_FALSE; } static inline void @@ -963,4 +966,18 @@ evas_3d_mesh_interpolate_vertex_buffer_get(Evas_3D_Mesh *mesh, int frame, } } +EOLIAN static Eina_Bool +_evas_3d_mesh_color_pick_enable_get(Eo *obj EINA_UNUSED, Evas_3D_Mesh_Data *pd) +{ + return pd->color_pick_enabled; +} +EOLIAN static Eina_Bool +_evas_3d_mesh_color_pick_enable_set(Eo *obj, Evas_3D_Mesh_Data *pd, Eina_Bool _enabled) +{ + if (pd->color_pick_enabled != _enabled) + pd->color_pick_enabled = _enabled; + eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_MESH_COLOR_PICK, NULL)); + return EINA_TRUE; +} + #include "canvas/evas_3d_mesh.eo.c" diff --git a/src/lib/evas/canvas/evas_3d_mesh.eo b/src/lib/evas/canvas/evas_3d_mesh.eo index 5657b32..a23654a 100644 --- a/src/lib/evas/canvas/evas_3d_mesh.eo +++ b/src/lib/evas/canvas/evas_3d_mesh.eo @@ -352,6 +352,27 @@ class Evas_3D_Mesh (Evas_3D_Object, Evas.Common_Interface, Efl.File) params { } } + color_pick_enable_get @const { + /* + Get status of color picking of the mesh. + + @ingroup Evas_3D_Mesh + */ + return: bool; + params { + } + } + color_pick_enable_set { + /* + Set posibility color picking. + + @ingroup Evas_3D_Mesh + */ + return: bool; + params { + @in bool _enabled; /*@ Posibility flag */ + } + } } properties { shade_mode { diff --git a/src/lib/evas/canvas/evas_3d_node.c b/src/lib/evas/canvas/evas_3d_node.c index a5355ed..62e2c1c 100644 --- a/src/lib/evas/canvas/evas_3d_node.c +++ b/src/lib/evas/canvas/evas_3d_node.c @@ -6,6 +6,27 @@ Evas_3D_Mesh_Frame *evas_3d_mesh_frame_find(Evas_3D_Mesh_Data *pd, int frame); +static Eina_Stringshare * +_generate_unic_color_key(Evas_Color *color, Evas_Color *bg_color, Evas_3D_Node *node, Evas_3D_Mesh *mesh, + Eina_Bool init) +{ + static unsigned short red = USHRT_MAX; + + if (init) red = USHRT_MAX; + + if (fabs(bg_color->r - (double)red) <= DBL_EPSILON) red--; + + color->r = (double)red / USHRT_MAX; + color->g = 0.0; + color->b = 0.0; + + red--; + + if (red < 1) red = USHRT_MAX; + + return eina_stringshare_printf("%p %p", node, mesh); +} + static inline Evas_3D_Node_Mesh * _node_mesh_new(Evas_3D_Node *node, Evas_3D_Mesh *mesh) { @@ -795,6 +816,56 @@ evas_3d_node_mesh_collect(Evas_3D_Node *node, void *data) } Eina_Bool +evas_3d_node_color_node_mesh_collect(Evas_3D_Node *node, void *data) +{ + Evas_3D_Scene_Public_Data *scene_data = (Evas_3D_Scene_Public_Data *)data; + Evas_3D_Node_Data *pd = eo_data_scope_get(node, MY_CLASS); + Evas_3D_Node_Data *pd_camera = eo_data_scope_get(scene_data->camera_node, MY_CLASS); + Evas_3D_Camera *camera = (Evas_3D_Camera*)pd_camera->data.camera.camera; + + Eina_List *list_meshes, *l; + Evas_3D_Mesh *mesh; + Eina_Stringshare *key, *datakey; + Evas_Color *color; + Eina_Bool visible = EINA_FALSE; + Eina_Array *arr; + if (pd->type == EVAS_3D_NODE_TYPE_MESH) + { + eo_do(camera, + visible = evas_3d_camera_node_visible_get(scene_data->camera_node, + node, EVAS_3D_FRUSTUM_MODE_BSPHERE)); + if (visible) + { + eo_do (node, list_meshes = (Eina_List *)evas_3d_node_mesh_list_get()); + EINA_LIST_FOREACH(list_meshes, l, mesh) + { + if (eo_do(mesh, evas_3d_mesh_color_pick_enable_get())) + { + color = calloc(1, sizeof(Evas_Color)); + + if (!eina_hash_population(scene_data->node_mesh_colors)) + key = _generate_unic_color_key(color, &scene_data->bg_color, + node, mesh, EINA_TRUE); + else + key = _generate_unic_color_key(color, &scene_data->bg_color, + node, mesh, EINA_FALSE); + + datakey = eina_stringshare_printf("%f %f %f", color->r, color->g, color->b); + eina_hash_add(scene_data->node_mesh_colors, key, color); + arr = eina_array_new(2); + eina_array_push(arr, (void *)node); + eina_array_push(arr, (void *)mesh); + eina_hash_add(scene_data->colors_node_mesh, datakey, arr); + } + } + } + else + return EINA_FALSE; + } + return EINA_TRUE; +} + +Eina_Bool evas_3d_node_light_collect(Evas_3D_Node *node, void *data) { Evas_3D_Scene_Public_Data *scene_data = (Evas_3D_Scene_Public_Data *)data; diff --git a/src/lib/evas/canvas/evas_3d_scene.c b/src/lib/evas/canvas/evas_3d_scene.c index 0e177a7..a26b6c8 100644 --- a/src/lib/evas/canvas/evas_3d_scene.c +++ b/src/lib/evas/canvas/evas_3d_scene.c @@ -9,6 +9,8 @@ evas_3d_scene_data_init(Evas_3D_Scene_Public_Data *data) data->camera_node = NULL; data->light_nodes = NULL; data->mesh_nodes = NULL; + data->node_mesh_colors = NULL; + data->colors_node_mesh = NULL; } void @@ -46,6 +48,8 @@ _evas_3d_scene_evas_3d_object_update_notify(Eo *obj EINA_UNUSED, Evas_3D_Scene_D { eo_do(pd->camera_node, evas_3d_object_update()); } + + eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_SCENE_UPDATED, NULL)); } EAPI Evas_3D_Scene * @@ -65,6 +69,9 @@ _evas_3d_scene_eo_base_constructor(Eo *obj, Evas_3D_Scene_Data *pd) eo_do(obj, evas_3d_object_type_set(EVAS_3D_OBJECT_TYPE_SCENE)); evas_color_set(&pd->bg_color, 0.0, 0.0, 0.0, 0.0); pd->shadows_enabled = EINA_FALSE; + pd->color_pick_enabled = EINA_FALSE; + pd->node_mesh_colors = NULL; + pd->colors_node_mesh = NULL; } EOLIAN static void @@ -608,17 +615,32 @@ _node_pick(Evas_3D_Node *node, void *data) return EINA_TRUE; } +static void _node_mesh_colors_free_cb(void *data) +{ + if (data) free(data); +} + EOLIAN static Eina_Bool _evas_3d_scene_pick(Eo *obj, Evas_3D_Scene_Data *pd, Evas_Real x, Evas_Real y, Evas_3D_Node **node, Evas_3D_Mesh **mesh, Evas_Real *s, Evas_Real *t) { - /* TODO: Use H/W picking if availabe. */ Evas_3D_Pick_Data data; + Evas_3D_Node_Data *pd_camera_node; + Evas_3D_Camera_Data *pd_camera; + Evas_3D_Object_Data *pd_parent; + Evas_Public_Data *e; + int tex, px, py;; + double redcomponent; + Eina_Stringshare *tmp; + Eina_Array *arr = NULL; + Eina_Bool update_scene = EINA_FALSE; + + pd_parent = eo_data_scope_get(obj, EVAS_3D_OBJECT_CLASS); + e = eo_data_scope_get(pd_parent->evas, EVAS_CANVAS_CLASS); data.x = ((x * 2.0) / (Evas_Real)pd->w) - 1.0; data.y = (((pd->h - y - 1) * 2.0) / ((Evas_Real)pd->h)) - 1.0; - data.picked = EINA_FALSE; data.z = 1.0; data.node = NULL; @@ -626,17 +648,78 @@ _evas_3d_scene_pick(Eo *obj, Evas_3D_Scene_Data *pd, Evas_Real x, Evas_Real y, data.s = 0.0; data.t = 0.0; + px = round(x * pd->w / e->viewport.w); + py = round((pd->h - (y * pd->h / e->viewport.h) - 1)); + + /*Use color pick mechanism finding node and mesh*/ + if (pd->color_pick_enabled) + { + Evas_3D_Scene_Public_Data scene_data; + + scene_data.bg_color = pd->bg_color; + scene_data.shadows_enabled = pd->shadows_enabled; + scene_data.camera_node = pd->camera_node; + scene_data.color_pick_enabled = pd->color_pick_enabled; + update_scene = eo_do(obj, evas_3d_object_dirty_get(EVAS_3D_STATE_SCENE_UPDATED)); + if (update_scene) + { + if (pd->node_mesh_colors) + { + eina_hash_free(pd->node_mesh_colors); + eina_hash_free(pd->colors_node_mesh); + pd->node_mesh_colors = NULL; + pd->colors_node_mesh = NULL; + } + pd->node_mesh_colors = eina_hash_stringshared_new(_node_mesh_colors_free_cb); + pd->colors_node_mesh = eina_hash_stringshared_new(_node_mesh_colors_free_cb); + } + scene_data.node_mesh_colors = pd->node_mesh_colors; + scene_data.colors_node_mesh = pd->colors_node_mesh; + evas_3d_node_tree_traverse(pd->root_node, + EVAS_3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_TRUE, + evas_3d_node_color_node_mesh_collect, &scene_data); + + if (e->engine.func->drawable_scene_render_to_texture) + { + if (e->engine.func->drawable_scene_render_to_texture(e->engine.data.output, + pd->surface, &scene_data)) + { + if (e->engine.func->drawable_texture_color_pick_id_get) + tex = e->engine.func->drawable_texture_color_pick_id_get(pd->surface); + if (e->engine.func->drawable_texture_pixel_color_get) + { + redcomponent = e->engine.func->drawable_texture_pixel_color_get(tex, px, py, pd->surface); + tmp = eina_stringshare_printf("%f %f %f", redcomponent, 0.0, 0.0); + arr = (Eina_Array *)eina_hash_find(pd->colors_node_mesh, tmp); + if (arr) + { + if (mesh) *mesh = (Evas_3D_Mesh *)eina_array_data_get(arr, 1); + if (node) *node = (Evas_3D_Node *)eina_array_data_get(arr, 0); + eina_stringshare_del(tmp); + + return EINA_TRUE; + } + else + { + eina_stringshare_del(tmp); + if (mesh) *mesh = NULL; + if (node) *node = NULL; + } + } + } + } + return EINA_FALSE; + } /* Update the scene graph. */ eo_do(obj, evas_3d_object_update()); - Evas_3D_Node_Data *pd_camera_node = eo_data_scope_get(pd->camera_node, EVAS_3D_NODE_CLASS); - Evas_3D_Camera_Data *pd_camera = eo_data_scope_get(pd_camera_node->data.camera.camera, EVAS_3D_CAMERA_CLASS); + pd_camera_node = eo_data_scope_get(pd->camera_node, EVAS_3D_NODE_CLASS); + pd_camera = eo_data_scope_get(pd_camera_node->data.camera.camera, EVAS_3D_CAMERA_CLASS); evas_mat4_multiply(&data.matrix_vp, &pd_camera->projection, &pd_camera_node->data.camera.matrix_world_to_eye); evas_ray3_init(&data.ray_world, data.x, data.y, &data.matrix_vp); - /* Traverse tree while adding meshes into pick data structure. */ evas_3d_node_tree_traverse(pd->root_node, EVAS_3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_TRUE, _node_pick, &data); @@ -726,4 +809,20 @@ _evas_3d_scene_shadows_enable_set(Eo *obj EINA_UNUSED, Evas_3D_Scene_Data *pd, E eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_SCENE_SHADOWS_ENABLED, NULL)); } +EOLIAN static Eina_Bool +_evas_3d_scene_color_pick_enable_get(Eo *obj EINA_UNUSED, Evas_3D_Scene_Data *pd) +{ + return pd->color_pick_enabled; +} + +EOLIAN static Eina_Bool +_evas_3d_scene_color_pick_enable_set(Eo *obj EINA_UNUSED, Evas_3D_Scene_Data *pd, Eina_Bool _enabled) +{ + if (pd->color_pick_enabled != _enabled) + pd->color_pick_enabled = _enabled; + + eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_SCENE_UPDATED, NULL)); + return EINA_TRUE; +} + #include "canvas/evas_3d_scene.eo.c" diff --git a/src/lib/evas/canvas/evas_3d_scene.eo b/src/lib/evas/canvas/evas_3d_scene.eo index 1078c02..bb25f90 100644 --- a/src/lib/evas/canvas/evas_3d_scene.eo +++ b/src/lib/evas/canvas/evas_3d_scene.eo @@ -136,6 +136,27 @@ class Evas_3D_Scene (Evas_3D_Object, Evas.Common_Interface) params { } } + color_pick_enable_get @const { + /* + Get status of color picking of the scene. + + @ingroup Evas_3D_Scene + */ + return: bool; + params { + } + } + color_pick_enable_set { + /* + Set posibility color picking. + + @ingroup Evas_3D_Scene + */ + return: bool; + params { + @in bool color_pick; /*@ Posibility flag */ + } + } } properties { diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index c07cfa3..ceab19d 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -191,11 +191,15 @@ struct _Evas_3D_Scene Evas_3D_Node *root_node; Evas_3D_Node *camera_node; Evas_Color bg_color; + Eina_Bool shadows_enabled :1; + Eina_Bool color_pick_enabled :1; void *surface; int w, h; Eina_List *images; - Eina_Bool shadows_enabled :1; + + Eina_Hash *node_mesh_colors; + Eina_Hash *colors_node_mesh; }; struct _Evas_3D_Node_Mesh @@ -380,6 +384,7 @@ struct _Evas_3D_Scene_Public_Data 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; }; @@ -1628,6 +1633,7 @@ void _canvas_smart_objects_calculate_count_get(Eo *e, void *_pd, va_list *list); void evas_3d_node_traverse(Evas_3D_Node *from, Evas_3D_Node *to, Evas_3D_Node_Traverse_Type type, Eina_Bool skip, Evas_3D_Node_Func func, void *data); void evas_3d_node_tree_traverse(Evas_3D_Node *root, Evas_3D_Tree_Traverse_Type type, Eina_Bool skip, Evas_3D_Node_Func func, void *data); Eina_Bool evas_3d_node_mesh_collect(Evas_3D_Node *node, void *data); +Eina_Bool evas_3d_node_color_node_mesh_collect(Evas_3D_Node *node, void *data); Eina_Bool evas_3d_node_light_collect(Evas_3D_Node *node, void *data); void evas_3d_node_scene_root_add(Evas_3D_Node *node, Evas_3D_Scene *scene); void evas_3d_node_scene_root_del(Evas_3D_Node *node, Evas_3D_Scene *scene); -- 2.7.4