forked from enlightenment/efl
1694 lines
54 KiB
C
1694 lines
54 KiB
C
#include "evas_common_private.h"
|
|
#include "evas_private.h"
|
|
#include "evas_canvas3d_node_callback.h"
|
|
|
|
#define MY_CLASS EVAS_CANVAS3D_NODE_CLASS
|
|
#define MY_CLASS_NAME "Evas_Canvas3D_Node"
|
|
|
|
Evas_Canvas3D_Mesh_Frame *evas_canvas3d_mesh_frame_find(Evas_Canvas3D_Mesh_Data *pd, int frame);
|
|
|
|
static void
|
|
_look_at_set(Evas_Canvas3D_Node_Data *pd, Eina_Vector3 *target, Eina_Vector3 *up);
|
|
|
|
static Eina_Stringshare *
|
|
_generate_unic_color_key(Evas_Color *color, Evas_Color *bg_color, Evas_Canvas3D_Node *node, Evas_Canvas3D_Mesh *mesh,
|
|
Eina_Bool init)
|
|
{
|
|
static unsigned char red = 0;
|
|
static unsigned char green = 0;
|
|
static unsigned char blue = 0;
|
|
if (init) red = green = blue = 0;
|
|
|
|
#define GET_NEXT_COLOR \
|
|
red++; \
|
|
if (red == 255) \
|
|
{ \
|
|
red = 0; \
|
|
green++; \
|
|
if (green == 255) \
|
|
{ \
|
|
green = 0; \
|
|
blue++; \
|
|
} \
|
|
}
|
|
|
|
GET_NEXT_COLOR
|
|
/*Get another color if color equal with background color*/
|
|
if ((EINA_DBL_EQ(bg_color->r, (double)red)) &&
|
|
(EINA_DBL_EQ(bg_color->g, (double)green)) &&
|
|
(EINA_DBL_EQ(bg_color->b, (double)blue)))
|
|
{
|
|
GET_NEXT_COLOR
|
|
}
|
|
|
|
color->r = (double)red / 255;
|
|
color->g = (double)green / 255;
|
|
color->b = (double)blue / 255;
|
|
|
|
#undef GET_NEXT_COLOR
|
|
|
|
return eina_stringshare_printf("%p %p", node, mesh);
|
|
}
|
|
|
|
static void
|
|
_evas_canvas3d_node_private_callback_collision(void *data, const Efl_Event *event)
|
|
{
|
|
Eina_List *collision_list = NULL, *l = NULL;
|
|
Evas_Canvas3D_Node *target_node = NULL, *n = NULL;
|
|
Evas_Canvas3D_Node_Data *pd_target = NULL, *pd = NULL;
|
|
const Efl_Event_Description *eo_desc = NULL;
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
target_node = (Evas_Canvas3D_Node *)event->info;
|
|
pd_target = efl_data_scope_get(target_node, EVAS_CANVAS3D_NODE_CLASS);
|
|
collision_list = (Eina_List *)data;
|
|
eo_desc = efl_object_legacy_only_event_description_get("collision");
|
|
|
|
if (collision_list)
|
|
{
|
|
EINA_LIST_FOREACH(collision_list, l, n)
|
|
{
|
|
pd = efl_data_scope_get(n, EVAS_CANVAS3D_NODE_CLASS);
|
|
if (box_intersection_box(&pd_target->aabb, &pd->aabb))
|
|
ret = efl_event_callback_legacy_call(target_node, eo_desc, n);
|
|
}
|
|
if (!ret)
|
|
{
|
|
/* XXX: Putting it like this because that's how the logic was,
|
|
* but it seems absolutely wrong that it only checks the last
|
|
* and decides based on that. */
|
|
efl_event_callback_stop(event->object);
|
|
}
|
|
}
|
|
}
|
|
static void
|
|
_evas_canvas3d_node_private_callback_clicked(void *data EINA_UNUSED, const Efl_Event *event)
|
|
{
|
|
Eina_Bool ret = EINA_FALSE;
|
|
const Efl_Event_Description *eo_desc = efl_object_legacy_only_event_description_get("clicked");
|
|
ret = efl_event_callback_legacy_call((Eo *)event->info, eo_desc, event->info);
|
|
|
|
if (!ret)
|
|
efl_event_callback_stop(event->object);
|
|
}
|
|
|
|
static inline Evas_Canvas3D_Node_Mesh *
|
|
_node_mesh_new(Evas_Canvas3D_Node *node, Evas_Canvas3D_Mesh *mesh)
|
|
{
|
|
Evas_Canvas3D_Node_Mesh *nm = (Evas_Canvas3D_Node_Mesh *)malloc(sizeof(Evas_Canvas3D_Node_Mesh));
|
|
|
|
if (nm == NULL)
|
|
{
|
|
ERR("Failed to allocate memory.");
|
|
return NULL;
|
|
}
|
|
|
|
nm->node = node;
|
|
nm->mesh = mesh;
|
|
nm->frame = 0;
|
|
|
|
return nm;
|
|
}
|
|
|
|
static inline void
|
|
_node_mesh_free(Evas_Canvas3D_Node_Mesh *nm)
|
|
{
|
|
free(nm);
|
|
}
|
|
|
|
static void
|
|
_node_mesh_free_func(void *data)
|
|
{
|
|
_node_mesh_free((Evas_Canvas3D_Node_Mesh *)data);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_node_scene_root_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
|
|
void *data EINA_UNUSED, void *fdata)
|
|
{
|
|
Evas_Canvas3D_Scene *s = *(Evas_Canvas3D_Scene **)key;
|
|
evas_canvas3d_object_change(s, EVAS_CANVAS3D_STATE_SCENE_ROOT_NODE, (Evas_Canvas3D_Object *)fdata);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_node_scene_camera_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
|
|
void *data EINA_UNUSED, void *fdata)
|
|
{
|
|
Evas_Canvas3D_Scene *s = *(Evas_Canvas3D_Scene **)key;
|
|
evas_canvas3d_object_change(s, EVAS_CANVAS3D_STATE_SCENE_CAMERA_NODE, (Evas_Canvas3D_Object *)fdata);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_evas_canvas3d_object_change_notify(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_State state EINA_UNUSED , Evas_Canvas3D_Object *ref EINA_UNUSED)
|
|
{
|
|
Eina_List *l;
|
|
Evas_Canvas3D_Node *n;
|
|
Eina_Bool orientation;
|
|
Eina_Bool position;
|
|
Eina_Bool scale;
|
|
Eina_Bool parent_change;
|
|
|
|
/* Notify all scenes using this node that it has changed. */
|
|
if (pd->scenes_root)
|
|
eina_hash_foreach(pd->scenes_root, _node_scene_root_change_notify, obj);
|
|
|
|
if (pd->scenes_camera)
|
|
eina_hash_foreach(pd->scenes_camera, _node_scene_camera_change_notify, obj);
|
|
|
|
parent_change = (state == EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION)
|
|
|| (state == EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION)
|
|
|| (state == EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE);
|
|
|
|
/* Notify parent that a member has changed. */
|
|
if (pd->parent && !parent_change)
|
|
{
|
|
evas_canvas3d_object_change(pd->parent, EVAS_CANVAS3D_STATE_NODE_MEMBER, obj);
|
|
}
|
|
|
|
orientation = (state == EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION)
|
|
|| (state == EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION);
|
|
position = (state == EVAS_CANVAS3D_STATE_NODE_TRANSFORM_POSITION)
|
|
|| (state == EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION);
|
|
scale = (state == EVAS_CANVAS3D_STATE_NODE_TRANSFORM_SCALE)
|
|
|| (state == EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE);
|
|
|
|
/* Notify members that the parent has changed. */
|
|
if (scale)
|
|
EINA_LIST_FOREACH(pd->members, l, n)
|
|
{
|
|
evas_canvas3d_object_change(n, EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE, obj);
|
|
}
|
|
if (orientation && !(pd->billboard_target))
|
|
EINA_LIST_FOREACH(pd->members, l, n)
|
|
{
|
|
/*Skip change orientation if node is billboard*/
|
|
Evas_Canvas3D_Node_Data *pdm = efl_data_scope_get(n, EVAS_CANVAS3D_NODE_CLASS);
|
|
if (pdm->billboard_target)
|
|
continue;
|
|
evas_canvas3d_object_change(n, EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION, obj);
|
|
}
|
|
if (position)
|
|
EINA_LIST_FOREACH(pd->members, l, n)
|
|
{
|
|
evas_canvas3d_object_change(n, EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION, obj);
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_evas_canvas3d_object_callback_register(Eo *obj, Evas_Canvas3D_Node_Data *pd EINA_UNUSED,
|
|
const char *event, const void *data)
|
|
{
|
|
Evas_Canvas3D_Node_Private_Callback_Type tcb;
|
|
|
|
GET_CALLBACK_TYPE(tcb, event)
|
|
|
|
if (tcb != PRIVATE_CALLBACK_NONE)
|
|
efl_event_callback_add(obj, &evas_canvas3d_node_private_event_desc[tcb], evas_canvas3d_node_private_callback_functions[tcb], data);
|
|
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_evas_canvas3d_object_callback_unregister(Eo *obj, Evas_Canvas3D_Node_Data *pd EINA_UNUSED,
|
|
const char *event)
|
|
{
|
|
Evas_Canvas3D_Node_Private_Callback_Type tcb;
|
|
|
|
GET_CALLBACK_TYPE(tcb, event)
|
|
|
|
if (tcb != PRIVATE_CALLBACK_NONE)
|
|
efl_event_callback_del(obj, &evas_canvas3d_node_private_event_desc[tcb], evas_canvas3d_node_private_callback_functions[tcb], NULL);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_node_transform_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
Eina_Bool transform_dirty = EINA_FALSE, parent_dirty = EINA_FALSE;
|
|
|
|
transform_dirty = evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION);
|
|
transform_dirty|= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_POSITION);
|
|
transform_dirty|= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_SCALE);
|
|
parent_dirty = evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION);
|
|
parent_dirty |= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION);
|
|
parent_dirty |= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE);
|
|
|
|
if (transform_dirty || parent_dirty)
|
|
{
|
|
if (pd->parent)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pdparent = efl_data_scope_get(pd->parent, MY_CLASS);
|
|
const Eina_Vector3 *scale_parent = &pdparent->scale_world;
|
|
const Eina_Quaternion *orientation_parent = &pdparent->orientation_world;
|
|
|
|
/* Orienatation */
|
|
if (pd->orientation_inherit)
|
|
{
|
|
eina_quaternion_mul(&pd->orientation_world,
|
|
orientation_parent, &pd->orientation);
|
|
}
|
|
else
|
|
{
|
|
pd->orientation_world = pd->orientation;
|
|
}
|
|
|
|
/* Scale */
|
|
if (pd->scale_inherit)
|
|
eina_vector3_multiply(&pd->scale_world, scale_parent, &pd->scale);
|
|
else
|
|
pd->scale_world = pd->scale;
|
|
|
|
/* Position */
|
|
if (pd->position_inherit)
|
|
{
|
|
eina_vector3_multiply(&pd->position_world, &pd->position, scale_parent);
|
|
eina_vector3_quaternion_rotate(&pd->position_world, &pd->position_world,
|
|
orientation_parent);
|
|
eina_vector3_add(&pd->position_world, &pd->position_world,
|
|
&pdparent->position_world);
|
|
}
|
|
else
|
|
{
|
|
pd->position_world = pd->position;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pd->position_world = pd->position;
|
|
pd->orientation_world = pd->orientation;
|
|
pd->scale_world = pd->scale;
|
|
}
|
|
|
|
if (pd->type == EVAS_CANVAS3D_NODE_TYPE_CAMERA)
|
|
{
|
|
evas_mat4_inverse_build(&pd->data.camera.matrix_world_to_eye,
|
|
&pd->position_world, &pd->orientation_world,
|
|
&pd->scale_world);
|
|
}
|
|
else if (pd->type == EVAS_CANVAS3D_NODE_TYPE_LIGHT)
|
|
{
|
|
}
|
|
else if (pd->type == EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
evas_mat4_build(&pd->data.mesh.matrix_local_to_world,
|
|
&pd->position_world, &pd->orientation_world, &pd->scale_world);
|
|
}
|
|
/*
|
|
if (pd->parent)
|
|
{
|
|
evas_mat4_nocheck_multiply(&pd->matrix_local_to_world,
|
|
&pd->parent->matrix_local_to_world,
|
|
&pd->matrix_local_to_parent);
|
|
}
|
|
else
|
|
{
|
|
evas_mat4_copy(&pd->matrix_local_to_world, &pd->matrix_local_to_parent);
|
|
}*/
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_node_billboard_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED)
|
|
{
|
|
Eina_Vector3 target;
|
|
Eina_Vector3 up;
|
|
Evas_Canvas3D_Node_Data *pd_node = efl_data_scope_get(node, MY_CLASS);
|
|
if (pd_node->billboard_target)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pd_target = efl_data_scope_get(pd_node->billboard_target,
|
|
MY_CLASS);
|
|
eina_vector3_set(&target, pd_target->position.x, pd_target->position.y,
|
|
pd_target->position.z);
|
|
eina_vector3_set(&up, 0, 1, 0);
|
|
|
|
_look_at_set(pd_node, &target, &up);
|
|
|
|
if (pd_node->type == EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
evas_mat4_build(&pd_node->data.mesh.matrix_local_to_world,
|
|
&pd_node->position, &pd_node->orientation,
|
|
&pd_node->scale);
|
|
}
|
|
else if (pd_node->type == EVAS_CANVAS3D_NODE_TYPE_LIGHT)
|
|
{
|
|
evas_mat4_build(&pd_node->data.light.matrix_local_to_world,
|
|
&pd_node->position, &pd_node->orientation,
|
|
&pd_node->scale);
|
|
}
|
|
else if (pd_node->type == EVAS_CANVAS3D_NODE_TYPE_CAMERA)
|
|
{
|
|
evas_mat4_inverse_build(&pd_node->data.light.matrix_local_to_world,
|
|
&pd_node->position, &pd_node->orientation,
|
|
&pd_node->scale);
|
|
}
|
|
else
|
|
ERR("Not supported type of node: line %d in file %s", __LINE__ , __FILE__);
|
|
}
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_node_item_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, EVAS_CANVAS3D_NODE_CLASS);
|
|
if (pd->type == EVAS_CANVAS3D_NODE_TYPE_CAMERA)
|
|
{
|
|
if (pd->data.camera.camera)
|
|
{
|
|
evas_canvas3d_object_update(pd->data.camera.camera);
|
|
}
|
|
}
|
|
else if (pd->type == EVAS_CANVAS3D_NODE_TYPE_LIGHT)
|
|
{
|
|
if (pd->data.light.light)
|
|
{
|
|
evas_canvas3d_object_update(pd->data.light.light);
|
|
}
|
|
}
|
|
else if (pd->type == EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
Eina_List *l;
|
|
Evas_Canvas3D_Mesh *m;
|
|
EINA_LIST_FOREACH(pd->data.mesh.meshes, l, m)
|
|
{
|
|
evas_canvas3d_object_update(m);
|
|
}
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_pack_meshes_vertex_data(Evas_Canvas3D_Node *node, Eina_Vector3 **vertices, int *count)
|
|
{
|
|
const Eina_List *m, *l;
|
|
Evas_Canvas3D_Mesh *mesh;
|
|
int j;
|
|
int frame;
|
|
Eina_Vector3 *it;
|
|
Evas_Canvas3D_Vertex_Buffer pos0, pos1;
|
|
Evas_Real pos_weight;
|
|
|
|
*count = 0;
|
|
m = (Eina_List *)evas_canvas3d_node_mesh_list_get(node);
|
|
EINA_LIST_FOREACH(m, l, mesh)
|
|
{
|
|
frame = evas_canvas3d_node_mesh_frame_get(node, mesh);
|
|
evas_canvas3d_mesh_interpolate_vertex_buffer_get(mesh, frame, EVAS_CANVAS3D_VERTEX_ATTRIB_POSITION,
|
|
&pos0, &pos1, &pos_weight);
|
|
if(!pos0.data) continue;
|
|
if(!pos0.stride)
|
|
{
|
|
*count += pos0.size / (sizeof(float) * 3);
|
|
}
|
|
else
|
|
{
|
|
*count += pos0.size / pos0.stride;
|
|
}
|
|
}
|
|
*vertices = (Eina_Vector3*)malloc(*count * sizeof(Eina_Vector3));
|
|
it = *vertices;
|
|
if(!*vertices)
|
|
{
|
|
ERR("Not enough memory.");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FOREACH(m, l, mesh)
|
|
{
|
|
frame = evas_canvas3d_node_mesh_frame_get(node, mesh);
|
|
evas_canvas3d_mesh_interpolate_vertex_buffer_get(mesh, frame, EVAS_CANVAS3D_VERTEX_ATTRIB_POSITION,
|
|
&pos0, &pos1, &pos_weight);
|
|
if(!pos0.data) continue;
|
|
int stride = 0;
|
|
if(!pos0.stride)
|
|
{
|
|
stride = sizeof(float) * 3;
|
|
}
|
|
else
|
|
{
|
|
stride = pos0.stride;
|
|
}
|
|
for (j = 0; j < pos0.size / stride; j++)
|
|
{
|
|
evas_canvas3d_mesh_interpolate_position_get(it, &pos0, &pos1, pos_weight, j);
|
|
it++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_update_node_shapes(Evas_Canvas3D_Node *node)
|
|
{
|
|
int i;
|
|
int count;
|
|
Eina_Vector3 *vertices = NULL;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, EVAS_CANVAS3D_NODE_CLASS);
|
|
Eina_Bool transform_orientation_dirty;
|
|
Eina_Bool transform_position_dirty;
|
|
Eina_Bool transform_scale_dirty;
|
|
Eina_Bool mesh_geom_dirty;
|
|
Eina_Vector3 position = pd->position_world;
|
|
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
pd->aabb.p0 = position;
|
|
pd->aabb.p1 = position;
|
|
pd->obb.p0 = position;
|
|
pd->obb.p1 = position;
|
|
pd->bsphere.radius = 0;
|
|
pd->bsphere.center = position;
|
|
return;
|
|
}
|
|
|
|
transform_orientation_dirty = evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION);
|
|
transform_orientation_dirty |= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION);
|
|
transform_position_dirty = evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_POSITION);
|
|
transform_position_dirty |= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION);
|
|
transform_scale_dirty = evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_SCALE);
|
|
transform_scale_dirty |= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE);
|
|
mesh_geom_dirty = evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_MESH_GEOMETRY);
|
|
mesh_geom_dirty |= evas_canvas3d_object_dirty_get(node, EVAS_CANVAS3D_STATE_NODE_MESH_FRAME);
|
|
|
|
|
|
_pack_meshes_vertex_data(node, &vertices, &count);
|
|
if (count > 0)
|
|
{
|
|
calculate_box(&pd->obb, count, vertices);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
eina_vector3_homogeneous_position_transform(&vertices[i], &pd->data.mesh.matrix_local_to_world, &vertices[i]);
|
|
}
|
|
calculate_box(&pd->aabb, count, vertices);
|
|
if (transform_position_dirty || transform_scale_dirty || mesh_geom_dirty)
|
|
{
|
|
calculate_sphere(&pd->bsphere, count, vertices);
|
|
}
|
|
eina_vector3_homogeneous_position_transform(&pd->obb.p0, &pd->data.mesh.matrix_local_to_world, &pd->obb.p0);
|
|
eina_vector3_homogeneous_position_transform(&pd->obb.p0, &pd->data.mesh.matrix_local_to_world, &pd->obb.p0);
|
|
}
|
|
free(vertices);
|
|
|
|
}
|
|
|
|
Eina_Bool
|
|
node_aabb_update(Evas_Canvas3D_Node *node, void *data EINA_UNUSED)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, EVAS_CANVAS3D_NODE_CLASS);
|
|
Eina_List *current;
|
|
Evas_Canvas3D_Node *datanode;
|
|
const Efl_Event_Description *eo_desc = NULL;
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_MESH &&
|
|
pd->type != EVAS_CANVAS3D_NODE_TYPE_NODE)
|
|
return EINA_TRUE;
|
|
_update_node_shapes(node);
|
|
EINA_LIST_FOREACH(pd->members, current, datanode)
|
|
{
|
|
Evas_Canvas3D_Node_Data *datapd = efl_data_scope_get(datanode, EVAS_CANVAS3D_NODE_CLASS);
|
|
evas_box3_union(&pd->obb, &pd->obb, &datapd->obb);
|
|
evas_box3_union(&pd->aabb, &pd->aabb, &datapd->aabb);
|
|
}
|
|
|
|
evas_build_sphere(&pd->aabb, &pd->bsphere);
|
|
eo_desc = efl_object_legacy_only_event_description_get("collision,private");
|
|
efl_event_callback_legacy_call(node, eo_desc, (void *)node);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_node_update_done(Evas_Canvas3D_Node *obj, void *data EINA_UNUSED)
|
|
{
|
|
//@FIXME
|
|
Evas_Canvas3D_Object_Data *pdobject = efl_data_scope_get(obj, EVAS_CANVAS3D_OBJECT_CLASS);
|
|
memset(&pdobject->dirty[0], 0x00, sizeof(Eina_Bool) * EVAS_CANVAS3D_STATE_MAX);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_evas_canvas3d_object_update_notify(Eo *obj, Evas_Canvas3D_Node_Data *pd EINA_UNUSED)
|
|
{
|
|
/* Update transform. */
|
|
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_FALSE,
|
|
_node_transform_update, NULL);
|
|
/*Update billboard*/
|
|
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_ANY_ORDER, EINA_FALSE,
|
|
_node_billboard_update, NULL);
|
|
/* Update AABB. */
|
|
if(efl_object_legacy_only_event_description_get("collision,private"))
|
|
{
|
|
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_POST_ORDER, EINA_FALSE,
|
|
node_aabb_update, NULL);
|
|
}
|
|
|
|
/* Update node item. */
|
|
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_ANY_ORDER, EINA_FALSE,
|
|
_node_item_update, NULL);
|
|
|
|
/* Mark all nodes in the tree as up-to-date. */
|
|
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_ANY_ORDER, EINA_FALSE,
|
|
_node_update_done, NULL);
|
|
}
|
|
|
|
static void
|
|
_node_free(Evas_Canvas3D_Object *obj)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(obj, MY_CLASS);
|
|
|
|
if (pd->members)
|
|
{
|
|
Eina_List *l;
|
|
Evas_Canvas3D_Node *n;
|
|
|
|
EINA_LIST_FOREACH(pd->members, l, n)
|
|
{
|
|
efl_unref(n);
|
|
}
|
|
|
|
eina_list_free(pd->members);
|
|
}
|
|
|
|
if (pd->parent)
|
|
{
|
|
evas_canvas3d_node_member_del(pd->parent, obj);
|
|
}
|
|
|
|
if (pd->type == EVAS_CANVAS3D_NODE_TYPE_MESH && pd->data.mesh.meshes)
|
|
{
|
|
Eina_List *l;
|
|
Evas_Canvas3D_Mesh *m;
|
|
|
|
EINA_LIST_FOREACH(pd->data.mesh.meshes, l, m)
|
|
{
|
|
efl_unref(m);
|
|
}
|
|
|
|
eina_list_free(pd->data.mesh.meshes);
|
|
|
|
if (pd->data.mesh.node_meshes)
|
|
eina_hash_free(pd->data.mesh.node_meshes);
|
|
}
|
|
|
|
if (pd->scenes_root)
|
|
eina_hash_free(pd->scenes_root);
|
|
|
|
if (pd->scenes_camera)
|
|
eina_hash_free(pd->scenes_camera);
|
|
}
|
|
|
|
void
|
|
evas_canvas3d_node_scene_root_add(Evas_Canvas3D_Node *node, Evas_Canvas3D_Scene *scene)
|
|
{
|
|
int count = 0;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
if (pd->scenes_root == NULL)
|
|
{
|
|
pd->scenes_root = eina_hash_pointer_new(NULL);
|
|
|
|
if (pd->scenes_root == NULL)
|
|
{
|
|
ERR("Failed to create hash table.");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
count = (int)(uintptr_t)eina_hash_find(pd->scenes_root, &scene);
|
|
|
|
eina_hash_set(pd->scenes_root, &scene, (const void *)(uintptr_t)(count + 1));
|
|
}
|
|
|
|
void
|
|
evas_canvas3d_node_scene_root_del(Evas_Canvas3D_Node *node, Evas_Canvas3D_Scene *scene)
|
|
{
|
|
int count = 0;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
if (pd->scenes_root == NULL)
|
|
{
|
|
ERR("No scene to delete.");
|
|
return;
|
|
}
|
|
|
|
count = (int)(uintptr_t)eina_hash_find(pd->scenes_root, &scene);
|
|
|
|
if (count == 1)
|
|
eina_hash_del(pd->scenes_root, &scene, NULL);
|
|
else
|
|
eina_hash_set(pd->scenes_root, &scene, (const void *)(uintptr_t)(count - 1));
|
|
}
|
|
|
|
EOLIAN static Eina_Hash*
|
|
_evas_canvas3d_node_scene_root_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->scenes_root;
|
|
}
|
|
|
|
void
|
|
evas_canvas3d_node_scene_camera_add(Evas_Canvas3D_Node *node, Evas_Canvas3D_Scene *scene)
|
|
{
|
|
int count = 0;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
if (pd->scenes_camera == NULL)
|
|
{
|
|
pd->scenes_camera = eina_hash_pointer_new(NULL);
|
|
|
|
if (pd->scenes_camera == NULL)
|
|
{
|
|
ERR("Failed to create hash table.");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
count = (int)(uintptr_t)eina_hash_find(pd->scenes_camera, &scene);
|
|
|
|
eina_hash_set(pd->scenes_camera, &scene, (const void *)(uintptr_t)(count + 1));
|
|
}
|
|
|
|
void
|
|
evas_canvas3d_node_scene_camera_del(Evas_Canvas3D_Node *node, Evas_Canvas3D_Scene *scene)
|
|
{
|
|
int count = 0;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
if (pd->scenes_camera == NULL)
|
|
{
|
|
ERR("No scene to delete.");
|
|
return;
|
|
}
|
|
|
|
count = (int)(uintptr_t)eina_hash_find(pd->scenes_camera, &scene);
|
|
|
|
if (count == 1)
|
|
eina_hash_del(pd->scenes_camera, &scene, NULL);
|
|
else
|
|
eina_hash_set(pd->scenes_camera, &scene, (const void *)(uintptr_t)(count - 1));
|
|
}
|
|
|
|
void
|
|
evas_canvas3d_node_traverse(Evas_Canvas3D_Node *from, Evas_Canvas3D_Node *to, Evas_Canvas3D_Node_Traverse_Type type,
|
|
Eina_Bool skip, Evas_Canvas3D_Node_Func func, void *data)
|
|
{
|
|
Eina_List *nodes = NULL, *n;
|
|
Evas_Canvas3D_Node *node = NULL;
|
|
|
|
if (from == NULL || func == NULL)
|
|
goto error;
|
|
|
|
if (type == EVAS_CANVAS3D_NODE_TRAVERSE_DOWNWARD)
|
|
{
|
|
if (to == NULL)
|
|
goto error;
|
|
|
|
node = to;
|
|
|
|
do {
|
|
nodes = eina_list_prepend(nodes, (const void *)node);
|
|
|
|
if (node == from)
|
|
break;
|
|
Evas_Canvas3D_Node_Data *pdnode = efl_data_scope_get(node, MY_CLASS);
|
|
node = pdnode->parent;
|
|
|
|
if (node == NULL)
|
|
goto error;
|
|
} while (1);
|
|
}
|
|
else if (type == EVAS_CANVAS3D_NODE_TRAVERSE_UPWARD)
|
|
{
|
|
node = from;
|
|
|
|
do {
|
|
nodes = eina_list_append(nodes, (const void *)node);
|
|
|
|
if (node == to)
|
|
break;
|
|
Evas_Canvas3D_Node_Data *pdnode = efl_data_scope_get(node, MY_CLASS);
|
|
node = pdnode->parent;
|
|
|
|
if (node == NULL)
|
|
{
|
|
if (to == NULL)
|
|
break;
|
|
|
|
goto error;
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
EINA_LIST_FOREACH(nodes, n, node)
|
|
{
|
|
if (!func(node, data) && skip)
|
|
break;
|
|
}
|
|
|
|
eina_list_free(nodes);
|
|
return;
|
|
|
|
error:
|
|
ERR("Node traverse error.");
|
|
|
|
if (nodes)
|
|
eina_list_free(nodes);
|
|
}
|
|
|
|
void
|
|
evas_canvas3d_node_tree_traverse(Evas_Canvas3D_Node *root, Evas_Canvas3D_Tree_Traverse_Type type,
|
|
Eina_Bool skip, Evas_Canvas3D_Node_Func func, void *data)
|
|
{
|
|
Eina_List *nodes = NULL, *l;
|
|
Evas_Canvas3D_Node *node = NULL, *n, *last;
|
|
|
|
if (root == NULL || func == NULL)
|
|
return;
|
|
|
|
if (type == EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER)
|
|
{
|
|
/* Put the root node in the queue. */
|
|
nodes = eina_list_append(nodes, root);
|
|
|
|
while (eina_list_count(nodes) > 0)
|
|
{
|
|
/* Dequeue a node. */
|
|
node = eina_list_data_get(nodes);
|
|
Evas_Canvas3D_Node_Data *pdnode = efl_data_scope_get(node, MY_CLASS);
|
|
|
|
nodes = eina_list_remove_list(nodes, nodes);
|
|
|
|
/* Call node function on the node. */
|
|
if (func(node, data) || !skip)
|
|
{
|
|
/* Enqueue member nodes. */
|
|
EINA_LIST_FOREACH(pdnode->members, l, n)
|
|
{
|
|
nodes = eina_list_append(nodes, n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (type == EVAS_CANVAS3D_TREE_TRAVERSE_PRE_ORDER)
|
|
{
|
|
/* Put the root node in the stack. */
|
|
nodes = eina_list_append(nodes, root);
|
|
|
|
while (eina_list_count(nodes) > 0)
|
|
{
|
|
/* Pop a node from the stack. */
|
|
node = eina_list_data_get(nodes);
|
|
Evas_Canvas3D_Node_Data *pdnode = efl_data_scope_get(node, MY_CLASS);
|
|
nodes = eina_list_remove_list(nodes, nodes);
|
|
|
|
/* Call node function on the node. */
|
|
if (func(node, data) || !skip)
|
|
{
|
|
/* Push member nodes into the stack. */
|
|
EINA_LIST_REVERSE_FOREACH(pdnode->members, l, n)
|
|
{
|
|
nodes = eina_list_prepend(nodes, n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (type == EVAS_CANVAS3D_TREE_TRAVERSE_POST_ORDER)
|
|
{
|
|
if (skip)
|
|
{
|
|
ERR("Using skip with post order traversal has no effect.");
|
|
return;
|
|
}
|
|
|
|
/* Put the root node in the stack. */
|
|
nodes = eina_list_append(nodes, root);
|
|
last = NULL;
|
|
|
|
while (eina_list_count(nodes) > 0)
|
|
{
|
|
/* Peek a node from the stack. */
|
|
node = eina_list_data_get(nodes);
|
|
Evas_Canvas3D_Node_Data *pdnode = efl_data_scope_get(node, MY_CLASS);
|
|
if (eina_list_count(pdnode->members) == 0)
|
|
{
|
|
/* The peeked node is a leaf node,
|
|
* so visit it and pop from the stack. */
|
|
func(node, data);
|
|
nodes = eina_list_remove_list(nodes, nodes);
|
|
|
|
/* Save the last visited node. */
|
|
last = node;
|
|
}
|
|
else
|
|
{
|
|
/* If the peeked node is not a leaf node,
|
|
* there can be only two possible cases.
|
|
*
|
|
* 1. the parent of the last visited node.
|
|
* 2. a sibling of the last visited node.
|
|
*
|
|
* If the last visited node is a direct child of the peeked node,
|
|
* we have no unvisted child nodes for the peeked node, so we have to visit
|
|
* the peeked node and pop from the stack.
|
|
*
|
|
* Otherwise it should be a sibling of the peeked node, so we have to push
|
|
* its childs into the stack. */
|
|
Evas_Canvas3D_Node_Data *pdlast;
|
|
if (last )
|
|
pdlast= efl_data_scope_get(last, MY_CLASS);
|
|
if (last && pdlast->parent == node)
|
|
{
|
|
/* Visit the node as it doesn't have any unvisited child node. */
|
|
func(node, data);
|
|
nodes = eina_list_remove_list(nodes, nodes);
|
|
|
|
/* Save the last visited node. */
|
|
last = node;
|
|
}
|
|
else
|
|
{
|
|
/* Push child nodes into the stack. */
|
|
EINA_LIST_REVERSE_FOREACH(pdnode->members, l, n)
|
|
{
|
|
nodes = eina_list_prepend(nodes, n);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nodes != NULL)
|
|
eina_list_free(nodes);
|
|
}
|
|
|
|
Eina_Bool
|
|
_node_is_visible(Evas_Canvas3D_Node *node EINA_UNUSED, Evas_Canvas3D_Node *camera_node EINA_UNUSED)
|
|
{
|
|
/* TODO: */
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
Eina_Bool
|
|
evas_canvas3d_node_mesh_collect(Evas_Canvas3D_Node *node, void *data)
|
|
{
|
|
Eina_List *list_meshes, *l;
|
|
Evas_Canvas3D_Mesh *mesh = NULL;
|
|
Evas_Canvas3D_Mesh_Data *mesh_pd;
|
|
Evas_Canvas3D_Mesh_Frame *f;
|
|
Evas_Canvas3D_Scene_Public_Data *scene_data = (Evas_Canvas3D_Scene_Public_Data *)data;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
unsigned short int *index;
|
|
int stride, tex_stride, normal_stride;
|
|
|
|
if (pd->type == EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
scene_data->mesh_nodes = eina_list_append(scene_data->mesh_nodes, node);
|
|
/*In case LOD calculate distance to the camera node*/
|
|
if (pd->lod)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pd_camera = efl_data_scope_get(scene_data->camera_node, MY_CLASS);
|
|
scene_data->lod_distance = eina_vector3_distance_get(&pd_camera->position, &pd->position_world);
|
|
}
|
|
/* calculation of tangent space for all meshes */
|
|
list_meshes = (Eina_List *)evas_canvas3d_node_mesh_list_get(node);
|
|
EINA_LIST_FOREACH(list_meshes, l, mesh)
|
|
{
|
|
mesh_pd = efl_data_scope_get(mesh, MY_CLASS);
|
|
f = evas_canvas3d_mesh_frame_find(mesh_pd, 0);
|
|
if (!f)
|
|
{
|
|
ERR("Not existing mesh frame.");
|
|
continue;
|
|
}
|
|
|
|
float *tangent_data = (float *)f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_TANGENT].data;
|
|
if (!tangent_data && ((mesh_pd->shader_mode == EVAS_CANVAS3D_SHADER_MODE_NORMAL_MAP) ||
|
|
(mesh_pd->shader_mode == EVAS_CANVAS3D_SHADER_MODE_PARALLAX_OCCLUSION)))
|
|
{
|
|
index = (unsigned short int *)mesh_pd->indices;
|
|
tangent_data = (float*) malloc((3 * mesh_pd->vertex_count) * sizeof(float));
|
|
|
|
float *vertex_data = (float *)f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_POSITION].data;
|
|
if (f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_POSITION].stride != 0)
|
|
stride = f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_POSITION].stride / sizeof(float);
|
|
else
|
|
stride = 3;
|
|
|
|
float *tex_data = (float *)f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_TEXCOORD].data;
|
|
if (f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_TEXCOORD].stride != 0)
|
|
tex_stride = f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_TEXCOORD].stride / sizeof(float);
|
|
else
|
|
tex_stride = 2;
|
|
|
|
float *normal_data = (float *)f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_NORMAL].data;
|
|
if (f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_NORMAL].stride != 0)
|
|
normal_stride = f->vertices[EVAS_CANVAS3D_VERTEX_ATTRIB_NORMAL].stride / sizeof(float);
|
|
else
|
|
normal_stride = 2;
|
|
|
|
evas_tangent_space_get(vertex_data, tex_data, normal_data, index, mesh_pd->vertex_count,
|
|
mesh_pd->index_count, stride, tex_stride, normal_stride, &tangent_data);
|
|
|
|
evas_canvas3d_mesh_frame_vertex_data_copy_set(mesh, 0, EVAS_CANVAS3D_VERTEX_ATTRIB_TANGENT, 3 * sizeof(float), tangent_data);
|
|
free(tangent_data);
|
|
}
|
|
}
|
|
}
|
|
if (!_node_is_visible(node, scene_data->camera_node))
|
|
{
|
|
/* Skip entire sub-tree of this node. */
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
Eina_Bool
|
|
evas_canvas3d_node_color_node_mesh_collect(Evas_Canvas3D_Node *node, void *data)
|
|
{
|
|
Evas_Canvas3D_Scene_Public_Data *scene_data = (Evas_Canvas3D_Scene_Public_Data *)data;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
Evas_Canvas3D_Node_Data *pd_camera = efl_data_scope_get(scene_data->camera_node, MY_CLASS);
|
|
Evas_Canvas3D_Camera *camera = (Evas_Canvas3D_Camera*)pd_camera->data.camera.camera;
|
|
|
|
Eina_List *list_meshes, *l;
|
|
Evas_Canvas3D_Mesh *mesh;
|
|
Eina_Stringshare *key, *datakey;
|
|
Evas_Color *color;
|
|
Eina_Bool visible = EINA_FALSE;
|
|
Eina_Array *arr;
|
|
if (pd->type == EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
visible = evas_canvas3d_camera_node_visible_get(camera, scene_data->camera_node, node, EVAS_CANVAS3D_FRUSTUM_MODE_BSPHERE);
|
|
if (visible)
|
|
{
|
|
list_meshes = (Eina_List *)evas_canvas3d_node_mesh_list_get(node);
|
|
EINA_LIST_FOREACH(list_meshes, l, mesh)
|
|
{
|
|
if (evas_canvas3d_mesh_color_pick_enable_get(mesh))
|
|
{
|
|
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_canvas3d_node_light_collect(Evas_Canvas3D_Node *node, void *data)
|
|
{
|
|
Evas_Canvas3D_Scene_Public_Data *scene_data = (Evas_Canvas3D_Scene_Public_Data *)data;
|
|
Evas_Canvas3D_Node_Data *pd = efl_data_scope_get(node, MY_CLASS);
|
|
if (pd->type == EVAS_CANVAS3D_NODE_TYPE_LIGHT)
|
|
scene_data->light_nodes = eina_list_append(scene_data->light_nodes, node);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
EAPI Evas_Canvas3D_Node *
|
|
evas_canvas3d_node_add(Evas *e, Evas_Canvas3D_Node_Type type)
|
|
{
|
|
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
|
|
return NULL;
|
|
MAGIC_CHECK_END();
|
|
return efl_add(MY_CLASS, e, evas_canvas3d_node_type_set(efl_added, type));
|
|
}
|
|
|
|
EOLIAN static Efl_Object *
|
|
_evas_canvas3d_node_efl_object_finalize(Eo *obj, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
if (pd->type == EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
pd->data.mesh.node_meshes = eina_hash_pointer_new(_node_mesh_free_func);
|
|
if (pd->data.mesh.node_meshes == NULL)
|
|
{
|
|
ERR("Failed to create node mesh table.");
|
|
_node_free(obj);
|
|
return NULL;
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
EOLIAN static Efl_Object *
|
|
_evas_canvas3d_node_efl_object_constructor(Eo *obj, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
evas_canvas3d_object_type_set(obj, EVAS_CANVAS3D_OBJECT_TYPE_NODE);
|
|
|
|
eina_vector3_set(&pd->position, 0.0, 0.0, 0.0);
|
|
eina_quaternion_set(&pd->orientation, 0.0, 0.0, 0.0, 1.0);
|
|
eina_vector3_set(&pd->scale, 1.0, 1.0, 1.0);
|
|
|
|
eina_vector3_set(&pd->position_world, 0.0, 0.0, 0.0);
|
|
eina_quaternion_set(&pd->orientation_world, 0.0, 0.0, 0.0, 1.0);
|
|
eina_vector3_set(&pd->scale_world, 1.0, 1.0, 1.0);
|
|
|
|
pd->position_inherit = EINA_TRUE;
|
|
pd->orientation_inherit = EINA_TRUE;
|
|
pd->scale_inherit = EINA_TRUE;
|
|
pd->data.mesh.node_meshes = 0;
|
|
pd->billboard_target = NULL;
|
|
pd->lod = EINA_FALSE;
|
|
|
|
evas_box3_set(&pd->aabb, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
return obj;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_efl_object_destructor(Eo *obj, Evas_Canvas3D_Node_Data *pd EINA_UNUSED)
|
|
{
|
|
_node_free(obj);
|
|
|
|
efl_destructor(efl_super(obj, MY_CLASS));
|
|
}
|
|
|
|
EOLIAN static Evas_Canvas3D_Node_Type
|
|
_evas_canvas3d_node_node_type_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->type;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_node_type_set(Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Node_Type type)
|
|
{
|
|
pd->type = type;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_member_add(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Node *member)
|
|
{
|
|
if (obj == member)
|
|
{
|
|
ERR("Failed to add a member node (adding to itself).");
|
|
return;
|
|
}
|
|
Evas_Canvas3D_Node_Data *pdmember = efl_data_scope_get(member, MY_CLASS);
|
|
if (!pdmember || pdmember->parent == obj)
|
|
return;
|
|
|
|
if (pdmember->parent)
|
|
{
|
|
/* Detaching from previous parent. */
|
|
Evas_Canvas3D_Node_Data *pdmemberparent = efl_data_scope_get(pdmember->parent, MY_CLASS);
|
|
pdmemberparent->members = eina_list_remove(pdmemberparent->members, member);
|
|
|
|
/* Mark changed. */
|
|
evas_canvas3d_object_change(pdmember->parent, EVAS_CANVAS3D_STATE_NODE_MEMBER, NULL);
|
|
}
|
|
else
|
|
{
|
|
/* Should get a new reference. */
|
|
efl_ref(member);
|
|
}
|
|
|
|
/* Add the member node. */
|
|
pd->members = eina_list_append(pd->members, (const void *)member);
|
|
pdmember->parent = obj;
|
|
|
|
/* Mark changed. */
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_MEMBER, NULL);
|
|
evas_canvas3d_object_change(member, EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION, NULL);
|
|
evas_canvas3d_object_change(member, EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION, NULL);
|
|
evas_canvas3d_object_change(member, EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_member_del(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Node *member)
|
|
{
|
|
Evas_Canvas3D_Node_Data *pdmember = efl_data_scope_get(member, MY_CLASS);
|
|
if (!pdmember || pdmember->parent != obj)
|
|
{
|
|
ERR("Failed to delete a member node (not a member of the given node)");
|
|
return;
|
|
}
|
|
|
|
/* Delete the member node. */
|
|
pd->members = eina_list_remove(pd->members, member);
|
|
pdmember->parent = NULL;
|
|
|
|
/* Mark modified object as changed. */
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_MEMBER, NULL);
|
|
evas_canvas3d_object_change(member, EVAS_CANVAS3D_STATE_NODE_PARENT_ORIENTATION, NULL);
|
|
evas_canvas3d_object_change(member, EVAS_CANVAS3D_STATE_NODE_PARENT_POSITION, NULL);
|
|
evas_canvas3d_object_change(member, EVAS_CANVAS3D_STATE_NODE_PARENT_SCALE, NULL);
|
|
|
|
/* Decrease reference count. */
|
|
efl_unref(member);
|
|
}
|
|
|
|
EOLIAN static Evas_Canvas3D_Node *
|
|
_evas_canvas3d_node_parent_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->parent;
|
|
}
|
|
|
|
EOLIAN static const Eina_List *
|
|
_evas_canvas3d_node_member_list_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->members;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_position_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Real x, Evas_Real y, Evas_Real z)
|
|
{
|
|
pd->position.x = x;
|
|
pd->position.y = y;
|
|
pd->position.z = z;
|
|
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_POSITION, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_orientation_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Real x, Evas_Real y, Evas_Real z, Evas_Real w)
|
|
{
|
|
pd->orientation.x = x;
|
|
pd->orientation.y = y;
|
|
pd->orientation.z = z;
|
|
pd->orientation.w = w;
|
|
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_orientation_angle_axis_set(Eo *obj, Evas_Canvas3D_Node_Data *pd,
|
|
Evas_Real angle, Evas_Real x, Evas_Real y, Evas_Real z)
|
|
{
|
|
Evas_Real half_angle = 0.5 * DEGREE_TO_RADIAN(angle);
|
|
Evas_Real s = sin(half_angle);
|
|
Eina_Vector3 axis;
|
|
|
|
eina_vector3_set(&axis, x, y, z);
|
|
eina_vector3_normalize(&axis, &axis);
|
|
|
|
pd->orientation.w = cos(half_angle);
|
|
pd->orientation.x = s * axis.x;
|
|
pd->orientation.y = s * axis.y;
|
|
pd->orientation.z = s * axis.z;
|
|
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_scale_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Real x, Evas_Real y, Evas_Real z)
|
|
{
|
|
pd->scale.x = x;
|
|
pd->scale.y = y;
|
|
pd->scale.z = z;
|
|
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_SCALE, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_position_get(const Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Space space,
|
|
Evas_Real *x, Evas_Real *y, Evas_Real *z)
|
|
{
|
|
if (space == EVAS_CANVAS3D_SPACE_LOCAL)
|
|
{
|
|
if (x) *x = 0.0;
|
|
if (y) *y = 0.0;
|
|
if (z) *z = 0.0;
|
|
}
|
|
else if (space == EVAS_CANVAS3D_SPACE_PARENT)
|
|
{
|
|
if (x) *x = pd->position.x;
|
|
if (y) *y = pd->position.y;
|
|
if (z) *z = pd->position.z;
|
|
}
|
|
else if (space == EVAS_CANVAS3D_SPACE_WORLD)
|
|
{
|
|
evas_canvas3d_object_update((Eo *) obj);
|
|
|
|
if (x) *x = pd->position_world.x;
|
|
if (y) *y = pd->position_world.y;
|
|
if (z) *z = pd->position_world.z;
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_orientation_get(const Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Space space,
|
|
Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *w)
|
|
{
|
|
if (space == EVAS_CANVAS3D_SPACE_LOCAL)
|
|
{
|
|
if (x) *x = 0.0;
|
|
if (y) *y = 0.0;
|
|
if (z) *z = 0.0;
|
|
if (w) *w = 0.0;
|
|
}
|
|
else if (space == EVAS_CANVAS3D_SPACE_PARENT)
|
|
{
|
|
if (x) *x = pd->orientation.x;
|
|
if (y) *y = pd->orientation.y;
|
|
if (z) *z = pd->orientation.z;
|
|
if (w) *w = pd->orientation.w;
|
|
}
|
|
else if (space == EVAS_CANVAS3D_SPACE_WORLD)
|
|
{
|
|
evas_canvas3d_object_update((Eo *) obj);
|
|
|
|
if (x) *x = pd->orientation_world.x;
|
|
if (y) *y = pd->orientation_world.y;
|
|
if (z) *z = pd->orientation_world.z;
|
|
if (w) *w = pd->orientation_world.w;
|
|
}
|
|
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_scale_get(const Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Space space,
|
|
Evas_Real *x, Evas_Real *y, Evas_Real *z)
|
|
{
|
|
if (space == EVAS_CANVAS3D_SPACE_LOCAL)
|
|
{
|
|
if (x) *x = 0.0;
|
|
if (y) *y = 0.0;
|
|
if (z) *z = 0.0;
|
|
}
|
|
else if (space == EVAS_CANVAS3D_SPACE_PARENT)
|
|
{
|
|
if (x) *x = pd->scale.x;
|
|
if (y) *y = pd->scale.y;
|
|
if (z) *z = pd->scale.z;
|
|
}
|
|
else if (space == EVAS_CANVAS3D_SPACE_WORLD)
|
|
{
|
|
evas_canvas3d_object_update((Eo *) obj);
|
|
|
|
if (x) *x = pd->scale_world.x;
|
|
if (y) *y = pd->scale_world.y;
|
|
if (z) *z = pd->scale_world.z;
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_position_inherit_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Eina_Bool inherit)
|
|
{
|
|
pd->position_inherit = inherit;
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_POSITION, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_orientation_inherit_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Eina_Bool inherit)
|
|
{
|
|
pd->orientation_inherit = inherit;
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_scale_inherit_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Eina_Bool inherit)
|
|
{
|
|
pd->scale_inherit = inherit;
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_SCALE, NULL);
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_evas_canvas3d_node_position_inherit_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->position_inherit;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_evas_canvas3d_node_orientation_inherit_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->orientation_inherit;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_evas_canvas3d_node_scale_inherit_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->scale_inherit;
|
|
}
|
|
|
|
static void
|
|
_look_at_set(Evas_Canvas3D_Node_Data *pd, Eina_Vector3 *target, Eina_Vector3 *up)
|
|
{
|
|
Eina_Vector3 x, y, z;
|
|
|
|
eina_vector3_subtract(&z, &pd->position, target);
|
|
eina_vector3_normalize(&z, &z);
|
|
|
|
eina_vector3_cross_product(&x, up, &z);
|
|
eina_vector3_normalize(&x, &x);
|
|
|
|
eina_vector3_cross_product(&y, &z, &x);
|
|
eina_vector3_normalize(&y, &y);
|
|
|
|
/* Below matrix to quaternion conversion code taken from
|
|
* http://fabiensanglard.net/doom3_documentation/37726-293748.pdf
|
|
* When any license issue occurs, use ken shoemake's algorithm instead.
|
|
*/
|
|
|
|
if (x.x + y.y + z.z > 0.0)
|
|
{
|
|
Evas_Real t = x.x + y.y + z.z + 1.0;
|
|
Evas_Real s = evas_reciprocal_sqrt(t) * 0.5;
|
|
|
|
pd->orientation.w = s * t;
|
|
pd->orientation.z = (x.y - y.x) * s;
|
|
pd->orientation.y = (z.x - x.z) * s;
|
|
pd->orientation.x = (y.z - z.y) * s;
|
|
}
|
|
else if (x.x > y.y && x.x > z.z)
|
|
{
|
|
Evas_Real t = x.x - y.y - z.z + 1.0;
|
|
Evas_Real s = evas_reciprocal_sqrt(t) * 0.5;
|
|
|
|
pd->orientation.x = s * t;
|
|
pd->orientation.y = (x.y + y.x) * s;
|
|
pd->orientation.z = (z.x + x.z) * s;
|
|
pd->orientation.w = (y.z - z.y) * s;
|
|
}
|
|
else if (y.y > z.z)
|
|
{
|
|
Evas_Real t = -x.x + y.y - z.z + 1.0;
|
|
Evas_Real s = evas_reciprocal_sqrt(t) * 0.5;
|
|
|
|
pd->orientation.y = s * t;
|
|
pd->orientation.x = (x.y + y.x) * s;
|
|
pd->orientation.w = (z.x - x.z) * s;
|
|
pd->orientation.z = (y.z + z.y) * s;
|
|
}
|
|
else
|
|
{
|
|
Evas_Real t = -x.x - y.y + z.z + 1.0;
|
|
Evas_Real s = evas_reciprocal_sqrt(t) * 0.5;
|
|
|
|
pd->orientation.z = s * t;
|
|
pd->orientation.w = (x.y - y.x) * s;
|
|
pd->orientation.x = (z.x + x.z) * s;
|
|
pd->orientation.y = (y.z + z.y) * s;
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_look_at_set(Eo *obj, Evas_Canvas3D_Node_Data *pd,
|
|
Evas_Canvas3D_Space target_space, Evas_Real tx, Evas_Real ty, Evas_Real tz,
|
|
Evas_Canvas3D_Space up_space, Evas_Real ux, Evas_Real uy, Evas_Real uz)
|
|
{
|
|
Eina_Vector3 target;
|
|
Eina_Vector3 up;
|
|
|
|
/* Target position in parent space. */
|
|
if (target_space == EVAS_CANVAS3D_SPACE_LOCAL)
|
|
{
|
|
ERR("TODO:");
|
|
return;
|
|
}
|
|
else if (target_space == EVAS_CANVAS3D_SPACE_PARENT)
|
|
{
|
|
eina_vector3_set(&target, tx, ty, tz);
|
|
}
|
|
else if (target_space == EVAS_CANVAS3D_SPACE_WORLD)
|
|
{
|
|
ERR("TODO:");
|
|
return;
|
|
|
|
}
|
|
else
|
|
{
|
|
ERR("Invalid coordinate space.");
|
|
return;
|
|
}
|
|
|
|
if (up_space == EVAS_CANVAS3D_SPACE_LOCAL)
|
|
{
|
|
eina_vector3_set(&up, ux, uy, uz);
|
|
//ERR("TODO:");
|
|
//return;
|
|
}
|
|
else if (up_space == EVAS_CANVAS3D_SPACE_PARENT)
|
|
{
|
|
eina_vector3_set(&up, ux, uy, uz);
|
|
}
|
|
else if (up_space == EVAS_CANVAS3D_SPACE_WORLD)
|
|
{
|
|
ERR("TODO:");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
ERR("Invalid coordinate space.");
|
|
return;
|
|
}
|
|
|
|
_look_at_set(pd, &target, &up);
|
|
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_TRANSFORM_ORIENTATION, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_camera_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Camera *camera)
|
|
{
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_CAMERA)
|
|
{
|
|
ERR("Node type mismatch.");
|
|
return;
|
|
}
|
|
|
|
if (pd->data.camera.camera == camera)
|
|
return;
|
|
|
|
if (pd->data.camera.camera)
|
|
{
|
|
/* Detach previous camera object. */
|
|
evas_canvas3d_camera_node_del(pd->data.camera.camera, obj);
|
|
efl_unref(pd->data.camera.camera);
|
|
}
|
|
|
|
pd->data.camera.camera = camera;
|
|
efl_ref(camera);
|
|
|
|
/* Register change notification on the camera for this node. */
|
|
evas_canvas3d_camera_node_add(camera, obj);
|
|
|
|
/* Mark changed. */
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_CAMERA, NULL);
|
|
}
|
|
|
|
EOLIAN static Evas_Canvas3D_Camera *
|
|
_evas_canvas3d_node_camera_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->data.camera.camera;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_light_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Light *light)
|
|
{
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_LIGHT)
|
|
{
|
|
ERR("Node type mismatch.");
|
|
return;
|
|
}
|
|
|
|
if (pd->data.light.light == light)
|
|
return;
|
|
|
|
if (pd->data.light.light)
|
|
{
|
|
/* Detach previous light object. */
|
|
evas_canvas3d_light_node_del(pd->data.light.light, obj);
|
|
efl_unref(pd->data.light.light);
|
|
}
|
|
|
|
pd->data.light.light = light;
|
|
efl_ref(light);
|
|
|
|
/* Register change notification on the light for this node. */
|
|
evas_canvas3d_light_node_add(light, obj);
|
|
|
|
/* Mark changed. */
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_LIGHT, NULL);
|
|
}
|
|
|
|
EOLIAN static Evas_Canvas3D_Light *
|
|
_evas_canvas3d_node_light_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->data.light.light;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_mesh_add(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Mesh *mesh)
|
|
{
|
|
Evas_Canvas3D_Node_Mesh *nm = NULL;
|
|
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
ERR("Node type mismatch.");
|
|
return;
|
|
}
|
|
|
|
if (eina_hash_find(pd->data.mesh.node_meshes, &mesh) != NULL)
|
|
{
|
|
ERR("The mesh is already added to the node.");
|
|
return;
|
|
}
|
|
|
|
if ((nm = _node_mesh_new(obj, mesh)) == NULL)
|
|
{
|
|
ERR("Failed to create node mesh.");
|
|
return;
|
|
}
|
|
|
|
/* TODO: Find node mesh and add if it does not exist. */
|
|
if (!eina_hash_add(pd->data.mesh.node_meshes, &mesh, nm))
|
|
{
|
|
ERR("Failed to add a mesh to mesh table.");
|
|
_node_mesh_free(nm);
|
|
return;
|
|
}
|
|
|
|
pd->data.mesh.meshes = eina_list_append(pd->data.mesh.meshes, mesh);
|
|
efl_ref(mesh);
|
|
|
|
/* Register change notification. */
|
|
evas_canvas3d_mesh_node_add(mesh, obj);
|
|
|
|
/* Mark changed. */
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_MESH_GEOMETRY, NULL);
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_MESH_MATERIAL, NULL);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_mesh_del(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Mesh *mesh)
|
|
{
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
ERR("Node type mismatch.");
|
|
return;
|
|
}
|
|
|
|
if (!eina_hash_del(pd->data.mesh.node_meshes, &mesh, NULL))
|
|
{
|
|
ERR("The given mesh doesn't belong to this node.");
|
|
return;
|
|
}
|
|
|
|
pd->data.mesh.meshes = eina_list_remove(pd->data.mesh.meshes, mesh);
|
|
evas_canvas3d_mesh_node_del(mesh, obj);
|
|
efl_unref(mesh);
|
|
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_MESH_GEOMETRY, NULL);
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_MESH_MATERIAL, NULL);
|
|
}
|
|
|
|
EOLIAN static const Eina_List *
|
|
_evas_canvas3d_node_mesh_list_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->data.mesh.meshes;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_mesh_frame_set(Eo *obj, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Mesh *mesh, int frame)
|
|
{
|
|
Evas_Canvas3D_Node_Mesh *nm = NULL;
|
|
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
ERR("Node type mismatch.");
|
|
return;
|
|
}
|
|
|
|
if ((nm = eina_hash_find(pd->data.mesh.node_meshes, &mesh)) == NULL)
|
|
{
|
|
ERR("The given mesh doesn't belongs to this node.");
|
|
return;
|
|
}
|
|
|
|
nm->frame = frame;
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_MESH_FRAME, NULL);
|
|
}
|
|
|
|
EOLIAN static int
|
|
_evas_canvas3d_node_mesh_frame_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd, Evas_Canvas3D_Mesh *mesh)
|
|
{
|
|
Evas_Canvas3D_Node_Mesh *nm = NULL;
|
|
|
|
if (pd->type != EVAS_CANVAS3D_NODE_TYPE_MESH)
|
|
{
|
|
ERR("Node type mismatch.");
|
|
return 0;
|
|
}
|
|
|
|
if ((nm = eina_hash_find(pd->data.mesh.node_meshes, &mesh)) == NULL)
|
|
{
|
|
ERR("The given mesh doesn't belongs to this node.");
|
|
return 0;
|
|
}
|
|
|
|
return nm->frame;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_bounding_box_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *x2, Evas_Real *y2, Evas_Real *z2)
|
|
{
|
|
evas_canvas3d_object_update(obj);
|
|
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_FALSE,
|
|
node_aabb_update, NULL);
|
|
|
|
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;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_bounding_sphere_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *r)
|
|
{
|
|
evas_canvas3d_object_update(obj);
|
|
evas_canvas3d_node_tree_traverse(obj, EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_FALSE,
|
|
node_aabb_update, NULL);
|
|
|
|
if (x) *x = pd->bsphere.center.x;
|
|
if (y) *y = pd->bsphere.center.y;
|
|
if (z) *z = pd->bsphere.center.z;
|
|
if (r) *r = pd->bsphere.radius;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_billboard_target_set(Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd,
|
|
Eo *target)
|
|
{
|
|
if (pd->billboard_target != target)
|
|
{
|
|
pd->billboard_target = target;
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_PARENT_BILLBOARD, NULL);
|
|
}
|
|
}
|
|
|
|
EOLIAN static Evas_Canvas3D_Node *
|
|
_evas_canvas3d_node_billboard_target_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->billboard_target;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_evas_canvas3d_node_lod_enable_set(Eo *obj, Evas_Canvas3D_Node_Data *pd,
|
|
Eina_Bool enable)
|
|
{
|
|
pd->lod = enable;
|
|
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_NODE_LOD, NULL);
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_evas_canvas3d_node_lod_enable_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Node_Data *pd)
|
|
{
|
|
return pd->lod;
|
|
}
|
|
#include "canvas/evas_canvas3d_node.eo.c"
|