aboutsummaryrefslogblamecommitdiffstats
path: root/src/lib/evas/canvas/evas_canvas3d_scene.c
blob: 161d1de12068f58a460350e74a74431f2e821a13 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                                
                                          
 
    
                                                                    



                            

                                 
                                        
                          
                                      
                                                                               


    
                                                                    







                                       
                  


                                                                                                             
 


                   
                                       
      
                                                                                          



                                    
                  
                                                                                                          
 
                     
      
                                                   

      
                       
      
                                                     
      
 
                                                                             

 

                                
 


                                    
                               

 
                  
                                                                                  
 
                                                   
                                                                       
                                                     
                                    


                                       

                              
              

 
                  
                                                                                                   
 
                             

            
                     
      
                                                              
                                 

      
                        


            
                      
                                                     

      
                                                                               

 

                                                                                     
 
                        

 
                  
                                                                                                     
 
                               

            
                       
      
                                                                  

      
                          


            
                                                       

      
                                                                                 

 

                                                                                       
 
                          

 
                  
                                                                                              
 

             
                                                                          

 
                  
                                                                                                      
 

                     

 
                  
                                                                                            

                                                                                      
                                             
                                                                                      

 
                  
                                                                                                  

                                                                                          



                              


                       
                                                                            

                                                  
                                           

                                     

                                                  
 

                                                     







                                                                    
                                                     

                                               
                                                        




                                    
                                                 

                                               
                                                            




                                               
                                                      
















                                         

                                                                                                            



















































                                                                                               
                       

                                                                                  
 
                                                        



                                                  



                                                            
 
                                                                                                      

                                                                         
                                                                                                      
                                                                         
                                                                                        
                       


                                
                                                                        
           
                                                         
                
                                                                                        
                     


                                                                       


                      


                                                                      

                     


                                                                                                     


                                                               

                                                                                                

                                         
                                        


                     
                                                                                  
           
                                                                                   
                

                                                              


                 

                                                             

                

                                                                                                
 
                                                          



                                  
                                                                                        
                                                                    
                      
                                                                   
 
                                                                                                     


                                                               
                                                                                             
                          

                                                                            


                           

                                                                           

                          

                                                                                                

                                         
                                        


                     
                                                                                
           
                                                                                   
                

                                                              


                 

                                                             

                

                                                                                                
 
                                                          


                                  
                                                                                        
                                                                    
                      
                                                                   
 
                                                                                                     


                                                               
                                                                                             
                                                                     
                           
                                                                    
 

                                                                                                





                                         
                                                                             
      
                                                                        
           
                                                         
                


                                                                                                        


                                                               

                                                                                                     




                                         
                                                                                  
           

                                                                                               
 
                                                          



                                  
                                                                                                        


                                                               

                                                                                                     




                                         
                                                                                
           

                                                                                               
 
                                                          


                                  
                                                                                                        


                                                               

                                                                                                





                                         
                                                      
                                      
      
                                                                        


                                                          


                                                                                                        


                                                               

                                                                                                     




                                         
                                                                                  
           

                                                                                               





                                                           
                                                                                                        


                                                               

                                                                                                    

                                         
                                        


                     
                                                                                
           

                                                                                               




                                                           
                                                                                                        


                                                               

                                                                                                 

                                         
                                        



                     
                     


         
                                                

                            
                                                                     
                               
                                                                                         
 


                                                                                             
                                                                    




                                  
                                                     




                                                        
                                                                                                 

                                                     
                                                                          


                                             
                                                                          

                                                                           





                    




                                                 












                                                                                                  
                       
                                                                                                
                                                                         
                                               
 



                                           
                       
                        
                                           


                                       
                                          
                                               
 

                                                                   
 
                                   





                                                         
                                                   




                                                               
                                                                                              
                                                













                                                                                          


                                                                                            


                                                             
                                                                                          





                                                                                          

                                                                                                          


                                                                                     

                                                                                                
                                                          

                                                      
                                                        
                                                                                                      
                                                                                              
 












                                                      
                                
                                           

                                                                                                  
                                         

                                                                        


                                                                    
                                                                    
                                                                                                      









                                                 
                               
                                                                             
                                                                 
 

                    
 
                                  
                                                                                                                           
 


                                           

                                        
 

                                                                   
 
                                   

                                
                                           

                                                                                                  
                                         













                                                                        
                                                                                                                
 

                                           



                                    
                                                                      




                                        
                                                            


                                   
                                                       





                                                           
                       
                                                                                                




                              
                                                                                                                      

                                          
                                                                                     

 
                       
                                                                                                   




                                 
                                                                                                                 



                                          
                                                                             


                    





                                                                                         
                                                                                   









                                                                                          
                                          
#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"