839 lines
30 KiB
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(const 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(const 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(const 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"
|