From e47373aee1fd516d3436220ed4f1489baa04f502 Mon Sep 17 00:00:00 2001 From: Oleksandr Shcherbina Date: Tue, 27 May 2014 22:07:28 +0900 Subject: [PATCH] [evas/evas-3d] Add OBB and AABB. Summary: Add axis-aligned bounding box (AABB) to frame. Set and update AABB and oriented bounding box (OBB) in node. Reviewers: Hermet, cedric, raster CC: cedric Differential Revision: https://phab.enlightenment.org/D881 --- src/examples/evas/evas-3d-aabb.c | 308 ++++++++++++++++++ src/lib/evas/canvas/evas_3d_mesh.c | 80 ++++- src/lib/evas/canvas/evas_3d_mesh_loader_md2.c | 8 + src/lib/evas/canvas/evas_3d_node.c | 195 ++++++++++- src/lib/evas/canvas/evas_3d_node.eo | 24 ++ src/lib/evas/include/evas_private.h | 1 + 6 files changed, 600 insertions(+), 16 deletions(-) create mode 100644 src/examples/evas/evas-3d-aabb.c diff --git a/src/examples/evas/evas-3d-aabb.c b/src/examples/evas/evas-3d-aabb.c new file mode 100644 index 0000000000..c1ced0df95 --- /dev/null +++ b/src/examples/evas/evas-3d-aabb.c @@ -0,0 +1,308 @@ +/* + * This example shows how to get and draw axis-aligned bounding box. + + * @see _mesh_aabb(Evas_3D_Mesh **mesh_b, const Evas_3D_Node *node); + * Rotate axises (keys 1-4) for model and bounding box view from another angle. + * Compile with "gcc -o evas-3d-aabb evas-3d-aabb.c `pkg-config --libs --cflags evas ecore ecore-evas eo`" + */ + +#define EFL_EO_API_SUPPORT +#define EFL_BETA_API_SUPPORT + +#include +#include +#include +#include + +#define WIDTH 400 +#define HEIGHT 400 + +Ecore_Evas *ecore_evas = NULL; +Evas *evas = NULL; +Eo *background = NULL; +Eo *image = NULL; + +Eo *scene = NULL; +Eo *root_node = NULL; +Eo *camera_node = NULL; +Eo *light_node = NULL; +Eo *camera = NULL; +Eo *mesh_node = NULL; +Eo *mesh_box_node = NULL; +Eo *mesh = NULL; +Eo *mesh_box = NULL; +Eo *material_box = NULL; +Eo *material = NULL; +Eo *texture = NULL; +Eo *light = NULL; + + +static Eina_Bool +_mesh_aabb(Evas_3D_Mesh **mesh_b, const Evas_3D_Node *node); + +static Eina_Bool +_animate_scene(void *data) +{ + static int frame = 0; + + eo_do((Evas_3D_Node *)data, evas_3d_node_mesh_frame_set(mesh, frame)); + + _mesh_aabb(&mesh_box, mesh_box_node); + + frame += 32; + + if (frame > 256 * 50) frame = 0; + + return EINA_TRUE; +} + +static void +_on_delete(Ecore_Evas *ee EINA_UNUSED) +{ + ecore_main_loop_quit(); +} + +static void +_on_key_down(void *data, Evas *e EINA_UNUSED, Evas_Object *eo EINA_UNUSED, void *event_info) +{ + Evas_Event_Key_Down *ev = event_info; + Evas_3D_Node *node = (Evas_3D_Node *)data; + + switch(atoi(ev->key)) + { + case 1: + { + eo_do(node, evas_3d_node_orientation_angle_axis_set(90, 1.0, 0.0, 0.0)); + break; + } + case 2: + { + eo_do(node, evas_3d_node_orientation_angle_axis_set(90, 0.0, 1.0, 0.0)); + break; + } + case 3: + { + eo_do(node, evas_3d_node_orientation_angle_axis_set(90, 0.0, 0.0, 1.0)); + break; + } + case 4: + { + eo_do(node, evas_3d_node_orientation_angle_axis_set(90, 1.0, 1.0, 0.0)); + break; + } + } +} + +static void +_on_canvas_resize(Ecore_Evas *ee) +{ + int w, h; + + ecore_evas_geometry_get(ee, NULL, NULL, &w, &h); + eo_do(background, evas_obj_size_set(w, h)); + eo_do(image, evas_obj_size_set(w, h)); +} + +static Eina_Bool +_mesh_aabb(Evas_3D_Mesh **mesh_b, const Evas_3D_Node *node) +{ + Evas_Real x0, y0, z0, x1, y1, z1; + + eo_do(mesh_node, evas_3d_node_bounding_box_get(&x0, &y0, &z0, &x1, &y1, &z1)); + + float vertices[] = + { + x0, y0, z1, + x0, y1, z1, + x1, y1, z1, + x1, y0, z1, + + x0, y0, z0, + x1, y0, z0, + x0, y1, z0, + x1, y1, z0, + + x0, y0, z0, + x0, y1, z0, + x0, y0, z1, + x0, y1, z1, + + x1, y0, z0, + x1, y1, z0, + x1, y1, z1, + x1, y0, z1, + + x0, y1, z0, + x1, y1, z0, + x0, y1, z1, + x1, y1, z1, + + x0, y0, z0, + x1, y0, z0, + x1, y0, z1, + x0, y0, z1 + }; + + unsigned short indices[] = + { + 0, 1, 2, 3, 1, 2, 0, 3, + 4, 5, 5, 7, 7, 6, 6, 4, + 8, 9, 9, 11, 11, 10, 10, 8, + 12, 13, 13, 14, 14, 15, 15, 12, + 16, 17, 17, 19, 19, 18, 18, 16, + 20, 21, 21, 22, 22, 23, 23, 20 + }; + + float *cube_vertices = (float *) malloc(1 * sizeof(vertices)); + unsigned short *cube_indices = (unsigned short *) malloc(1 * sizeof(indices)); + memcpy(cube_vertices, vertices, sizeof(vertices)); + memcpy(cube_indices, indices, sizeof(indices)); + + eo_do(*mesh_b, + evas_3d_mesh_vertex_count_set(24), + evas_3d_mesh_frame_add( 0), + evas_3d_mesh_frame_vertex_data_copy_set(0, EVAS_3D_VERTEX_POSITION, 3 * sizeof(float), &cube_vertices[ 0]), + evas_3d_mesh_index_data_copy_set(EVAS_3D_INDEX_FORMAT_UNSIGNED_SHORT, 48, &cube_indices[0]), + evas_3d_mesh_vertex_assembly_set(EVAS_3D_VERTEX_ASSEMBLY_LINES), + evas_3d_mesh_shade_mode_set(EVAS_3D_SHADE_MODE_DIFFUSE), + evas_3d_mesh_frame_material_set(0, material_box)); + + free(cube_vertices); + free(cube_indices); + + return EINA_TRUE; +} + +int +main(void) +{ + 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 = eo_add(EVAS_3D_SCENE_CLASS, evas); + + root_node = eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_NODE)); + + camera = eo_add(EVAS_3D_CAMERA_CLASS, evas); + eo_do(camera, + evas_3d_camera_projection_perspective_set(60.0, 1.0, 1.0, 500.0)); + + camera_node = + eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_CAMERA)); + eo_do(camera_node, + evas_3d_node_camera_set(camera)); + eo_do(root_node, + evas_3d_node_member_add(camera_node)); + eo_do(camera_node, + evas_3d_node_position_set(100.0, 50.0, 20.0), + evas_3d_node_look_at_set(EVAS_3D_SPACE_PARENT, 0.0, 0.0, 20.0, + EVAS_3D_SPACE_PARENT, 0.0, 0.0, 1.0)); + light = eo_add(EVAS_3D_LIGHT_CLASS, evas); + eo_do(light, + evas_3d_light_ambient_set(1.0, 1.0, 1.0, 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), + evas_3d_light_directional_set(EINA_TRUE)); + + light_node = + eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_LIGHT)); + eo_do(light_node, + evas_3d_node_light_set(light), + evas_3d_node_position_set(1000.0, 0.0, 1000.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(root_node, + evas_3d_node_member_add(light_node)); + + mesh = eo_add(EVAS_3D_MESH_CLASS, evas); + material = eo_add(EVAS_3D_MATERIAL_CLASS, evas); + + eo_do(mesh, + evas_3d_mesh_file_set(EVAS_3D_MESH_FILE_TYPE_MD2, "sonic.md2", NULL), + evas_3d_mesh_frame_material_set(0, material), + evas_3d_mesh_shade_mode_set(EVAS_3D_SHADE_MODE_PHONG)); + + texture = eo_add(EVAS_3D_TEXTURE_CLASS, evas); + eo_do(texture, + evas_3d_texture_file_set("sonic.png", NULL), + evas_3d_texture_filter_set(EVAS_3D_TEXTURE_FILTER_NEAREST, + EVAS_3D_TEXTURE_FILTER_NEAREST), + evas_3d_texture_wrap_set(EVAS_3D_WRAP_MODE_REPEAT, + EVAS_3D_WRAP_MODE_REPEAT)); + eo_do(material, + evas_3d_material_texture_set(EVAS_3D_MATERIAL_DIFFUSE, texture), + 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_enable_set(EVAS_3D_MATERIAL_NORMAL, EINA_TRUE), + evas_3d_material_color_set(EVAS_3D_MATERIAL_AMBIENT, + 0.01, 0.01, 0.01, 1.0), + evas_3d_material_color_set(EVAS_3D_MATERIAL_DIFFUSE, + 1.0, 1.0, 1.0, 1.0), + evas_3d_material_color_set(EVAS_3D_MATERIAL_SPECULAR, + 1.0, 1.0, 1.0, 1.0), + evas_3d_material_shininess_set(50.0)); + + mesh_node = eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_MESH)); + mesh_box_node = eo_add_custom(EVAS_3D_NODE_CLASS, evas, + evas_3d_node_constructor(EVAS_3D_NODE_TYPE_MESH)); + + material_box = eo_add(EVAS_3D_MATERIAL_CLASS, evas); + eo_do(material_box, evas_3d_material_enable_set(EVAS_3D_MATERIAL_DIFFUSE, EINA_TRUE)); + + mesh_box = eo_add(EVAS_3D_MESH_CLASS, evas); + _mesh_aabb(&mesh_box, mesh_box_node); + + eo_do(root_node, + evas_3d_node_member_add(mesh_box_node)); + eo_do(mesh_box_node, + evas_3d_node_mesh_add(mesh_box)); + + eo_do(root_node, + evas_3d_node_member_add(mesh_node)); + eo_do(mesh_node, + evas_3d_node_mesh_add(mesh)); + + eo_do(scene, + evas_3d_scene_root_node_set(root_node), + evas_3d_scene_camera_node_set(camera_node), + evas_3d_scene_size_set(WIDTH, HEIGHT)); + + background = eo_add(EVAS_OBJ_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)); + + image = evas_object_image_filled_add(evas); + eo_do(image, + evas_obj_size_set(WIDTH, HEIGHT), + evas_obj_visibility_set(EINA_TRUE)); + evas_object_focus_set(image, EINA_TRUE); + eo_do(image, evas_obj_image_scene_set(scene)); + + evas_object_event_callback_add(image, EVAS_CALLBACK_KEY_DOWN, _on_key_down, root_node); + + ecore_timer_add(0.01, _animate_scene, mesh_node); + + ecore_main_loop_begin(); + + ecore_evas_free(ecore_evas); + ecore_evas_shutdown(); + + return 0; +} diff --git a/src/lib/evas/canvas/evas_3d_mesh.c b/src/lib/evas/canvas/evas_3d_mesh.c index b678c0034b..de59c808a7 100644 --- a/src/lib/evas/canvas/evas_3d_mesh.c +++ b/src/lib/evas/canvas/evas_3d_mesh.c @@ -41,7 +41,7 @@ evas_3d_mesh_frame_free(Evas_3D_Mesh_Frame *frame) free(frame); } -static Evas_3D_Mesh_Frame * +Evas_3D_Mesh_Frame * evas_3d_mesh_frame_find(Evas_3D_Mesh_Data *pd, int frame) { Eina_List *l; @@ -56,6 +56,47 @@ evas_3d_mesh_frame_find(Evas_3D_Mesh_Data *pd, int frame) return NULL; } +Eina_Bool +_aabb_add_to_frame(Evas_3D_Mesh_Data *pd, int frame, int stride) +{ + Evas_3D_Mesh_Frame *curframe = evas_3d_mesh_frame_find(pd, frame); + int i = 0, j = 0, step = 0, size = 0; + float vxmin, vymin, vzmin, vxmax, vymax, vzmax; + float *minmaxdata = NULL; + Evas_Box3 box3; + + step = curframe->vertices[EVAS_3D_VERTEX_POSITION].element_count; + size = curframe->vertices[EVAS_3D_VERTEX_POSITION].size; + minmaxdata = (float *)curframe->vertices[EVAS_3D_VERTEX_POSITION].data; + + if (!minmaxdata) + { + ERR("Invalid vertex data."); + return EINA_FALSE; + } + + vxmax = vxmin = minmaxdata[0]; + vymax = vymin = minmaxdata[1]; + vzmax = vzmin = minmaxdata[2]; + j += step; + + for (i = 1; i < size/stride; ++i) + { + vxmin > minmaxdata[j] ? vxmin = minmaxdata[j] : 0; + vxmax < minmaxdata[j] ? vxmax = minmaxdata[j] : 0; + vymin > minmaxdata[j + 1] ? vymin = minmaxdata[j + 1] : 0; + vymax < minmaxdata[j + 1] ? vymax = minmaxdata[j + 1] : 0; + vzmin > minmaxdata[j + 2] ? vzmin = minmaxdata[j + 2] : 0; + vzmax < minmaxdata[j + 2] ? vzmax = minmaxdata[j + 2] : 0; + j += step; + } + + evas_box3_empty_set(&box3); + evas_box3_set(&box3, vxmin, vymin, vzmin, vxmax, vymax, vzmax); + curframe->aabb = box3; + return EINA_TRUE; +} + static inline void _mesh_init(Evas_3D_Mesh_Data *pd) { @@ -331,7 +372,39 @@ _evas_3d_mesh_frame_vertex_data_set(Eo *obj, Evas_3D_Mesh_Data *pd, int frame, E if (attrib == EVAS_3D_VERTEX_POSITION) { + int i = 0, j = 0, size = stride/sizeof(float); + float vxmin, vymin, vzmin, vxmax, vymax, vzmax; + float *minmaxdata = (float *)data; + Evas_Box3 box3; + element_count = 3; + + if (minmaxdata) + { + vxmax = vxmin = minmaxdata[0]; + vymax = vymin = minmaxdata[1]; + vzmax = vzmin = minmaxdata[2]; + j += size; + + for (i = 1; i < size; ++i) + { + vxmin > minmaxdata[j] ? vxmin = minmaxdata[j] : 0; + vxmax < minmaxdata[j] ? vxmax = minmaxdata[j] : 0; + vymin > minmaxdata[j + 1] ? vymin = minmaxdata[j + 1] : 0; + vymax < minmaxdata[j + 1] ? vymax = minmaxdata[j + 1] : 0; + vzmin > minmaxdata[j + 2] ? vzmin = minmaxdata[j + 2] : 0; + vzmax < minmaxdata[j + 2] ? vzmax = minmaxdata[j + 2] : 0; + j += size; + } + + evas_box3_empty_set(&box3); + evas_box3_set(&box3, vxmin, vymin, vzmin, vxmax, vymax, vzmax); + f->aabb = box3; + } + else + { + ERR("Axis-Aligned Bounding Box wasn't added in frame %d ", frame); + } } else if (attrib == EVAS_3D_VERTEX_NORMAL) { @@ -491,6 +564,11 @@ _evas_3d_mesh_frame_vertex_data_copy_set(Eo *obj, Evas_3D_Mesh_Data *pd, int fra } } + if (attrib == EVAS_3D_VERTEX_POSITION && !_aabb_add_to_frame(pd, frame, stride)) + { + ERR("Axis-Aligned Bounding Box wasn't added in frame %d ", frame); + } + eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_MESH_VERTEX_DATA, NULL)); } diff --git a/src/lib/evas/canvas/evas_3d_mesh_loader_md2.c b/src/lib/evas/canvas/evas_3d_mesh_loader_md2.c index ffe1b3e4db..6c5a779b1c 100644 --- a/src/lib/evas/canvas/evas_3d_mesh_loader_md2.c +++ b/src/lib/evas/canvas/evas_3d_mesh_loader_md2.c @@ -350,6 +350,7 @@ evas_3d_mesh_file_md2_set(Evas_3D_Mesh *mesh, const char *file) float *pos, *nor, *tex; int stride_pos, stride_nor, stride_tex; float s_scale, t_scale; + Evas_3D_Mesh_Data *pd; /* Initialize MD2 loader (Open file and read MD2 head ant etc) */ if (!_md2_loader_init(&loader, file)) @@ -432,6 +433,13 @@ evas_3d_mesh_file_md2_set(Evas_3D_Mesh *mesh, const char *file) evas_3d_mesh_frame_vertex_data_unmap(f, EVAS_3D_VERTEX_POSITION), evas_3d_mesh_frame_vertex_data_unmap(f, EVAS_3D_VERTEX_NORMAL), evas_3d_mesh_frame_vertex_data_unmap(f, EVAS_3D_VERTEX_TEXCOORD)); + + pd = eo_data_scope_get(mesh, EVAS_3D_MESH_CLASS); + + if (!_aabb_add_to_frame(pd, f, stride_pos)) + { + ERR("Axis-Aligned Bounding Box wasn't added in frame %d ", f); + } } _md2_loader_fini(&loader); diff --git a/src/lib/evas/canvas/evas_3d_node.c b/src/lib/evas/canvas/evas_3d_node.c index 2ea36be399..14e6393525 100644 --- a/src/lib/evas/canvas/evas_3d_node.c +++ b/src/lib/evas/canvas/evas_3d_node.c @@ -4,6 +4,8 @@ #define MY_CLASS EVAS_3D_NODE_CLASS #define MY_CLASS_NAME "Evas_3D_Node" +Evas_3D_Mesh_Frame *evas_3d_mesh_frame_find(Evas_3D_Mesh_Data *pd, int frame); + static inline Evas_3D_Node_Mesh * _node_mesh_new(Evas_3D_Node *node, Evas_3D_Mesh *mesh) { @@ -199,8 +201,17 @@ static Eina_Bool _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED) { Evas_3D_Node_Data *pd = eo_data_scope_get(node, EVAS_3D_NODE_CLASS); - Eina_Bool transform_dirty = EINA_FALSE, mesh_geom_dirty = EINA_FALSE, - mesh_frame_dirty = EINA_FALSE, member_dirty = EINA_FALSE; + Eina_Bool transform_dirty = EINA_FALSE, mesh_geom_dirty = EINA_FALSE; + Eina_Bool mesh_frame_dirty = EINA_FALSE, member_dirty = EINA_FALSE; + Eina_Bool frame_found = EINA_FALSE, is_change_orientation = EINA_FALSE; + Eina_List *m, *l; + Evas_3D_Mesh *mesh; + int frame, count, size, i, j; + Evas_3D_Mesh_Frame *f; + float minx, miny, minz, maxx, maxy, maxz, vxmin, vymin, vzmin, vxmax, vymax, vzmax; + float *minmaxdata; + Evas_Vec4 orientation; + Evas_Box3 box3; eo_do(node, transform_dirty = evas_3d_object_dirty_get(EVAS_3D_STATE_NODE_TRANSFORM), @@ -213,21 +224,164 @@ _node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED) mesh_frame_dirty || member_dirty) { - Eina_List *l; - Evas_3D_Node *n; - - /* Update AABB of this node. */ - evas_box3_empty_set(&pd->aabb); - - EINA_LIST_FOREACH(pd->members, l, n) - { - Evas_3D_Node_Data *pdmember = eo_data_scope_get(n, EVAS_3D_NODE_CLASS); - evas_box3_union(&pd->aabb, &pd->aabb, &pdmember->aabb); - } - if (pd->type == EVAS_3D_NODE_TYPE_MESH) { - /* TODO: */ + + if (pd->orientation.x || pd->orientation.y || pd->orientation.z) + { + evas_vec4_set(&orientation, pd->orientation.x, pd->orientation.y, pd->orientation.z, pd->orientation.w); + is_change_orientation = EINA_TRUE; + } + + eo_do (node, m = evas_3d_node_mesh_list_get()); + + EINA_LIST_FOREACH(m, l, mesh) + { + eo_do(node, frame = evas_3d_node_mesh_frame_get(mesh)); + Evas_3D_Mesh_Data *mpd = eo_data_scope_get(mesh, EVAS_3D_MESH_CLASS); + f = evas_3d_mesh_frame_find(mpd, frame); + + if (f) + { + i = 0, j = 0; + + evas_box3_empty_set(&box3); + count = f->vertices[EVAS_3D_VERTEX_POSITION].element_count; + size = f->vertices[EVAS_3D_VERTEX_POSITION].size; + if (!size) size = count * sizeof(float) * mpd->vertex_count; + minmaxdata = (float *)malloc(size); + + if (!minmaxdata) + { + ERR("Not enough memory."); + return EINA_FALSE; + } + + memcpy(minmaxdata, f->vertices[EVAS_3D_VERTEX_POSITION].data, size); + + /*get current coordinates, set orientation and find min/max*/ + if (is_change_orientation) + { + Evas_Vec3 rotate; + evas_vec3_set(&rotate, minmaxdata[0], minmaxdata[1], minmaxdata[2]); + evas_vec3_quaternion_rotate(&rotate, &rotate, &orientation); + vxmax = vxmin = minmaxdata[0] = rotate.x; + vymax = vymin = minmaxdata[1] = rotate.y; + vzmax = vzmin = minmaxdata[2] = rotate.z; + } + else + { + vxmax = vxmin = minmaxdata[0]; + vymax = vymin = minmaxdata[1]; + vzmax = vzmin = minmaxdata[2]; + } + + j += count; + + if (is_change_orientation) + { + for (i = 1; i < mpd->vertex_count; ++i) + { + Evas_Vec3 rotate; + evas_vec3_set(&rotate, minmaxdata[j], minmaxdata[j + 1], minmaxdata[j + 2]); + evas_vec3_quaternion_rotate(&rotate, &rotate, &orientation); + minmaxdata[j] = rotate.x; + minmaxdata[j + 1] = rotate.y; + minmaxdata[j + 2] = rotate.z; + vxmin > minmaxdata[j] ? vxmin = minmaxdata[j] : 0; + vxmax < minmaxdata[j] ? vxmax = minmaxdata[j] : 0; + vymin > minmaxdata[j + 1] ? vymin = minmaxdata[j + 1] : 0; + vymax < minmaxdata[j + 1] ? vymax = minmaxdata[j + 1] : 0; + vzmin > minmaxdata[j + 2] ? vzmin = minmaxdata[j + 2] : 0; + vzmax < minmaxdata[j + 2] ? vzmax = minmaxdata[j + 2] : 0; + j += count; + } + } + else + { + for (i = 1; i < mpd->vertex_count; ++i) + { + vxmin > minmaxdata[j] ? vxmin = minmaxdata[j] : 0; + vxmax < minmaxdata[j] ? vxmax = minmaxdata[j] : 0; + vymin > minmaxdata[j + 1] ? vymin = minmaxdata[j + 1] : 0; + vymax < minmaxdata[j + 1] ? vymax = minmaxdata[j + 1] : 0; + vzmin > minmaxdata[j + 2] ? vzmin = minmaxdata[j + 2] : 0; + vzmax < minmaxdata[j + 2] ? vzmax = minmaxdata[j + 2] : 0; + j += count; + } + } + + if (!frame_found) + { + evas_box3_empty_set(&pd->aabb); + evas_box3_empty_set(&pd->obb); + minx = vxmin; + miny = vymin; + minz = vzmin; + maxx = vxmax; + maxy = vymax; + maxz = vzmax; + } + else + { + minx > vxmin ? minx = vxmin : 0; + maxx < vxmax ? maxx = vxmax : 0; + miny > vymin ? miny = vymin : 0; + maxy < vymax ? maxy = vymax : 0; + minz > vzmin ? minz = vzmin : 0; + maxz < vzmax ? maxz = vzmax : 0; + } + + frame_found = EINA_TRUE; + free(minmaxdata); + evas_box3_set(&box3, minx, miny, minz, maxx, maxy, maxz); + evas_box3_union(&pd->aabb, &pd->aabb, &box3); + evas_box3_union(&pd->obb, &pd->obb, &f->aabb); + } + } + + if (frame_found) + { + if (is_change_orientation) + { + evas_vec3_quaternion_rotate(&pd->obb.p0, &pd->obb.p0, &orientation); + evas_vec3_quaternion_rotate(&pd->obb.p1, &pd->obb.p1, &orientation); + } + if ((pd->scale.x != 1 || pd->scale.y != 1 || pd->scale.z != 1)) + { + Evas_Vec3 scale; + evas_vec3_set(&scale, pd->scale.x, pd->scale.y, pd->scale.z); + evas_vec3_multiply(&pd->obb.p0, &scale, &pd->obb.p0); + evas_vec3_multiply(&pd->obb.p1, &scale, &pd->obb.p1); + evas_vec3_multiply(&pd->aabb.p0, &scale, &pd->aabb.p0); + evas_vec3_multiply(&pd->aabb.p1, &scale, &pd->aabb.p1); + } + if ((pd->position.x || pd->position.y || pd->position.z)) + { + Evas_Vec3 position; + evas_vec3_set(&position, pd->position.x, pd->position.y, pd->position.z); + evas_vec3_add(&pd->obb.p0, &position, &pd->obb.p0); + evas_vec3_add(&pd->obb.p1, &position, &pd->obb.p1); + evas_vec3_add(&pd->aabb.p0, &position, &pd->aabb.p0); + evas_vec3_add(&pd->aabb.p1, &position, &pd->aabb.p1); + } + } + } + else + { + Eina_List *current; + Evas_3D_Node *data; + + /* Update AABB and OBB of this node. */ + evas_box3_empty_set(&pd->aabb); + evas_box3_empty_set(&pd->obb); + + EINA_LIST_FOREACH(pd->members, current, data) + { + Evas_3D_Node_Data *datapd = eo_data_scope_get(data, EVAS_3D_NODE_CLASS); + evas_box3_union(&pd->obb, &pd->obb, &datapd->obb); + evas_box3_union(&pd->aabb, &pd->aabb, &datapd->aabb); + } } } @@ -1213,4 +1367,15 @@ _evas_3d_node_mesh_frame_get(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_3D return nm->frame; } +EOLIAN static void +_evas_3d_node_bounding_box_get(Eo *obj EINA_UNUSED, Evas_3D_Node_Data *pd, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *x2, Evas_Real *y2, Evas_Real *z2) +{ + if (x) *x = pd->aabb.p0.x; + if (y) *y = pd->aabb.p0.y; + if (z) *z = pd->aabb.p0.z; + if (x2) *x2 = pd->aabb.p1.x; + if (y2) *y2 = pd->aabb.p1.y; + if (z2) *z2 = pd->aabb.p1.z; +} + #include "canvas/evas_3d_node.eo.c" diff --git a/src/lib/evas/canvas/evas_3d_node.eo b/src/lib/evas/canvas/evas_3d_node.eo index f09a15c734..3b8f8431bc 100644 --- a/src/lib/evas/canvas/evas_3d_node.eo +++ b/src/lib/evas/canvas/evas_3d_node.eo @@ -330,6 +330,30 @@ class Evas_3D_Node (Evas_3D_Object, Evas_Common_Interface) return const Eina_List *; } + bounding_box_get{ + /* + + * Get axis-aligned bounding box (AABB) of the given node. + * + * @param node The given node. + * @param x Pointer to receive X coordinate of the first point of AABB. + * @param y Pointer to receive Y coordinate of the first point of AABB. + * @param z Pointer to receive Z coordinate of the first point of AABB. + * @param x2 Pointer to receive X coordinate of the second point of AABB. + * @param y2 Pointer to receive Y coordinate of the second point of AABB. + * @param z2 Pointer to receive Z coordinate of the second point of AABB. + + @ingroup Evas_3D_Node + */ + params { + @in Evas_Real *x; /*@ Coordinates of vector.*/ + @in Evas_Real *y; + @in Evas_Real *z; + @in Evas_Real *x2; + @in Evas_Real *y2; + @in Evas_Real *z2; + } + } } properties { diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 0165d10068..453b52202d 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -136,6 +136,7 @@ struct _Evas_3D_Node Evas_Vec3 scale_world; Evas_Box3 aabb; + Evas_Box3 obb; Evas_3D_Node_Type type;