efl/src/lib/evas/canvas/evas_canvas3d_scene.c

839 lines
30 KiB
C

#include "evas_common_private.h"
#include "evas_private.h"
#define MY_CLASS EVAS_CANVAS3D_SCENE_CLASS
void
evas_canvas3d_scene_data_init(Evas_Canvas3D_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;
data->render_to_texture = EINA_FALSE;
data->lod_distance = 0;
data->post_processing = EINA_FALSE;
data->post_processing_type = EVAS_CANVAS3D_SHADER_MODE_POST_PROCESSING_FXAA;
}
void
evas_canvas3d_scene_data_fini(Evas_Canvas3D_Scene_Public_Data *data)
{
if (data->light_nodes)
eina_list_free(data->light_nodes);
if (data->mesh_nodes)
eina_list_free(data->mesh_nodes);
}
EOLIAN static void
_evas_canvas3d_scene_evas_canvas3d_object_change_notify(Eo *eo_obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd,
Evas_Canvas3D_State state EINA_UNUSED,
Evas_Canvas3D_Object *ref EINA_UNUSED)
{
Eina_List *l;
Evas_Object *eo;
EINA_LIST_FOREACH(pd->images, l, eo)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo, EFL_CANVAS_OBJECT_CLASS);
evas_object_change(eo, obj);
}
}
EOLIAN static void
_evas_canvas3d_scene_evas_canvas3d_object_update_notify(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd)
{
if (pd->root_node)
{
evas_canvas3d_object_update(pd->root_node);
}
if (pd->camera_node)
{
evas_canvas3d_object_update(pd->camera_node);
}
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_UPDATED, NULL);
}
EAPI Evas_Canvas3D_Scene *
evas_canvas3d_scene_add(Evas *e)
{
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return NULL;
MAGIC_CHECK_END();
return efl_add(MY_CLASS, e);
}
EOLIAN static Eo *
_evas_canvas3d_scene_efl_object_constructor(Eo *obj, Evas_Canvas3D_Scene_Data *pd)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
evas_canvas3d_object_type_set(obj, EVAS_CANVAS3D_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;
pd->depth_offset = 4.0;
pd->depth_constant = 100.0;
return obj;
}
EOLIAN static void
_evas_canvas3d_scene_root_node_set(Eo *obj, Evas_Canvas3D_Scene_Data *pd, Evas_Canvas3D_Node *node)
{
if (pd->root_node == node)
return;
if (pd->root_node)
{
evas_canvas3d_node_scene_root_del(pd->root_node, obj);
efl_unref(pd->root_node);
}
pd->root_node = node;
if (node)
{
efl_ref(node);
evas_canvas3d_node_scene_root_add(node, obj);
}
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_ROOT_NODE, NULL);
}
EOLIAN static Evas_Canvas3D_Node *
_evas_canvas3d_scene_root_node_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd)
{
return pd->root_node;
}
EOLIAN static void
_evas_canvas3d_scene_camera_node_set(Eo *obj, Evas_Canvas3D_Scene_Data *pd, Evas_Canvas3D_Node *node)
{
if (pd->camera_node == node)
return;
if (pd->camera_node)
{
evas_canvas3d_node_scene_camera_del(pd->camera_node, obj);
}
pd->camera_node = node;
if (node)
{
evas_canvas3d_node_scene_camera_add(node, obj);
}
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_CAMERA_NODE, NULL);
}
EOLIAN static Evas_Canvas3D_Node *
_evas_canvas3d_scene_camera_node_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd)
{
return pd->camera_node;
}
EOLIAN static void
_evas_canvas3d_scene_size_set(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd, int w, int h)
{
pd->w = w;
pd->h = h;
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_SIZE, NULL);
}
EOLIAN static void
_evas_canvas3d_scene_size_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd, int *w, int *h)
{
if (w) *w = pd->w;
if (h) *h = pd->h;
}
EOLIAN static void
_evas_canvas3d_scene_background_color_set(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd,
Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a)
{
evas_color_set(&pd->bg_color, r, g, b, a);
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_BACKGROUND_COLOR, NULL);
}
EOLIAN static void
_evas_canvas3d_scene_background_color_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd,
Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a)
{
if (r) *r = pd->bg_color.r;
if (g) *g = pd->bg_color.g;
if (b) *b = pd->bg_color.b;
if (a) *a = pd->bg_color.a;
}
static inline Eina_Bool
_pick_data_triangle_add(Evas_Canvas3D_Pick_Data *data, const Evas_Ray3 *ray,
const Evas_Triangle3 *tri)
{
Eina_Vector3 e1, e2, tvec, pvec, qvec;
Evas_Real det, inv_det, u, v, t;
eina_vector3_subtract(&e1, &tri->p1, &tri->p0);
eina_vector3_subtract(&e2, &tri->p2, &tri->p0);
eina_vector3_cross_product(&pvec, &ray->dir, &e2);
det = eina_vector3_dot_product(&e1, &pvec);
/* If determinant is near zero, ray lies in plane of triangle. */
if (det > -0.0000001 && det < 0.0000001)
return EINA_FALSE;
inv_det = 1.0 / det;
/* Calculate distance from p0 to ray origin. */
eina_vector3_subtract(&tvec, &ray->org, &tri->p0);
/* Calculate U parameter and test bounds. */
u = eina_vector3_dot_product(&tvec, &pvec) * inv_det;
if (u < 0.0 || u > 1.0)
return EINA_FALSE;
/* Prepare to tst V parameter. */
eina_vector3_cross_product(&qvec, &tvec, &e1);
/* Calculate V parameter and test bounds. */
v = eina_vector3_dot_product(&ray->dir, &qvec) * inv_det;
if (v < 0.0 || u + v > 1.0)
return EINA_FALSE;
/* Calculate T parameter and test bounds. */
t = eina_vector3_dot_product(&e2, &qvec) * inv_det;
if (t >= 0.0 && t <= 1.0)
{
if (!data->picked || t < data->z)
{
data->picked = EINA_TRUE;
data->z = t;
data->u = u;
data->v = v;
return EINA_TRUE;
}
}
return EINA_FALSE;
}
static inline void
_pick_data_texcoord_update(Evas_Canvas3D_Pick_Data *data,
const Evas_Canvas3D_Vertex_Buffer *tex0, const Evas_Canvas3D_Vertex_Buffer *tex1,
Evas_Real weight, unsigned int i0, unsigned int i1, unsigned int i2)
{
Evas_Real s0, s1, s2;
Evas_Real t0, t1, t2;
if (tex1->data == NULL)
{
float *ptr;
ptr = (float *)((char *)tex0->data + tex0->stride * i0);
s0 = ptr[0];
t0 = ptr[1];
ptr = (float *)((char *)tex0->data + tex0->stride * i1);
s1 = ptr[0];
t1 = ptr[1];
ptr = (float *)((char *)tex0->data + tex0->stride * i2);
s2 = ptr[0];
t2 = ptr[1];
}
else
{
float *ptr0, *ptr1;
ptr0 = (float *)((char *)tex0->data + tex0->stride * i0);
ptr1 = (float *)((char *)tex1->data + tex1->stride * i0);
s0 = ptr0[0] * weight + ptr1[0] * (1.0 - weight);
t0 = ptr0[1] * weight + ptr1[1] * (1.0 - weight);
ptr0 = (float *)((char *)tex0->data + tex0->stride * i1);
ptr1 = (float *)((char *)tex1->data + tex1->stride * i1);
s1 = ptr0[0] * weight + ptr1[0] * (1.0 - weight);
t1 = ptr0[1] * weight + ptr1[1] * (1.0 - weight);
ptr0 = (float *)((char *)tex0->data + tex0->stride * i2);
ptr1 = (float *)((char *)tex1->data + tex1->stride * i2);
s2 = ptr0[0] * weight + ptr1[0] * (1.0 - weight);
t2 = ptr0[1] * weight + ptr1[1] * (1.0 - weight);
}
data->s = s0 * (1 - data->u - data->v) + s1 * data->u + s2 * data->v;
data->t = t0 * (1 - data->u - data->v) + t1 * data->u + t2 * data->v;
}
static inline Eina_Bool
_pick_data_mesh_add(Evas_Canvas3D_Pick_Data *data, const Evas_Ray3 *ray,
Evas_Canvas3D_Mesh *mesh, int frame, Evas_Canvas3D_Node *node)
{
Evas_Canvas3D_Vertex_Buffer pos0, pos1, tex0, tex1;
Evas_Real pos_weight, tex_weight;
Evas_Triangle3 tri;
int i;
memset(&pos0, 0x00, sizeof(Evas_Canvas3D_Vertex_Buffer));
memset(&pos1, 0x00, sizeof(Evas_Canvas3D_Vertex_Buffer));
memset(&tex0, 0x00, sizeof(Evas_Canvas3D_Vertex_Buffer));
memset(&tex1, 0x00, sizeof(Evas_Canvas3D_Vertex_Buffer));
evas_canvas3d_mesh_interpolate_vertex_buffer_get(mesh, frame, EVAS_CANVAS3D_VERTEX_ATTRIB_POSITION,
&pos0, &pos1, &pos_weight);
evas_canvas3d_mesh_interpolate_vertex_buffer_get(mesh, frame, EVAS_CANVAS3D_VERTEX_ATTRIB_TEXCOORD,
&tex0, &tex1, &tex_weight);
Evas_Canvas3D_Mesh_Data *pdmesh = efl_data_scope_get(mesh, EVAS_CANVAS3D_MESH_CLASS);
if (pdmesh->indices)
{
unsigned int i0, i1, i2;
if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLES)
{
for (i = 0; i < pdmesh->index_count; i += 3)
{
if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_SHORT)
{
i0 = ((unsigned short *)pdmesh->indices)[i];
i1 = ((unsigned short *)pdmesh->indices)[i + 1];
i2 = ((unsigned short *)pdmesh->indices)[i + 2];
}
else
{
i0 = ((unsigned char *)pdmesh->indices)[i];
i1 = ((unsigned char *)pdmesh->indices)[i + 1];
i2 = ((unsigned char *)pdmesh->indices)[i + 2];
}
evas_canvas3d_mesh_interpolate_position_get(&tri.p0, &pos0, &pos1, pos_weight, i0);
evas_canvas3d_mesh_interpolate_position_get(&tri.p1, &pos0, &pos1, pos_weight, i1);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i2);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, i0, i1, i2);
data->mesh = mesh;
data->node = node;
return EINA_TRUE;
}
}
}
else if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLE_STRIP)
{
if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_SHORT)
{
i1 = ((unsigned short *)pdmesh->indices)[0];
i2 = ((unsigned short *)pdmesh->indices)[1];
}
else
{
i1 = ((unsigned char *)pdmesh->indices)[0];
i2 = ((unsigned char *)pdmesh->indices)[1];
}
evas_canvas3d_mesh_interpolate_position_get(&tri.p1, &pos0, &pos1, pos_weight, i1);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i2);
for (i = 0; i < pdmesh->index_count - 2; i++)
{
tri.p0 = tri.p1;
tri.p1 = tri.p2;
if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_SHORT)
i2 = ((unsigned short *)pdmesh->indices)[i + 2];
else
i2 = ((unsigned char *)pdmesh->indices)[i + 2];
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i2);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_SHORT)
{
i0 = ((unsigned short *)pdmesh->indices)[i];
i1 = ((unsigned short *)pdmesh->indices)[i + 1];
}
else
{
i0 = ((unsigned char *)pdmesh->indices)[i];
i1 = ((unsigned char *)pdmesh->indices)[i + 1];
}
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, i0, i1, i2);
data->mesh = mesh;
data->node = node;
return EINA_TRUE;
}
}
}
else if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLE_FAN)
{
if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_SHORT)
{
i0 = ((unsigned short *)pdmesh->indices)[0];
i2 = ((unsigned short *)pdmesh->indices)[1];
}
else
{
i0 = ((unsigned char *)pdmesh->indices)[0];
i2 = ((unsigned char *)pdmesh->indices)[1];
}
evas_canvas3d_mesh_interpolate_position_get(&tri.p0, &pos0, &pos1, pos_weight, i0);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i2);
for (i = 1; i < pdmesh->index_count - 1; i++)
{
tri.p1 = tri.p2;
if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_SHORT)
i2 = ((unsigned short *)pdmesh->indices)[i + 1];
else
i2 = ((unsigned char *)pdmesh->indices)[i + 1];
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i2);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_SHORT)
i1 = ((unsigned short *)pdmesh->indices)[i];
else
i1 = ((unsigned char *)pdmesh->indices)[i];
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, i0, i1, i2);
data->mesh = mesh;
data->node = node;
}
}
}
}
else if (pdmesh->index_format == EVAS_CANVAS3D_INDEX_FORMAT_UNSIGNED_BYTE)
{
if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLES)
{
for (i = 0; i < pdmesh->index_count; i += 3)
{
evas_canvas3d_mesh_interpolate_position_get(&tri.p0, &pos0, &pos1, pos_weight, i);
evas_canvas3d_mesh_interpolate_position_get(&tri.p1, &pos0, &pos1, pos_weight, i + 1);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i + 2);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, i, i + 1, i + 2);
data->mesh = mesh;
data->node = node;
}
}
}
else if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLE_STRIP)
{
evas_canvas3d_mesh_interpolate_position_get(&tri.p1, &pos0, &pos1, pos_weight, 0);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, 1);
for (i = 0; i < pdmesh->index_count - 2; i++)
{
tri.p0 = tri.p1;
tri.p1 = tri.p2;
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i + 2);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, i, i + 1, i + 2);
data->mesh = mesh;
data->node = node;
}
}
}
else if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLE_FAN)
{
evas_canvas3d_mesh_interpolate_position_get(&tri.p0, &pos0, &pos1, pos_weight, 0);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, 1);
for (i = 1; i < pdmesh->index_count - 1; i++)
{
tri.p1 = tri.p2;
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i + 1);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, 0, i, i + 1);
data->mesh = mesh;
data->node = node;
}
}
}
}
else if ((EINA_DBL_EQ(pdmesh->index_count, 0.0)) &&
pdmesh->vertex_count != 0)
{
if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLES)
{
for (i = 0; i < pdmesh->vertex_count; i += 3)
{
evas_canvas3d_mesh_interpolate_position_get(&tri.p0, &pos0, &pos1, pos_weight, i);
evas_canvas3d_mesh_interpolate_position_get(&tri.p1, &pos0, &pos1, pos_weight, i + 1);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i + 2);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, i, i + 1, i + 2);
data->mesh = mesh;
data->node = node;
}
}
}
else if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLE_STRIP)
{
evas_canvas3d_mesh_interpolate_position_get(&tri.p1, &pos0, &pos1, pos_weight, 0);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, 1);
for (i = 0; i < pdmesh->vertex_count - 2; i++)
{
tri.p0 = tri.p1;
tri.p1 = tri.p2;
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i + 2);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, i, i + 1, i + 2);
data->mesh = mesh;
data->node = node;
return EINA_TRUE;
}
}
}
else if (pdmesh->assembly == EVAS_CANVAS3D_VERTEX_ASSEMBLY_TRIANGLE_FAN)
{
evas_canvas3d_mesh_interpolate_position_get(&tri.p0, &pos0, &pos1, pos_weight, 0);
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, 1);
for (i = 1; i < pdmesh->vertex_count - 1; i++)
{
tri.p1 = tri.p2;
evas_canvas3d_mesh_interpolate_position_get(&tri.p2, &pos0, &pos1, pos_weight, i + 1);
if (_pick_data_triangle_add(data, ray, &tri))
{
if (tex0.data)
_pick_data_texcoord_update(data, &tex0, &tex1, tex_weight, 0, i, i + 1);
data->mesh = mesh;
data->node = node;
return EINA_TRUE;
}
}
}
}
return EINA_FALSE;
}
Eina_Bool
_node_pick(Evas_Canvas3D_Node *node, void *data)
{
Evas_Ray3 ray;
Evas_Canvas3D_Pick_Data *pick = (Evas_Canvas3D_Pick_Data *)data;
Eina_Matrix4 mvp;
Evas_Canvas3D_Node_Data *pd_node = efl_data_scope_get(node, EVAS_CANVAS3D_NODE_CLASS);
evas_canvas3d_node_tree_traverse(node, EVAS_CANVAS3D_TREE_TRAVERSE_POST_ORDER, EINA_FALSE,
node_aabb_update, NULL);
if (! evas_box3_ray3_intersect(&pd_node->aabb, &pick->ray_world))
{
/* Skip entire subtree. */
return EINA_FALSE;
}
if (pd_node->type == EVAS_CANVAS3D_NODE_TYPE_MESH)
{
Eina_Iterator *itr;
void *ptr;
/* Transform ray into local coordinate space. */
eina_matrix4_multiply(&mvp, &pick->matrix_vp, &pd_node->data.mesh.matrix_local_to_world);
evas_ray3_init(&ray, pick->x, pick->y, &mvp);
itr = eina_hash_iterator_data_new(pd_node->data.mesh.node_meshes);
while (eina_iterator_next(itr, &ptr))
{
Evas_Canvas3D_Node_Mesh *nm = (Evas_Canvas3D_Node_Mesh *)ptr;
if(_pick_data_mesh_add(pick, &ray, nm->mesh, nm->frame, node))
break;
}
}
return EINA_TRUE;
}
static void _node_mesh_colors_free_cb(void *data)
{
if (data) free(data);
}
static inline void
_pick_data_init(Evas_Canvas3D_Pick_Data *data, Evas_Public_Data *e, Evas_Real x, Evas_Real y)
{
data->x = ((x * 2.0) / ((Evas_Real)e->viewport.w)) - 1.0;
data->y = ((((Evas_Real)e->viewport.h - y - 1) * 2.0) / ((Evas_Real)e->viewport.h)) - 1.0;
data->picked = EINA_FALSE;
data->z = 1.0;
data->node = NULL;
data->mesh = NULL;
data->s = 0.0;
data->t = 0.0;
}
EOLIAN static Eina_Bool
_evas_canvas3d_scene_pick(const Eo *obj, Evas_Canvas3D_Scene_Data *pd, Evas_Real x, Evas_Real y,
Evas_Canvas3D_Node **node, Evas_Canvas3D_Mesh **mesh,
Evas_Real *s, Evas_Real *t)
{
Evas_Canvas3D_Pick_Data data;
Evas_Canvas3D_Node_Data *pd_camera_node;
Evas_Canvas3D_Camera_Data *pd_camera;
Evas_Canvas3D_Object_Data *pd_parent;
Evas_Public_Data *e;
int tex = 0, px, py;;
Evas_Color color = {0.0, 0.0, 0.0, 0.0};
Eina_Stringshare *tmp;
Eina_Array *arr = NULL;
Eina_Bool update_scene = EINA_FALSE;
Evas_Canvas3D_Node *picked_node = NULL;
const Efl_Event_Description *eo_desc = NULL;
pd_parent = efl_data_scope_get(obj, EVAS_CANVAS3D_OBJECT_CLASS);
e = efl_data_scope_get(pd_parent->evas, EVAS_CANVAS_CLASS);
_pick_data_init(&data, e, x, y);
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_Canvas3D_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 = evas_canvas3d_object_dirty_get(obj, EVAS_CANVAS3D_STATE_SCENE_UPDATED);
scene_data.post_processing = EINA_FALSE;
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_canvas3d_node_tree_traverse(pd->root_node,
EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_TRUE,
evas_canvas3d_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(_evas_engine_context(e),
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)
{
e->engine.func->drawable_texture_pixel_color_get(tex, px, py, &color, pd->surface);
tmp = eina_stringshare_printf("%f %f %f", color.r, color.g, color.b);
arr = (Eina_Array *)eina_hash_find(pd->colors_node_mesh, tmp);
if (arr)
{
picked_node = (Evas_Canvas3D_Node *)eina_array_data_get(arr, 0);
if (mesh) *mesh = (Evas_Canvas3D_Mesh *)eina_array_data_get(arr, 1);
if (node) *node = picked_node;
eina_stringshare_del(tmp);
/*Calling callback clicked*/
eo_desc = efl_object_legacy_only_event_description_get("clicked,private");
efl_event_callback_legacy_call(picked_node, eo_desc, picked_node);
return EINA_TRUE;
}
else
{
eina_stringshare_del(tmp);
if (mesh) *mesh = NULL;
if (node) *node = NULL;
}
}
}
}
return EINA_FALSE;
}
/* Update the scene graph. */
evas_canvas3d_object_update((Eo *) obj);
pd_camera_node = efl_data_scope_get(pd->camera_node, EVAS_CANVAS3D_NODE_CLASS);
pd_camera = efl_data_scope_get(pd_camera_node->data.camera.camera, EVAS_CANVAS3D_CAMERA_CLASS);
eina_matrix4_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_canvas3d_node_tree_traverse(pd->root_node, EVAS_CANVAS3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_TRUE,
_node_pick, &data);
if (!data.picked)
return EINA_FALSE;
if (s) *s = data.s;
if (t) *t = data.t;
if (node) *node = data.node;
if (mesh) *mesh = data.mesh;
/*Calling callback clicked*/
eo_desc = efl_object_legacy_only_event_description_get("clicked,private");
efl_event_callback_legacy_call(data.node, eo_desc, data.node);
return EINA_TRUE;
}
EOLIAN static Evas_Canvas3D_Node *
_evas_canvas3d_scene_exist(const Eo *obj, Evas_Canvas3D_Scene_Data *pd, Evas_Real x, Evas_Real y, Evas_Canvas3D_Node *node)
{
Evas_Canvas3D_Pick_Data data;
Evas_Canvas3D_Node_Data *pd_camera_node;
Evas_Canvas3D_Camera_Data *pd_camera;
Evas_Canvas3D_Object_Data *pd_parent;
Evas_Public_Data *e;
pd_parent = efl_data_scope_get(obj, EVAS_CANVAS3D_OBJECT_CLASS);
e = efl_data_scope_get(pd_parent->evas, EVAS_CANVAS_CLASS);
_pick_data_init(&data, e, x, y);
/* Update the scene graph. */
evas_canvas3d_object_update((Eo *) obj);
pd_camera_node = efl_data_scope_get(pd->camera_node, EVAS_CANVAS3D_NODE_CLASS);
pd_camera = efl_data_scope_get(pd_camera_node->data.camera.camera, EVAS_CANVAS3D_CAMERA_CLASS);
eina_matrix4_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);
/* Check pick for given node. */
_node_pick(node, &data);
if (!data.picked || data.node != node) node = NULL;
return node;
}
EOLIAN static Eina_List *
_evas_canvas3d_scene_pick_member_list_get(const Eo *obj, Evas_Canvas3D_Scene_Data *pd, Evas_Real x, Evas_Real y)
{
const Eina_List *list = NULL, *l = NULL;
Eina_List *picked_nodes = NULL;
void *node;
Eina_Bool pick = EINA_FALSE;
/* Check pick for given scene. */
pick = evas_canvas3d_scene_pick(obj, x, y, NULL, NULL, NULL, NULL);
if (!pick)
return NULL;
/* Get all members from root node. */
list = evas_canvas3d_node_member_list_get(pd->root_node);
EINA_LIST_FOREACH(list, l, node)
{
if (evas_canvas3d_scene_exist(obj, x, y, node))
picked_nodes = eina_list_append(picked_nodes, l);
}
return picked_nodes;
}
EOLIAN static Eina_Bool
_evas_canvas3d_scene_shadows_enable_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd)
{
return pd->shadows_enabled;
}
EOLIAN static void
_evas_canvas3d_scene_shadows_enable_set(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd, Eina_Bool _shadows_enabled)
{
pd->shadows_enabled = _shadows_enabled;
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_SHADOWS_ENABLED, NULL);
}
EOLIAN static Eina_Bool
_evas_canvas3d_scene_color_pick_enable_get(const Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd)
{
return pd->color_pick_enabled;
}
EOLIAN static Eina_Bool
_evas_canvas3d_scene_color_pick_enable_set(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd, Eina_Bool _enabled)
{
if (pd->color_pick_enabled != _enabled)
pd->color_pick_enabled = _enabled;
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_UPDATED, NULL);
return EINA_TRUE;
}
EOLIAN static void
_evas_canvas3d_scene_shadows_depth_set(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd,
Evas_Real depth_offset, Evas_Real depth_constant)
{
pd->depth_offset = depth_offset;
pd->depth_constant = depth_constant;
evas_canvas3d_object_change(obj, EVAS_CANVAS3D_STATE_SCENE_SHADOWS_DEPTH, NULL);
}
EOLIAN static void
_evas_canvas3d_scene_shadows_depth_get(Eo *obj EINA_UNUSED, Evas_Canvas3D_Scene_Data *pd,
Evas_Real *depth_offset, Evas_Real *depth_constant)
{
if (depth_offset) *depth_offset = pd->depth_offset;
if (depth_constant) *depth_constant = pd->depth_constant;
}
#include "canvas/evas_canvas3d_scene.eo.c"