summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorTaekyun Kim <tkq.kim@samsung.com>2013-12-27 16:56:30 +0900
committerChunEon Park <hermet@hermet.pe.kr>2014-04-25 16:15:41 +0900
commit8fda63173063e03e1d48c8b026ecf8b94298162c (patch)
treec5988ae26377679bf58bf777148a6b1a6c5a3912 /src/lib
parent96f9353f4c951dd5dd41a687e272ffe1c28bb9ba (diff)
Evas: 3D: Introducing 3D scene rendering features
Enable 3D features using --enable-evas-3d=yes when configuring. APIs are exposed through Evas_3D.h. Currently, evas-3d is being supported only on gl_x11 engine. Conflicts: src/lib/evas/Evas_Eo.h
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/evas/Evas.h1
-rw-r--r--src/lib/evas/Evas_3D.h289
-rw-r--r--src/lib/evas/canvas/evas_3d_camera.c159
-rw-r--r--src/lib/evas/canvas/evas_3d_light.c273
-rw-r--r--src/lib/evas/canvas/evas_3d_material.c221
-rw-r--r--src/lib/evas/canvas/evas_3d_mesh.c828
-rw-r--r--src/lib/evas/canvas/evas_3d_mesh_loader_md2.c440
-rw-r--r--src/lib/evas/canvas/evas_3d_node.c1162
-rw-r--r--src/lib/evas/canvas/evas_3d_object.c129
-rw-r--r--src/lib/evas/canvas/evas_3d_scene.c622
-rw-r--r--src/lib/evas/canvas/evas_3d_texture.c440
-rw-r--r--src/lib/evas/canvas/evas_image.eo27
-rw-r--r--src/lib/evas/canvas/evas_object_image.c194
-rw-r--r--src/lib/evas/canvas/evas_object_main.c21
-rw-r--r--src/lib/evas/include/evas_3d_private.h377
-rw-r--r--src/lib/evas/include/evas_3d_utils.h1526
-rw-r--r--src/lib/evas/include/evas_private.h32
17 files changed, 6736 insertions, 5 deletions
diff --git a/src/lib/evas/Evas.h b/src/lib/evas/Evas.h
index dc4d435712..05ac2c01e7 100644
--- a/src/lib/evas/Evas.h
+++ b/src/lib/evas/Evas.h
@@ -292,7 +292,6 @@ extern "C" {
292#ifdef EFL_EO_API_SUPPORT 292#ifdef EFL_EO_API_SUPPORT
293#include <Evas_Eo.h> 293#include <Evas_Eo.h>
294#endif 294#endif
295
296#ifdef __cplusplus 295#ifdef __cplusplus
297} 296}
298#endif 297#endif
diff --git a/src/lib/evas/Evas_3D.h b/src/lib/evas/Evas_3D.h
new file mode 100644
index 0000000000..4a25246531
--- /dev/null
+++ b/src/lib/evas/Evas_3D.h
@@ -0,0 +1,289 @@
1#ifndef _EVAS_3D_H
2#define _EVAS_3D_H
3
4#include <Evas.h>
5
6typedef float Evas_Real;
7
8typedef struct _Evas_3D_Scene Evas_3D_Scene;
9typedef struct _Evas_3D_Node Evas_3D_Node;
10typedef struct _Evas_3D_Camera Evas_3D_Camera;
11typedef struct _Evas_3D_Light Evas_3D_Light;
12typedef struct _Evas_3D_Mesh Evas_3D_Mesh;
13typedef struct _Evas_3D_Texture Evas_3D_Texture;
14typedef struct _Evas_3D_Material Evas_3D_Material;
15
16typedef enum _Evas_3D_Space
17{
18 EVAS_3D_SPACE_LOCAL,
19 EVAS_3D_SPACE_PARENT,
20 EVAS_3D_SPACE_WORLD,
21} Evas_3D_Space;
22
23typedef enum _Evas_3D_Node_Type
24{
25 EVAS_3D_NODE_TYPE_NODE,
26 EVAS_3D_NODE_TYPE_CAMERA,
27 EVAS_3D_NODE_TYPE_LIGHT,
28 EVAS_3D_NODE_TYPE_MESH,
29} Evas_3D_Node_Type;
30
31typedef enum _Evas_3D_Vertex_Attrib
32{
33 EVAS_3D_VERTEX_POSITION,
34 EVAS_3D_VERTEX_NORMAL,
35 EVAS_3D_VERTEX_TANGENT,
36 EVAS_3D_VERTEX_COLOR,
37 EVAS_3D_VERTEX_TEXCOORD,
38} Evas_3D_Vertex_Attrib;
39
40typedef enum _Evas_3D_Index_Format
41{
42 EVAS_3D_INDEX_FORMAT_NONE,
43 EVAS_3D_INDEX_FORMAT_UNSIGNED_BYTE,
44 EVAS_3D_INDEX_FORMAT_UNSIGNED_SHORT,
45} Evas_3D_Index_Format;
46
47typedef enum _Evas_3D_Vertex_Assembly
48{
49 EVAS_3D_VERTEX_ASSEMBLY_POINTS,
50 EVAS_3D_VERTEX_ASSEMBLY_LINES,
51 EVAS_3D_VERTEX_ASSEMBLY_LINE_STRIP,
52 EVAS_3D_VERTEX_ASSEMBLY_LINE_LOOP,
53 EVAS_3D_VERTEX_ASSEMBLY_TRIANGLES,
54 EVAS_3D_VERTEX_ASSEMBLY_TRIANGLE_STRIP,
55 EVAS_3D_VERTEX_ASSEMBLY_TRIANGLE_FAN,
56} Evas_3D_Vertex_Assembly;
57
58typedef enum _Evas_3D_Color_Format
59{
60 EVAS_3D_COLOR_FORMAT_RGBA,
61 EVAS_3D_COLOR_FORMAT_RGB,
62 EVAS_3D_COLOR_FORMAT_ALPHA,
63} Evas_3D_Color_Format;
64
65typedef enum _Evas_3D_Pixel_Format
66{
67 EVAS_3D_PIXEL_FORMAT_8,
68 EVAS_3D_PIXEL_FORMAT_565,
69 EVAS_3D_PIXEL_FORMAT_888,
70 EVAS_3D_PIXEL_FORMAT_8888,
71 EVAS_3D_PIXEL_FORMAT_4444,
72 EVAS_3D_PIXEL_FORMAT_5551,
73} Evas_3D_Pixel_Format;
74
75typedef enum _Evas_3D_Wrap_Mode
76{
77 EVAS_3D_WRAP_MODE_CLAMP,
78 EVAS_3D_WRAP_MODE_REPEAT,
79 EVAS_3D_WRAP_MODE_REFLECT,
80} Evas_3D_Wrap_Mode;
81
82typedef enum _Evas_3D_Texture_Filter
83{
84 EVAS_3D_TEXTURE_FILTER_NEAREST,
85 EVAS_3D_TEXTURE_FILTER_LINEAR,
86 EVAS_3D_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST,
87 EVAS_3D_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST,
88 EVAS_3D_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR,
89 EVAS_3D_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR,
90} Evas_3D_Texture_Filter;
91
92typedef enum _Evas_3D_Shade_Mode
93{
94 EVAS_3D_SHADE_MODE_VERTEX_COLOR,
95 EVAS_3D_SHADE_MODE_DIFFUSE,
96 EVAS_3D_SHADE_MODE_FLAT,
97 EVAS_3D_SHADE_MODE_PHONG,
98 EVAS_3D_SHADE_MODE_NORMAL_MAP,
99} Evas_3D_Shade_Mode;
100
101typedef enum _Evas_3D_Material_Attrib
102{
103 EVAS_3D_MATERIAL_AMBIENT,
104 EVAS_3D_MATERIAL_DIFFUSE,
105 EVAS_3D_MATERIAL_SPECULAR,
106 EVAS_3D_MATERIAL_EMISSION,
107 EVAS_3D_MATERIAL_NORMAL,
108} Evas_3D_Material_Attrib;
109
110typedef enum _Evas_3D_Mesh_File_Type
111{
112 EVAS_3D_MESH_FILE_TYPE_MD2,
113} Evas_3D_Mesh_File_Type;
114
115typedef enum _Evas_3D_Pick_Type
116{
117 EVAS_3D_PICK_NODE,
118 EVAS_3D_PICK_MESH,
119} Evas_3D_Pick_Type;
120
121/* Image object render target */
122EAPI void evas_object_image_3d_scene_set(Evas_Object *obj, Evas_3D_Scene *scene) EINA_ARG_NONNULL(1);
123EAPI Evas_3D_Scene *evas_object_image_3d_scene_get(const Evas_Object *obj) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
124
125/* Scene */
126EAPI Evas_3D_Scene *evas_3d_scene_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
127EAPI void evas_3d_scene_del(Evas_3D_Scene *scene) EINA_ARG_NONNULL(1);
128EAPI Evas *evas_3d_scene_evas_get(const Evas_3D_Scene *scene) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
129
130EAPI void evas_3d_scene_root_node_set(Evas_3D_Scene *scene, Evas_3D_Node *node) EINA_ARG_NONNULL(1);
131EAPI Evas_3D_Node *evas_3d_scene_root_node_get(const Evas_3D_Scene *scene) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
132EAPI void evas_3d_scene_camera_node_set(Evas_3D_Scene *scene, Evas_3D_Node *node) EINA_ARG_NONNULL(1);
133EAPI Evas_3D_Node *evas_3d_scene_camera_node_get(const Evas_3D_Scene *scene) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
134
135EAPI void evas_3d_scene_size_set(Evas_3D_Scene *scene, int w, int h) EINA_ARG_NONNULL(1);
136EAPI void evas_3d_scene_size_get(const Evas_3D_Scene *scene, int *w, int *h) EINA_ARG_NONNULL(1);
137
138EAPI void evas_3d_scene_background_color_set(Evas_3D_Scene *scene, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a) EINA_ARG_NONNULL(1);
139EAPI void evas_3d_scene_background_color_get(const Evas_3D_Scene *scene, Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a) EINA_ARG_NONNULL(1);
140
141EAPI Eina_Bool evas_3d_scene_pick(const Evas_3D_Scene *scene, Evas_Real x, Evas_Real y, Evas_3D_Node **node, Evas_3D_Mesh **mesh, Evas_Real *s, Evas_Real *t) EINA_ARG_NONNULL(1);
142
143/* Node */
144EAPI Evas_3D_Node *evas_3d_node_add(Evas *e, Evas_3D_Node_Type type) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
145EAPI void evas_3d_node_del(Evas_3D_Node *node) EINA_ARG_NONNULL(1);
146EAPI Evas_3D_Node_Type evas_3d_node_type_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
147EAPI Evas *evas_3d_node_evas_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
148
149EAPI void evas_3d_node_member_add(Evas_3D_Node *node, Evas_3D_Node *member) EINA_ARG_NONNULL(1, 2);
150EAPI void evas_3d_node_member_del(Evas_3D_Node *node, Evas_3D_Node *member) EINA_ARG_NONNULL(1, 2);
151EAPI Evas_3D_Node *evas_3d_node_parent_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
152EAPI const Eina_List *evas_3d_node_member_list_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
153
154EAPI void evas_3d_node_position_set(Evas_3D_Node *node, Evas_Real x, Evas_Real y, Evas_Real z) EINA_ARG_NONNULL(1);
155EAPI void evas_3d_node_orientation_set(Evas_3D_Node *node, Evas_Real x, Evas_Real y, Evas_Real z, Evas_Real w) EINA_ARG_NONNULL(1);
156EAPI void evas_3d_node_orientation_euler_set(Evas_3D_Node *node, Evas_Real x, Evas_Real y, Evas_Real z) EINA_ARG_NONNULL(1);
157EAPI void evas_3d_node_orientation_angle_axis_set(Evas_3D_Node *node, Evas_Real angle, Evas_Real x, Evas_Real y, Evas_Real z) EINA_ARG_NONNULL(1);
158EAPI void evas_3d_node_scale_set(Evas_3D_Node *node, Evas_Real x, Evas_Real y, Evas_Real z) EINA_ARG_NONNULL(1);
159
160EAPI void evas_3d_node_position_get(const Evas_3D_Node *node, Evas_3D_Space space, Evas_Real *x, Evas_Real *y, Evas_Real *z) EINA_ARG_NONNULL(1);
161EAPI void evas_3d_node_orientation_get(const Evas_3D_Node *node, Evas_3D_Space space, Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *w) EINA_ARG_NONNULL(1);
162EAPI void evas_3d_node_scale_get(const Evas_3D_Node *node, Evas_3D_Space space, Evas_Real *x, Evas_Real *y, Evas_Real *z) EINA_ARG_NONNULL(1);
163
164EAPI void evas_3d_node_position_inherit_set(Evas_3D_Node *node, Eina_Bool inherit) EINA_ARG_NONNULL(1);
165EAPI void evas_3d_node_orientation_inherit_set(Evas_3D_Node *node, Eina_Bool inherit) EINA_ARG_NONNULL(1);
166EAPI void evas_3d_node_scale_inherit_set(Evas_3D_Node *node, Eina_Bool inherit) EINA_ARG_NONNULL(1);
167
168EAPI Eina_Bool evas_3d_node_position_inherit_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
169EAPI Eina_Bool evas_3d_node_orientation_inherit_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
170EAPI Eina_Bool evas_3d_node_scale_inherit_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
171
172EAPI void evas_3d_node_look_at_set(Evas_3D_Node *node, Evas_3D_Space target_space, Evas_Real x, Evas_Real y, Evas_Real z, Evas_3D_Space up_space, Evas_Real ux, Evas_Real uy, Evas_Real uz) EINA_ARG_NONNULL(1);
173
174EAPI void evas_3d_node_camera_set(Evas_3D_Node *node, Evas_3D_Camera *camera) EINA_ARG_NONNULL(1);
175EAPI Evas_3D_Camera *evas_3d_node_camera_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
176
177EAPI void evas_3d_node_light_set(Evas_3D_Node *node, Evas_3D_Light *light) EINA_ARG_NONNULL(1);
178EAPI Evas_3D_Light *evas_3d_node_light_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
179
180EAPI void evas_3d_node_mesh_add(Evas_3D_Node *node, Evas_3D_Mesh *mesh) EINA_ARG_NONNULL(1);
181EAPI void evas_3d_node_mesh_del(Evas_3D_Node *node, Evas_3D_Mesh *mesh) EINA_ARG_NONNULL(1);
182EAPI const Eina_List *evas_3d_node_mesh_list_get(const Evas_3D_Node *node) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
183EAPI void evas_3d_node_mesh_frame_set(Evas_3D_Node *node, Evas_3D_Mesh *mesh, int frame) EINA_ARG_NONNULL(1);
184EAPI int evas_3d_node_mesh_frame_get(const Evas_3D_Node *node, Evas_3D_Mesh *mesh) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
185
186/* Camera */
187EAPI Evas_3D_Camera *evas_3d_camera_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
188EAPI void evas_3d_camera_del(Evas_3D_Camera *camera) EINA_ARG_NONNULL(1);
189EAPI Evas *evas_3d_camera_evas_get(const Evas_3D_Camera *camera) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
190
191EAPI void evas_3d_camera_projection_matrix_set(Evas_3D_Camera *camera, const Evas_Real *matrix) EINA_ARG_NONNULL(1);
192EAPI void evas_3d_camera_projection_matrix_get(const Evas_3D_Camera *camera, Evas_Real *matrix) EINA_ARG_NONNULL(1, 2);
193EAPI void evas_3d_camera_projection_perspective_set(Evas_3D_Camera *camera, Evas_Real fovy, Evas_Real aspect, Evas_Real near, Evas_Real far) EINA_ARG_NONNULL(1);
194EAPI void evas_3d_camera_projection_frustum_set(Evas_3D_Camera *camera, Evas_Real left, Evas_Real right, Evas_Real bottom, Evas_Real top, Evas_Real near, Evas_Real far) EINA_ARG_NONNULL(1);
195EAPI void evas_3d_camera_projection_ortho_set(Evas_3D_Camera *camera, Evas_Real left, Evas_Real right, Evas_Real bottom, Evas_Real top, Evas_Real near, Evas_Real far) EINA_ARG_NONNULL(1);
196
197/* Light */
198EAPI Evas_3D_Light *evas_3d_light_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
199EAPI void evas_3d_light_del(Evas_3D_Light *light) EINA_ARG_NONNULL(1);
200EAPI Evas *evas_3d_light_evas_get(const Evas_3D_Light *light) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
201
202EAPI void evas_3d_light_directional_set(Evas_3D_Light *light, Eina_Bool directional) EINA_ARG_NONNULL(1);
203EAPI Eina_Bool evas_3d_light_directional_get(const Evas_3D_Light *light) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
204
205EAPI void evas_3d_light_ambient_set(Evas_3D_Light *light, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a) EINA_ARG_NONNULL(1);
206EAPI void evas_3d_light_ambient_get(const Evas_3D_Light *light, Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a) EINA_ARG_NONNULL(1);
207EAPI void evas_3d_light_diffuse_set(Evas_3D_Light *light, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a) EINA_ARG_NONNULL(1);
208EAPI void evas_3d_light_diffuse_get(const Evas_3D_Light *light, Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a) EINA_ARG_NONNULL(1);
209EAPI void evas_3d_light_specular_set(Evas_3D_Light *light, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a) EINA_ARG_NONNULL(1);
210EAPI void evas_3d_light_specular_get(const Evas_3D_Light *light, Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a) EINA_ARG_NONNULL(1);
211EAPI void evas_3d_light_spot_exponent_set(Evas_3D_Light *light, Evas_Real exponent) EINA_ARG_NONNULL(1);
212EAPI Evas_Real evas_3d_light_spot_exponent_get(const Evas_3D_Light *light) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
213EAPI void evas_3d_light_spot_cutoff_set(Evas_3D_Light *light, Evas_Real cutoff) EINA_ARG_NONNULL(1);
214EAPI Evas_Real evas_3d_light_spot_cutoff_get(const Evas_3D_Light *light) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
215EAPI void evas_3d_light_attenuation_set(Evas_3D_Light *light, Evas_Real constant, Evas_Real linear, Evas_Real quadratic) EINA_ARG_NONNULL(1);
216EAPI void evas_3d_light_attenuation_get(const Evas_3D_Light *light, Evas_Real *constant, Evas_Real *linear, Evas_Real *quadratic) EINA_ARG_NONNULL(1);
217
218EAPI void evas_3d_light_attenuation_enable_set(Evas_3D_Light *light, Eina_Bool enable) EINA_ARG_NONNULL(1);
219EAPI Eina_Bool evas_3d_light_attenuation_enable_get(const Evas_3D_Light *light) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
220
221/* Mesh */
222EAPI Evas_3D_Mesh *evas_3d_mesh_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
223EAPI void evas_3d_mesh_del(Evas_3D_Mesh *mesh) EINA_ARG_NONNULL(1);
224EAPI Evas *evas_3d_mesh_evas_get(const Evas_3D_Mesh *mesh) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
225
226EAPI void evas_3d_mesh_shade_mode_set(Evas_3D_Mesh *mesh, Evas_3D_Shade_Mode mode) EINA_ARG_NONNULL(1);
227EAPI Evas_3D_Shade_Mode evas_3d_mesh_shade_mode_get(const Evas_3D_Mesh *mesh) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
228
229EAPI void evas_3d_mesh_file_set(Evas_3D_Mesh *mesh, Evas_3D_Mesh_File_Type type, const char *file, const char *key) EINA_ARG_NONNULL(1);
230
231EAPI void evas_3d_mesh_vertex_count_set(Evas_3D_Mesh *mesh, unsigned int count) EINA_ARG_NONNULL(1);
232EAPI int evas_3d_mesh_vertex_count_get(const Evas_3D_Mesh *mesh) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
233
234EAPI void evas_3d_mesh_frame_add(Evas_3D_Mesh *mesh, int frame) EINA_ARG_NONNULL(1);
235EAPI void evas_3d_mesh_frame_del(Evas_3D_Mesh *mesh, int frame) EINA_ARG_NONNULL(1);
236
237EAPI void evas_3d_mesh_frame_material_set(Evas_3D_Mesh *mesh, int frame, Evas_3D_Material *material) EINA_ARG_NONNULL(1);
238EAPI Evas_3D_Material *evas_3d_mesh_frame_material_get(const Evas_3D_Mesh *mesh, int frame) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
239
240EAPI void evas_3d_mesh_frame_vertex_data_set(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib, int stride, const void *data) EINA_ARG_NONNULL(1);
241EAPI void evas_3d_mesh_frame_vertex_data_copy_set(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib, int stride, const void *data) EINA_ARG_NONNULL(1);
242EAPI void *evas_3d_mesh_frame_vertex_data_map(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
243EAPI void evas_3d_mesh_frame_vertex_data_unmap(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib) EINA_ARG_NONNULL(1);
244EAPI int evas_3d_mesh_frame_vertex_stride_get(const Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
245
246EAPI void evas_3d_mesh_index_data_set(Evas_3D_Mesh *mesh, Evas_3D_Index_Format format, int count, const void *indices) EINA_ARG_NONNULL(1);
247EAPI void evas_3d_mesh_index_data_copy_set(Evas_3D_Mesh *mesh, Evas_3D_Index_Format format, int count, const void *indices) EINA_ARG_NONNULL(1);
248EAPI Evas_3D_Index_Format evas_3d_mesh_index_format_get(const Evas_3D_Mesh *mesh) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
249EAPI int evas_3d_mesh_index_count_get(const Evas_3D_Mesh *mesh) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
250EAPI void *evas_3d_mesh_index_data_map(Evas_3D_Mesh *mesh) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
251EAPI void evas_3d_mesh_index_data_unmap(Evas_3D_Mesh *mesh) EINA_ARG_NONNULL(1);
252
253EAPI void evas_3d_mesh_vertex_assembly_set(Evas_3D_Mesh *mesh, Evas_3D_Vertex_Assembly assembly);
254EAPI Evas_3D_Vertex_Assembly evas_3d_mesh_vertex_assembly_get(const Evas_3D_Mesh *mesh);
255
256/* Texture */
257EAPI Evas_3D_Texture *evas_3d_texture_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
258EAPI void evas_3d_texture_del(Evas_3D_Texture *texture) EINA_ARG_NONNULL(1);
259EAPI Evas *evas_3d_texture_evas_get(const Evas_3D_Texture *texture) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
260
261EAPI void evas_3d_texture_data_set(Evas_3D_Texture *texture, Evas_3D_Color_Format color_format, Evas_3D_Pixel_Format pixel_format, int w, int h, const void *data);
262EAPI void evas_3d_texture_file_set(Evas_3D_Texture *texture, const char *file, const char *key) EINA_ARG_NONNULL(1);
263EAPI void evas_3d_texture_source_set(Evas_3D_Texture *texture, Evas_Object *source) EINA_ARG_NONNULL(1);
264EAPI Evas_3D_Color_Format evas_3d_texture_color_format_get(const Evas_3D_Texture *texture) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
265EAPI void evas_3d_texture_size_get(const Evas_3D_Texture *texture, int *w, int *h) EINA_ARG_NONNULL(1);
266EAPI void evas_3d_texture_wrap_set(Evas_3D_Texture *texture, Evas_3D_Wrap_Mode s, Evas_3D_Wrap_Mode t) EINA_ARG_NONNULL(1);
267EAPI void evas_3d_texture_wrap_get(const Evas_3D_Texture *texture, Evas_3D_Wrap_Mode *s, Evas_3D_Wrap_Mode *t) EINA_ARG_NONNULL(1);
268
269EAPI void evas_3d_texture_filter_set(Evas_3D_Texture *texture, Evas_3D_Texture_Filter min, Evas_3D_Texture_Filter mag) EINA_ARG_NONNULL(1);
270EAPI void evas_3d_texture_filter_get(const Evas_3D_Texture *texture, Evas_3D_Texture_Filter *min, Evas_3D_Texture_Filter *mag) EINA_ARG_NONNULL(1);
271
272/* Material */
273EAPI Evas_3D_Material *evas_3d_material_add(Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
274EAPI void evas_3d_material_del(Evas_3D_Material *material) EINA_ARG_NONNULL(1);
275EAPI Evas *evas_3d_material_evas_get(const Evas_3D_Material *material) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
276
277EAPI void evas_3d_material_enable_set(Evas_3D_Material *material, Evas_3D_Material_Attrib attrib, Eina_Bool enable) EINA_ARG_NONNULL(1);
278EAPI Eina_Bool evas_3d_material_enable_get(const Evas_3D_Material *material, Evas_3D_Material_Attrib attrib) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
279
280EAPI void evas_3d_material_color_set(Evas_3D_Material *material, Evas_3D_Material_Attrib attrib, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a) EINA_ARG_NONNULL(1);
281EAPI void evas_3d_material_color_get(const Evas_3D_Material *material, Evas_3D_Material_Attrib attrib, Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a) EINA_ARG_NONNULL(1);
282
283EAPI void evas_3d_material_shininess_set(Evas_3D_Material *material, Evas_Real shininess) EINA_ARG_NONNULL(1);
284EAPI Evas_Real evas_3d_material_shininess_get(const Evas_3D_Material *material) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
285
286EAPI void evas_3d_material_texture_set(Evas_3D_Material *material, Evas_3D_Material_Attrib attrib, Evas_3D_Texture *texture) EINA_ARG_NONNULL(1);
287EAPI Evas_3D_Texture *evas_3d_material_texture_get(const Evas_3D_Material *material, Evas_3D_Material_Attrib attrib) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
288
289#endif /* _EVAS_3D_H */
diff --git a/src/lib/evas/canvas/evas_3d_camera.c b/src/lib/evas/canvas/evas_3d_camera.c
new file mode 100644
index 0000000000..fba4e7a4e7
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_camera.c
@@ -0,0 +1,159 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include "evas_common_private.h"
7#include "evas_private.h"
8
9static void
10_camera_free(Evas_3D_Object *obj)
11{
12 Evas_3D_Camera *camera = (Evas_3D_Camera *)obj;
13
14 if (camera->nodes)
15 eina_hash_free(camera->nodes);
16
17 free(camera);
18}
19
20static Eina_Bool
21_camera_node_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
22 void *data EINA_UNUSED, void *fdata)
23{
24 Evas_3D_Node *n = *(Evas_3D_Node **)key;
25 evas_3d_object_change(&n->base, EVAS_3D_STATE_NODE_CAMERA, (Evas_3D_Object *)fdata);
26 return EINA_TRUE;
27}
28
29static void
30_camera_change(Evas_3D_Object *obj, Evas_3D_State state EINA_UNUSED,
31 Evas_3D_Object *ref EINA_UNUSED)
32{
33 Evas_3D_Camera *camera = (Evas_3D_Camera *)obj;
34
35 if (camera->nodes)
36 eina_hash_foreach(camera->nodes, _camera_node_change_notify, obj);
37}
38
39static const Evas_3D_Object_Func camera_func =
40{
41 _camera_free,
42 _camera_change,
43 NULL,
44};
45
46void
47evas_3d_camera_node_add(Evas_3D_Camera *camera, Evas_3D_Node *node)
48{
49 int count = 0;
50
51 if (camera->nodes == NULL)
52 {
53 camera->nodes = eina_hash_pointer_new(NULL);
54
55 if (camera->nodes == NULL)
56 {
57 ERR("Failed to create hash table.");
58 return;
59 }
60 }
61 else
62 count = (int)eina_hash_find(camera->nodes, &node);
63
64 eina_hash_set(camera->nodes, &node, (const void *)(count + 1));
65}
66
67void
68evas_3d_camera_node_del(Evas_3D_Camera *camera, Evas_3D_Node *node)
69{
70 int count = 0;
71
72 if (camera->nodes == NULL)
73 {
74 ERR("No node to delete.");
75 return;
76 }
77
78 count = (int)eina_hash_find(camera->nodes, &node);
79
80 if (count == 1)
81 eina_hash_del(camera->nodes, &node, NULL);
82 else
83 eina_hash_set(camera->nodes, &node, (const void *)(count - 1));
84}
85
86Evas_3D_Camera *
87evas_3d_camera_new(Evas *e)
88{
89 Evas_3D_Camera *camera = NULL;
90
91 camera = (Evas_3D_Camera *)calloc(1, sizeof(Evas_3D_Camera));
92
93 if (camera == NULL)
94 {
95 ERR("Failed to allocate memory.");
96 return NULL;
97 }
98
99 evas_3d_object_init(&camera->base, e, EVAS_3D_OBJECT_TYPE_CAMERA, &camera_func);
100 return camera;
101}
102
103EAPI Evas_3D_Camera *
104evas_3d_camera_add(Evas *e)
105{
106 return evas_3d_camera_new(e);
107}
108
109EAPI void
110evas_3d_camera_del(Evas_3D_Camera *camera)
111{
112 evas_3d_object_unreference(&camera->base);
113}
114
115EAPI Evas *
116evas_3d_camera_evas_get(const Evas_3D_Camera *camera)
117{
118 return camera->base.evas;
119}
120
121EAPI void
122evas_3d_camera_projection_matrix_set(Evas_3D_Camera *camera, const Evas_Real *matrix)
123{
124 evas_mat4_array_set(&camera->projection, matrix);
125 evas_3d_object_change(&camera->base, EVAS_3D_STATE_CAMERA_PROJECTION, NULL);
126}
127
128EAPI void
129evas_3d_camera_projection_matrix_get(const Evas_3D_Camera *camera, Evas_Real *matrix)
130{
131 memcpy(matrix, &camera->projection.m[0], sizeof(Evas_Real) * 16);
132}
133
134EAPI void
135evas_3d_camera_projection_perspective_set(Evas_3D_Camera *camera, Evas_Real fovy, Evas_Real aspect, Evas_Real near, Evas_Real far)
136{
137 Evas_Real xmax;
138 Evas_Real ymax;
139
140 ymax = near * (Evas_Real)tan((double)fovy * M_PI / 360.0);
141 xmax = ymax * aspect;
142
143 evas_mat4_frustum_set(&camera->projection, -xmax, xmax, -ymax, ymax, near, far);
144 evas_3d_object_change(&camera->base, EVAS_3D_STATE_CAMERA_PROJECTION, NULL);
145}
146
147EAPI void
148evas_3d_camera_projection_frustum_set(Evas_3D_Camera *camera, Evas_Real left, Evas_Real right, Evas_Real bottom, Evas_Real top, Evas_Real near, Evas_Real far)
149{
150 evas_mat4_frustum_set(&camera->projection, left, right, bottom, top, near, far);
151 evas_3d_object_change(&camera->base, EVAS_3D_STATE_CAMERA_PROJECTION, NULL);
152}
153
154EAPI void
155evas_3d_camera_projection_ortho_set(Evas_3D_Camera *camera, Evas_Real left, Evas_Real right, Evas_Real bottom, Evas_Real top, Evas_Real near, Evas_Real far)
156{
157 evas_mat4_ortho_set(&camera->projection, left, right, bottom, top, near, far);
158 evas_3d_object_change(&camera->base, EVAS_3D_STATE_CAMERA_PROJECTION, NULL);
159}
diff --git a/src/lib/evas/canvas/evas_3d_light.c b/src/lib/evas/canvas/evas_3d_light.c
new file mode 100644
index 0000000000..356e8dd49b
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_light.c
@@ -0,0 +1,273 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include <math.h>
7#include "evas_common_private.h"
8#include "evas_private.h"
9
10static void
11_light_free(Evas_3D_Object *obj)
12{
13 Evas_3D_Light *light = (Evas_3D_Light *)obj;
14
15 if (light->nodes)
16 eina_hash_free(light->nodes);
17
18 free(light);
19}
20
21static Eina_Bool
22_light_node_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
23 void *data EINA_UNUSED, void *fdata)
24{
25 Evas_3D_Node *n = *(Evas_3D_Node **)key;
26 evas_3d_object_change(&n->base, EVAS_3D_STATE_NODE_LIGHT, (Evas_3D_Object *)fdata);
27 return EINA_TRUE;
28}
29
30static void
31_light_change(Evas_3D_Object *obj, Evas_3D_State state EINA_UNUSED,
32 Evas_3D_Object *ref EINA_UNUSED)
33{
34 Evas_3D_Light *light = (Evas_3D_Light *)obj;
35
36 if (light->nodes)
37 eina_hash_foreach(light->nodes, _light_node_change_notify, obj);
38}
39
40static const Evas_3D_Object_Func light_func =
41{
42 _light_free,
43 _light_change,
44 NULL,
45};
46
47void
48evas_3d_light_node_add(Evas_3D_Light *light, Evas_3D_Node *node)
49{
50 int count = 0;
51
52 if (light->nodes == NULL)
53 {
54 light->nodes = eina_hash_pointer_new(NULL);
55
56 if (light->nodes == NULL)
57 {
58 ERR("Failed to create hash table.");
59 return;
60 }
61 }
62 else
63 count = (int)eina_hash_find(light->nodes, &node);
64
65 eina_hash_set(light->nodes, &node, (const void *)(count + 1));
66}
67
68void
69evas_3d_light_node_del(Evas_3D_Light *light, Evas_3D_Node *node)
70{
71 int count = 0;
72
73 if (light->nodes == NULL)
74 {
75 ERR("No node to delete.");
76 return;
77 }
78
79 count = (int)eina_hash_find(light->nodes, &node);
80
81 if (count == 1)
82 eina_hash_del(light->nodes, &node, NULL);
83 else
84 eina_hash_set(light->nodes, &node, (const void *)(count - 1));
85}
86
87Evas_3D_Light *
88evas_3d_light_new(Evas *e)
89{
90 Evas_3D_Light *light = NULL;
91
92 light = (Evas_3D_Light *)calloc(1, sizeof(Evas_3D_Light));
93
94 if (light == NULL)
95 {
96 ERR("Failed to allocate memory.");
97 return NULL;
98 }
99
100 evas_3d_object_init(&light->base, e, EVAS_3D_OBJECT_TYPE_LIGHT, &light_func);
101
102 evas_color_set(&light->ambient, 0.0, 0.0, 0.0, 1.0);
103 evas_color_set(&light->diffuse, 1.0, 1.0, 1.0, 1.0);
104 evas_color_set(&light->specular, 1.0, 1.0, 1.0, 1.0);
105
106 light->spot_exp = 0.0;
107 light->spot_cutoff = 180.0;
108 light->spot_cutoff_cos = -1.0;
109
110 light->atten_const = 1.0;
111 light->atten_linear = 0.0;
112 light->atten_quad = 0.0;
113
114 return light;
115}
116
117EAPI Evas_3D_Light *
118evas_3d_light_add(Evas *e)
119{
120 return evas_3d_light_new(e);
121}
122
123EAPI void
124evas_3d_light_del(Evas_3D_Light *light)
125{
126 evas_3d_object_unreference(&light->base);
127}
128
129EAPI Evas *
130evas_3d_light_evas_get(const Evas_3D_Light *light)
131{
132 return light->base.evas;
133}
134
135EAPI void
136evas_3d_light_directional_set(Evas_3D_Light *light, Eina_Bool directional)
137{
138 if (light->directional != directional)
139 {
140 light->directional = directional;
141 evas_3d_object_change(&light->base, EVAS_3D_STATE_ANY, NULL);
142 }
143}
144
145EAPI Eina_Bool
146evas_3d_light_directional_get(const Evas_3D_Light *light)
147{
148 return light->directional;
149}
150
151EAPI void
152evas_3d_light_ambient_set(Evas_3D_Light *light, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a)
153{
154 light->ambient.r = r;
155 light->ambient.g = g;
156 light->ambient.b = b;
157 light->ambient.a = a;
158
159 evas_3d_object_change(&light->base, EVAS_3D_STATE_LIGHT_AMBIENT, NULL);
160}
161
162EAPI void
163evas_3d_light_ambient_get(const Evas_3D_Light *light,
164 Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a)
165{
166 if (r) *r = light->ambient.r;
167 if (g) *g = light->ambient.g;
168 if (b) *b = light->ambient.b;
169 if (a) *a = light->ambient.a;
170}
171
172EAPI void
173evas_3d_light_diffuse_set(Evas_3D_Light *light, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a)
174{
175 light->diffuse.r = r;
176 light->diffuse.g = g;
177 light->diffuse.b = b;
178 light->diffuse.a = a;
179
180 evas_3d_object_change(&light->base, EVAS_3D_STATE_LIGHT_DIFFUSE, NULL);
181}
182
183EAPI void
184evas_3d_light_diffuse_get(const Evas_3D_Light *light,
185 Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a)
186{
187 if (r) *r = light->diffuse.r;
188 if (g) *g = light->diffuse.g;
189 if (b) *b = light->diffuse.b;
190 if (a) *a = light->diffuse.a;
191}
192
193EAPI void
194evas_3d_light_specular_set(Evas_3D_Light *light, Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a)
195{
196 light->specular.r = r;
197 light->specular.g = g;
198 light->specular.b = b;
199 light->specular.a = a;
200
201 evas_3d_object_change(&light->base, EVAS_3D_STATE_LIGHT_SPECULAR, NULL);
202}
203
204EAPI void
205evas_3d_light_specular_get(const Evas_3D_Light *light,
206 Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a)
207{
208 if (r) *r = light->specular.r;
209 if (g) *g = light->specular.g;
210 if (b) *b = light->specular.b;
211 if (a) *a = light->specular.a;
212}
213
214EAPI void
215evas_3d_light_spot_exponent_set(Evas_3D_Light *light, Evas_Real exponent)
216{
217 light->spot_exp = exponent;
218 evas_3d_object_change(&light->base, EVAS_3D_STATE_LIGHT_SPOT_EXP, NULL);
219}
220
221EAPI Evas_Real
222evas_3d_light_spot_exponent_get(const Evas_3D_Light *light)
223{
224 return light->spot_exp;
225}
226
227EAPI void
228evas_3d_light_spot_cutoff_set(Evas_3D_Light *light, Evas_Real cutoff)
229{
230 light->spot_cutoff = cutoff;
231 light->spot_cutoff_cos = cos(cutoff * M_PI / 180.0);
232 evas_3d_object_change(&light->base, EVAS_3D_STATE_LIGHT_SPOT_CUTOFF, NULL);
233}
234
235EAPI Evas_Real
236evas_3d_light_spot_cutoff_get(const Evas_3D_Light *light)
237{
238 return light->spot_cutoff;
239}
240
241EAPI void
242evas_3d_light_attenuation_set(Evas_3D_Light *light,
243 Evas_Real constant, Evas_Real linear, Evas_Real quadratic)
244{
245 light->atten_const = constant;
246 light->atten_linear = linear;
247 light->atten_quad = quadratic;
248 evas_3d_object_change(&light->base, EVAS_3D_STATE_LIGHT_ATTENUATION, NULL);
249}
250
251EAPI void
252evas_3d_light_attenuation_get(const Evas_3D_Light *light, Evas_Real *constant, Evas_Real *linear, Evas_Real *quadratic)
253{
254 if (constant) *constant = light->atten_const;
255 if (linear) *linear = light->atten_linear;
256 if (quadratic) *quadratic = light->atten_quad;
257}
258
259EAPI void
260evas_3d_light_attenuation_enable_set(Evas_3D_Light *light, Eina_Bool enable)
261{
262 if (light->enable_attenuation != enable)
263 {
264 light->enable_attenuation = enable;
265 evas_3d_object_change(&light->base, EVAS_3D_STATE_LIGHT_ATTENUATION, NULL);
266 }
267}
268
269EAPI Eina_Bool
270evas_3d_light_attenuation_enable_get(const Evas_3D_Light *light)
271{
272 return light->enable_attenuation;
273}
diff --git a/src/lib/evas/canvas/evas_3d_material.c b/src/lib/evas/canvas/evas_3d_material.c
new file mode 100644
index 0000000000..e9a131de91
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_material.c
@@ -0,0 +1,221 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include "evas_common_private.h"
7#include "evas_private.h"
8
9static void
10_material_free(Evas_3D_Object *obj)
11{
12 int i;
13 Evas_3D_Material *material = (Evas_3D_Material *)obj;
14
15 if (material->meshes)
16 eina_hash_free(material->meshes);
17
18 for (i = 0; i < EVAS_3D_MATERIAL_ATTRIB_COUNT; i++)
19 {
20 if (material->attribs[i].texture)
21 {
22 evas_3d_texture_material_del(material->attribs[i].texture, material);
23 evas_3d_object_unreference(&material->attribs[i].texture->base);
24 }
25 }
26
27 free(material);
28}
29
30static Eina_Bool
31_material_mesh_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
32 void *data EINA_UNUSED, void *fdata)
33{
34 Evas_3D_Mesh *m = *(Evas_3D_Mesh **)key;
35 evas_3d_object_change(&m->base, EVAS_3D_STATE_MESH_MATERIAL, (Evas_3D_Object *)fdata);
36 return EINA_TRUE;
37}
38
39static void
40_material_change(Evas_3D_Object *obj, Evas_3D_State state EINA_UNUSED,
41 Evas_3D_Object *ref EINA_UNUSED)
42{
43 Evas_3D_Material *material = (Evas_3D_Material *)obj;
44
45 if (material->meshes)
46 eina_hash_foreach(material->meshes, _material_mesh_change_notify, obj);
47}
48
49static void
50_material_update(Evas_3D_Object *obj)
51{
52 int i;
53 Evas_3D_Material *material = (Evas_3D_Material *)obj;
54
55 for (i = 0; i < EVAS_3D_MATERIAL_ATTRIB_COUNT; i++)
56 {
57 if (material->attribs[i].enable)
58 {
59 if (material->attribs[i].texture)
60 evas_3d_object_update(&material->attribs[i].texture->base);
61 }
62 }
63}
64
65static const Evas_3D_Object_Func material_func =
66{
67 _material_free,
68 _material_change,
69 _material_update,
70};
71
72void
73evas_3d_material_mesh_add(Evas_3D_Material *material, Evas_3D_Mesh *mesh)
74{
75 int count = 0;
76
77 if (material->meshes == NULL)
78 {
79 material->meshes = eina_hash_pointer_new(NULL);
80
81 if (material->meshes == NULL)
82 {
83 ERR("Failed to create hash table.");
84 return;
85 }
86 }
87 else
88 count = (int)eina_hash_find(material->meshes, &mesh);
89
90 eina_hash_set(material->meshes, &mesh, (const void *)(count + 1));
91}
92
93void
94evas_3d_material_mesh_del(Evas_3D_Material *material, Evas_3D_Mesh *mesh)
95{
96 int count = 0;
97
98 if (material->meshes == NULL)
99 {
100 ERR("No mesh to delete.");
101 return;
102 }
103
104 count = (int)eina_hash_find(material->meshes, &mesh);
105
106 if (count == 1)
107 eina_hash_del(material->meshes, &mesh, NULL);
108 else
109 eina_hash_set(material->meshes, &mesh, (const void *)(count - 1));
110}
111
112Evas_3D_Material *
113evas_3d_material_new(Evas *e)
114{
115 Evas_3D_Material *material = NULL;
116
117 material = (Evas_3D_Material *)calloc(1, sizeof(Evas_3D_Material));
118
119 if (material == NULL)
120 {
121 ERR("Failed to allocate memory.");
122 return NULL;
123 }
124
125 evas_3d_object_init(&material->base, e, EVAS_3D_OBJECT_TYPE_MATERIAL, &material_func);
126
127 evas_color_set(&material->attribs[EVAS_3D_MATERIAL_AMBIENT].color, 0.2, 0.2, 0.2, 1.0);
128 evas_color_set(&material->attribs[EVAS_3D_MATERIAL_DIFFUSE].color, 0.8, 0.8, 0.8, 1.0);
129 evas_color_set(&material->attribs[EVAS_3D_MATERIAL_SPECULAR].color, 1.0, 1.0, 1.0, 1.0);
130 evas_color_set(&material->attribs[EVAS_3D_MATERIAL_EMISSION].color, 0.0, 0.0, 0.0, 1.0);
131 material->shininess = 150.0;
132
133 return material;
134}
135
136EAPI Evas_3D_Material *
137evas_3d_material_add(Evas *e)
138{
139 return evas_3d_material_new(e);
140}
141
142EAPI void
143evas_3d_material_del(Evas_3D_Material *material)
144{
145 evas_3d_object_unreference(&material->base);
146}
147
148EAPI Evas *
149evas_3d_material_evas_get(const Evas_3D_Material *material)
150{
151 return material->base.evas;
152}
153
154EAPI void
155evas_3d_material_enable_set(Evas_3D_Material *material, Evas_3D_Material_Attrib attrib,
156 Eina_Bool enable)
157{
158 material->attribs[attrib].enable = enable;
159}
160
161EAPI Eina_Bool
162evas_3d_material_enable_get(const Evas_3D_Material *material, Evas_3D_Material_Attrib attrib)
163{
164 return material->attribs[attrib].enable;
165}
166
167EAPI void
168evas_3d_material_color_set(Evas_3D_Material *material, Evas_3D_Material_Attrib attrib,
169 Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a)
170{
171 evas_color_set(&material->attribs[attrib].color, r, g, b, a);
172 evas_3d_object_change(&material->base, EVAS_3D_STATE_MATERIAL_COLOR, NULL);
173}
174
175EAPI void
176evas_3d_material_color_get(const Evas_3D_Material *material, Evas_3D_Material_Attrib attrib,
177 Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a)
178{
179 if (r) *r = material->attribs[attrib].color.r;
180 if (g) *g = material->attribs[attrib].color.g;
181 if (b) *b = material->attribs[attrib].color.b;
182 if (a) *a = material->attribs[attrib].color.a;
183}
184
185EAPI void
186evas_3d_material_shininess_set(Evas_3D_Material *material, Evas_Real shininess)
187{
188 material->shininess = shininess;
189}
190
191EAPI Evas_Real
192evas_3d_material_shininess_get(const Evas_3D_Material *material)
193{
194 return material->shininess;
195}
196
197EAPI void
198evas_3d_material_texture_set(Evas_3D_Material *material, Evas_3D_Material_Attrib attrib,
199 Evas_3D_Texture *texture)
200{
201 if (material->attribs[attrib].texture != texture)
202 {
203 if (material->attribs[attrib].texture)
204 {
205 evas_3d_texture_material_del(material->attribs[attrib].texture, material);
206 evas_3d_object_unreference(&material->attribs[attrib].texture->base);
207 }
208
209 material->attribs[attrib].texture = texture;
210 evas_3d_texture_material_add(texture, material);
211 evas_3d_object_reference(&texture->base);
212 }
213
214 evas_3d_object_change(&material->base, EVAS_3D_STATE_MATERIAL_TEXTURE, NULL);
215}
216
217EAPI Evas_3D_Texture *
218evas_3d_material_texture_get(const Evas_3D_Material *material, Evas_3D_Material_Attrib attrib)
219{
220 return material->attribs[attrib].texture;
221}
diff --git a/src/lib/evas/canvas/evas_3d_mesh.c b/src/lib/evas/canvas/evas_3d_mesh.c
new file mode 100644
index 0000000000..37d767180f
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_mesh.c
@@ -0,0 +1,828 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include "evas_common_private.h"
7#include "evas_private.h"
8
9static Evas_3D_Mesh_Frame *
10evas_3d_mesh_frame_new(Evas_3D_Mesh *mesh)
11{
12 Evas_3D_Mesh_Frame *frame = NULL;
13
14 frame = (Evas_3D_Mesh_Frame *)calloc(1, sizeof(Evas_3D_Mesh_Frame));
15
16 if (frame == NULL)
17 {
18 ERR("Failed to allocate memory.");
19 return NULL;
20 }
21
22 frame->mesh = mesh;
23 evas_box3_empty_set(&frame->aabb);
24
25 return frame;
26}
27
28static void
29evas_3d_mesh_frame_free(Evas_3D_Mesh_Frame *frame)
30{
31 int i;
32
33 if (frame->material)
34 {
35 evas_3d_material_mesh_del(frame->material, frame->mesh);
36 evas_3d_object_unreference(&frame->material->base);
37 }
38
39 for (i = 0; i < EVAS_3D_VERTEX_ATTRIB_COUNT; i++)
40 {
41 if (frame->vertices[i].owns_data)
42 free(frame->vertices[i].data);
43 }
44
45 free(frame);
46}
47
48static Evas_3D_Mesh_Frame *
49evas_3d_mesh_frame_find(Evas_3D_Mesh *mesh, int frame)
50{
51 Eina_List *l;
52 Evas_3D_Mesh_Frame *f;
53
54 EINA_LIST_FOREACH(mesh->frames, l, f)
55 {
56 if (f->frame == frame)
57 return f;
58 }
59
60 return NULL;
61}
62
63static inline void
64_mesh_init(Evas_3D_Mesh *mesh)
65{
66 mesh->vertex_count = 0;
67 mesh->frame_count = 0;
68 mesh->frames = NULL;
69
70 mesh->index_format = EVAS_3D_INDEX_FORMAT_NONE;
71 mesh->index_count = 0;
72 mesh->indices = NULL;
73 mesh->owns_indices = EINA_FALSE;
74 mesh->assembly = EVAS_3D_VERTEX_ASSEMBLY_TRIANGLES;
75
76 mesh->nodes = NULL;
77}
78
79static inline void
80_mesh_fini(Evas_3D_Mesh *mesh)
81{
82 Eina_List *l;
83 Evas_3D_Mesh_Frame *f;
84
85 if (mesh->frames)
86 {
87 EINA_LIST_FOREACH(mesh->frames, l, f)
88 {
89 evas_3d_mesh_frame_free(f);
90 }
91
92 eina_list_free(mesh->frames);
93 }
94
95 if (mesh->indices && mesh->owns_indices)
96 free(mesh->indices);
97
98 if (mesh->nodes)
99 eina_hash_free(mesh->nodes);
100}
101
102static void
103_mesh_free(Evas_3D_Object *obj)
104{
105 Evas_3D_Mesh *mesh = (Evas_3D_Mesh *)obj;
106 _mesh_fini(mesh);
107 free(mesh);
108}
109
110static Eina_Bool
111_mesh_node_geometry_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
112 void *data EINA_UNUSED, void *fdata)
113{
114 Evas_3D_Node *n = *(Evas_3D_Node **)key;
115 evas_3d_object_change(&n->base, EVAS_3D_STATE_NODE_MESH_GEOMETRY, (Evas_3D_Object *)fdata);
116 return EINA_TRUE;
117}
118
119static Eina_Bool
120_mesh_node_material_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
121 void *data EINA_UNUSED, void *fdata)
122{
123 Evas_3D_Node *n = *(Evas_3D_Node **)key;
124 evas_3d_object_change(&n->base, EVAS_3D_STATE_NODE_MESH_MATERIAL, (Evas_3D_Object *)fdata);
125 return EINA_TRUE;
126}
127
128static void
129_mesh_change(Evas_3D_Object *obj, Evas_3D_State state, Evas_3D_Object *ref EINA_UNUSED)
130{
131 Evas_3D_Mesh *mesh = (Evas_3D_Mesh *)obj;
132
133 if (state == EVAS_3D_STATE_MESH_MATERIAL)
134 {
135 if (mesh->nodes)
136 eina_hash_foreach(mesh->nodes, _mesh_node_material_change_notify, obj);
137 }
138 else
139 {
140 if (mesh->nodes)
141 eina_hash_foreach(mesh->nodes, _mesh_node_geometry_change_notify, obj);
142 }
143}
144
145static void
146_mesh_update(Evas_3D_Object *obj)
147{
148 Eina_List *l;
149 Evas_3D_Mesh_Frame *f;
150 Evas_3D_Mesh *mesh = (Evas_3D_Mesh *)obj;
151
152 EINA_LIST_FOREACH(mesh->frames, l, f)
153 {
154 if (f->material)
155 evas_3d_object_update(&f->material->base);
156 }
157}
158
159static const Evas_3D_Object_Func mesh_func =
160{
161 _mesh_free,
162 _mesh_change,
163 _mesh_update,
164};
165
166void
167evas_3d_mesh_node_add(Evas_3D_Mesh *mesh, Evas_3D_Node *node)
168{
169 int count = 0;
170
171 if (mesh->nodes == NULL)
172 {
173 mesh->nodes = eina_hash_pointer_new(NULL);
174
175 if (mesh->nodes == NULL)
176 {
177 ERR("Failed to create hash table.");
178 return;
179 }
180 }
181 else
182 count = (int)eina_hash_find(mesh->nodes, &node);
183
184 eina_hash_set(mesh->nodes, &node, (const void *)(count + 1));
185}
186
187void
188evas_3d_mesh_node_del(Evas_3D_Mesh *mesh, Evas_3D_Node *node)
189{
190 int count = 0;
191
192 if (mesh->nodes == NULL)
193 {
194 ERR("No node to delete.");
195 return;
196 }
197
198 count = (int)eina_hash_find(mesh->nodes, &node);
199
200 if (count == 1)
201 eina_hash_del(mesh->nodes, &node, NULL);
202 else
203 eina_hash_set(mesh->nodes, &node, (const void *)(count - 1));
204}
205
206Evas_3D_Mesh *
207evas_3d_mesh_new(Evas *e)
208{
209 Evas_3D_Mesh *mesh = NULL;
210
211 mesh = (Evas_3D_Mesh *)malloc(sizeof(Evas_3D_Mesh));
212
213 if (mesh == NULL)
214 {
215 ERR("Failed to allocate memory.");
216 return NULL;
217 }
218
219 evas_3d_object_init(&mesh->base, e, EVAS_3D_OBJECT_TYPE_MESH, &mesh_func);
220 _mesh_init(mesh);
221 return mesh;
222}
223
224EAPI Evas_3D_Mesh *
225evas_3d_mesh_add(Evas *e)
226{
227 return evas_3d_mesh_new(e);
228}
229
230EAPI void
231evas_3d_mesh_del(Evas_3D_Mesh *mesh)
232{
233 evas_3d_object_unreference(&mesh->base);
234}
235
236EAPI Evas *
237evas_3d_mesh_evas_get(const Evas_3D_Mesh *mesh)
238{
239 return mesh->base.evas;
240}
241
242EAPI void
243evas_3d_mesh_shade_mode_set(Evas_3D_Mesh *mesh, Evas_3D_Shade_Mode mode)
244{
245 if (mesh->shade_mode != mode)
246 {
247 mesh->shade_mode = mode;
248 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_SHADE_MODE, NULL);
249 }
250}
251
252EAPI Evas_3D_Shade_Mode
253evas_3d_mesh_shade_mode_get(const Evas_3D_Mesh *mesh)
254{
255 return mesh->shade_mode;
256}
257
258EAPI void
259evas_3d_mesh_vertex_count_set(Evas_3D_Mesh *mesh, unsigned int count)
260{
261 mesh->vertex_count = count;
262 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_VERTEX_COUNT, NULL);
263}
264
265EAPI int
266evas_3d_mesh_vertex_count_get(const Evas_3D_Mesh *mesh)
267{
268 return mesh->vertex_count;
269}
270
271EAPI void
272evas_3d_mesh_frame_add(Evas_3D_Mesh *mesh, int frame)
273{
274 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(mesh, frame);
275
276 if (f != NULL)
277 {
278 ERR("Already existing frame.");
279 return;
280 }
281
282 f = evas_3d_mesh_frame_new(mesh);
283
284 if (f == NULL)
285 return;
286
287 f->frame = frame;
288 mesh->frames = eina_list_append(mesh->frames, f);
289 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_FRAME, NULL);
290}
291
292EAPI void
293evas_3d_mesh_frame_del(Evas_3D_Mesh *mesh, int frame)
294{
295 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(mesh, frame);
296
297 if (f == NULL)
298 {
299 ERR("Not existing mesh frame.");
300 return;
301 }
302
303 mesh->frames = eina_list_remove(mesh->frames, f);
304 evas_3d_mesh_frame_free(f);
305 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_FRAME, NULL);
306}
307
308EAPI void
309evas_3d_mesh_frame_material_set(Evas_3D_Mesh *mesh, int frame, Evas_3D_Material *material)
310{
311 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(mesh, frame);
312
313 if (f == NULL)
314 {
315 ERR("Not existing mesh frame.");
316 return;
317 }
318
319 if (f->material == material)
320 return;
321
322 if (f->material)
323 {
324 evas_3d_material_mesh_del(f->material, mesh);
325 evas_3d_object_unreference(&f->material->base);
326 }
327
328 f->material = material;
329 evas_3d_object_reference(&material->base);
330 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_MATERIAL, NULL);
331 evas_3d_material_mesh_add(material, mesh);
332}
333
334EAPI Evas_3D_Material *
335evas_3d_mesh_frame_material_get(const Evas_3D_Mesh *mesh, int frame)
336{
337 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find((Evas_3D_Mesh *)mesh, frame);
338
339 if (f == NULL)
340 {
341 ERR("Not existing mesh frame.");
342 return NULL;
343 }
344
345 return f->material;
346}
347
348EAPI void
349evas_3d_mesh_frame_vertex_data_set(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib,
350 int stride, const void *data)
351{
352 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(mesh, frame);
353 int element_count;
354
355 if (f == NULL)
356 {
357 ERR("Not existing mesh frame.");
358 return;
359 }
360
361 if (attrib == EVAS_3D_VERTEX_POSITION)
362 {
363 element_count = 3;
364 }
365 else if (attrib == EVAS_3D_VERTEX_NORMAL)
366 {
367 element_count = 3;
368 }
369 else if (attrib == EVAS_3D_VERTEX_TANGENT)
370 {
371 element_count = 3;
372 }
373 else if (attrib == EVAS_3D_VERTEX_COLOR)
374 {
375 element_count = 4;
376 }
377 else if (attrib == EVAS_3D_VERTEX_TEXCOORD)
378 {
379 element_count = 2;
380 }
381 else
382 {
383 ERR("Invalid vertex attrib.");
384 return;
385 }
386
387 if (f->vertices[attrib].owns_data && f->vertices[attrib].data)
388 free(f->vertices[attrib].data);
389
390 f->vertices[attrib].size = 0;
391 f->vertices[attrib].stride = stride;
392 f->vertices[attrib].data = (void *)data;
393 f->vertices[attrib].owns_data = EINA_FALSE;
394 f->vertices[attrib].element_count = element_count;
395
396 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_VERTEX_DATA, NULL);
397}
398
399EAPI void
400evas_3d_mesh_frame_vertex_data_copy_set(Evas_3D_Mesh *mesh, int frame,
401 Evas_3D_Vertex_Attrib attrib,
402 int stride, const void *data)
403{
404 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(mesh, frame);
405 Evas_3D_Vertex_Buffer *vb;
406 int size, element_count;
407
408 if (f == NULL)
409 {
410 ERR("Not existing mesh frame.");
411 return;
412 }
413
414 if (attrib == EVAS_3D_VERTEX_POSITION)
415 {
416 element_count = 3;
417 }
418 else if (attrib == EVAS_3D_VERTEX_NORMAL)
419 {
420 element_count = 3;
421 }
422 else if (attrib == EVAS_3D_VERTEX_TANGENT)
423 {
424 element_count = 3;
425 }
426 else if (attrib == EVAS_3D_VERTEX_COLOR)
427 {
428 element_count = 4;
429 }
430 else if (attrib == EVAS_3D_VERTEX_TEXCOORD)
431 {
432 element_count = 2;
433 }
434 else
435 {
436 ERR("Invalid vertex attrib.");
437 return;
438 }
439
440 vb = &f->vertices[attrib];
441 size = element_count * sizeof(float) * mesh->vertex_count;
442
443 if (!vb->owns_data || vb->size < size)
444 {
445 if (vb->owns_data && vb->data)
446 free(vb->data);
447
448 vb->data = malloc(size);
449
450 if (vb->data == NULL)
451 {
452 vb->element_count = 0;
453 vb->size = 0;
454 vb->stride = 0;
455 vb->owns_data = EINA_FALSE;
456
457 ERR("Failed to allocate memory.");
458 return;
459 }
460
461 vb->size = size;
462 vb->owns_data = EINA_TRUE;
463 }
464
465 vb->element_count = element_count;
466 vb->stride = 0;
467
468 if (data == NULL)
469 return;
470
471 if (stride == 0 || stride == (int)(element_count * sizeof(float)))
472 {
473 memcpy(vb->data, data, size);
474 }
475 else
476 {
477 int i;
478 float *dst = (float *)vb->data;
479 float *src = (float *)data;
480
481 if (element_count == 1)
482 {
483 for (i = 0; i <mesh->vertex_count; i++)
484 {
485 *dst++ = src[0];
486
487 src = (float *)((char *)src + stride);
488 }
489 }
490 else if (element_count == 2)
491 {
492 for (i = 0; i <mesh->vertex_count; i++)
493 {
494 *dst++ = src[0];
495 *dst++ = src[1];
496
497 src = (float *)((char *)src + stride);
498 }
499 }
500 else if (element_count == 3)
501 {
502 for (i = 0; i <mesh->vertex_count; i++)
503 {
504 *dst++ = src[0];
505 *dst++ = src[1];
506 *dst++ = src[2];
507
508 src = (float *)((char *)src + stride);
509 }
510 }
511 else if (element_count == 4)
512 {
513 for (i = 0; i <mesh->vertex_count; i++)
514 {
515 *dst++ = src[0];
516 *dst++ = src[1];
517 *dst++ = src[2];
518 *dst++ = src[3];
519
520 src = (float *)((char *)src + stride);
521 }
522 }
523 }
524
525 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_VERTEX_DATA, NULL);
526}
527
528EAPI void *
529evas_3d_mesh_frame_vertex_data_map(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib)
530{
531 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(mesh, frame);
532
533 if (f == NULL)
534 {
535 ERR("Not existing mesh frame.");
536 return NULL;
537 }
538
539 if (f->vertices[attrib].mapped)
540 {
541 ERR("Try to map alreadly mapped data.");
542 return NULL;
543 }
544
545 f->vertices[attrib].mapped = EINA_TRUE;
546 return f->vertices[attrib].data;
547}
548
549EAPI void
550evas_3d_mesh_frame_vertex_data_unmap(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib)
551{
552 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(mesh, frame);
553
554 if (f == NULL)
555 {
556 ERR("Not existing mesh frame.");
557 return;
558 }
559
560 if (!f->vertices[attrib].mapped)
561 {
562 ERR("Try to unmap data which is not mapped yet.");
563 return;
564 }
565
566 f->vertices[attrib].mapped = EINA_FALSE;
567}
568
569EAPI int
570evas_3d_mesh_frame_vertex_stride_get(const Evas_3D_Mesh *mesh, int frame,
571 Evas_3D_Vertex_Attrib attrib)
572{
573 Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find((Evas_3D_Mesh *)mesh, frame);
574
575 if (f == NULL)
576 {
577 ERR("Not existing mesh frame.");
578 return 0;
579 }
580
581 return f->vertices[attrib].stride;
582}
583
584EAPI void
585evas_3d_mesh_index_data_set(Evas_3D_Mesh *mesh, Evas_3D_Index_Format format, int count,
586 const void *indices)
587{
588 if (mesh->owns_indices && mesh->indices)
589 free(mesh->indices);
590
591 mesh->index_format = format;
592 mesh->index_count = count;
593 mesh->index_size = 0;
594 mesh->indices = (void *)indices;
595 mesh->owns_indices = EINA_FALSE;
596
597 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_INDEX_DATA, NULL);
598}
599
600EAPI void
601evas_3d_mesh_index_data_copy_set(Evas_3D_Mesh *mesh, Evas_3D_Index_Format format, int count, const void *indices)
602{
603 int size;
604
605 if (format == EVAS_3D_INDEX_FORMAT_UNSIGNED_BYTE)
606 {
607 size = count * sizeof(unsigned char);
608 }
609 else if (format == EVAS_3D_INDEX_FORMAT_UNSIGNED_SHORT)
610 {
611 size = count * sizeof(unsigned short);
612 }
613 else
614 {
615 ERR("Invalid index format.");
616 return;
617 }
618
619 if (!mesh->owns_indices || mesh->index_size < size)
620 {
621 if (mesh->owns_indices && mesh->indices)
622 free(mesh->indices);
623
624 mesh->indices = malloc(size);
625
626 if (mesh->indices == NULL)
627 {
628 ERR("Failed to allocate memory.");
629 return;
630 }
631
632 mesh->index_size = size;
633 mesh->owns_indices = EINA_TRUE;
634 }
635
636 mesh->index_format = format;
637 mesh->index_count = count;
638
639 if (indices)
640 memcpy(mesh->indices, indices, size);
641}
642
643EAPI Evas_3D_Index_Format
644evas_3d_mesh_index_format_get(const Evas_3D_Mesh *mesh)
645{
646 return mesh->index_format;
647}
648
649EAPI int
650evas_3d_mesh_index_count_get(const Evas_3D_Mesh *mesh)
651{
652 return mesh->index_count;
653}
654
655EAPI void *
656evas_3d_mesh_index_data_map(Evas_3D_Mesh *mesh)
657{
658 if (mesh->index_mapped)
659 {
660 ERR("Try to map alreadly mapped data.");
661 return NULL;
662 }
663
664 mesh->index_mapped = EINA_TRUE;
665 return mesh->indices;
666}
667
668EAPI void
669evas_3d_mesh_index_data_unmap(Evas_3D_Mesh *mesh)
670{
671 if (!mesh->index_mapped)
672 {
673 ERR("Try to unmap data which is not mapped yet.");
674 return;
675 }
676
677 mesh->index_mapped = EINA_FALSE;
678}
679
680EAPI void
681evas_3d_mesh_vertex_assembly_set(Evas_3D_Mesh *mesh, Evas_3D_Vertex_Assembly assembly)
682{
683 mesh->assembly = assembly;
684 evas_3d_object_change(&mesh->base, EVAS_3D_STATE_MESH_VERTEX_ASSEMBLY, NULL);
685}
686
687EAPI Evas_3D_Vertex_Assembly
688evas_3d_mesh_vertex_assembly_get(const Evas_3D_Mesh *mesh)
689{
690 return mesh->assembly;
691}
692
693EAPI void
694evas_3d_mesh_file_set(Evas_3D_Mesh *mesh, Evas_3D_Mesh_File_Type type,
695 const char *file, const char *key EINA_UNUSED)
696{
697 _mesh_fini(mesh);
698 _mesh_init(mesh);
699
700 if (file == NULL)
701 return;
702
703 switch (type)
704 {
705 case EVAS_3D_MESH_FILE_TYPE_MD2:
706 evas_3d_mesh_file_md2_set(mesh, file);
707 break;
708 default:
709 ERR("Invalid mesh file type.");
710 break;
711 }
712}
713
714static inline void
715_mesh_frame_find(Evas_3D_Mesh *mesh, int frame,
716 Eina_List **l, Eina_List **r)
717{
718 Eina_List *left, *right;
719 Evas_3D_Mesh_Frame *f0, *f1;
720
721 left = mesh->frames;
722 right = eina_list_next(left);
723
724 while (right)
725 {
726 f0 = (Evas_3D_Mesh_Frame *)eina_list_data_get(left);
727 f1 = (Evas_3D_Mesh_Frame *)eina_list_data_get(right);
728
729 if (frame >= f0->frame && frame <= f1->frame)
730 break;
731
732 left = right;
733 right = eina_list_next(left);
734 }
735
736 if (right == NULL)
737 {
738 if (frame <= f0->frame)
739 {
740 *l = NULL;
741 *r = left;
742 }
743 else
744 {
745 *l = left;
746 *r = NULL;
747 }
748 }
749
750 *l = left;
751 *r = right;
752}
753
754void
755evas_3d_mesh_interpolate_vertex_buffer_get(Evas_3D_Mesh *mesh, int frame,
756 Evas_3D_Vertex_Attrib attrib,
757 Evas_3D_Vertex_Buffer *buf0,
758 Evas_3D_Vertex_Buffer *buf1,
759 Evas_Real *weight)
760{
761 Eina_List *l, *r;
762 const Evas_3D_Mesh_Frame *f0 = NULL, *f1 = NULL;
763
764 _mesh_frame_find(mesh, frame, &l, &r);
765
766 while (l)
767 {
768 f0 = (const Evas_3D_Mesh_Frame *)eina_list_data_get(l);
769
770 if (f0->vertices[attrib].data != NULL)
771 break;
772
773 l = eina_list_prev(l);
774 f0 = NULL;
775 }
776
777 while (r)
778 {
779 f1 = (const Evas_3D_Mesh_Frame *)eina_list_data_get(r);
780
781 if (f1->vertices[attrib].data != NULL)
782 break;
783
784 r = eina_list_next(r);
785 f1 = NULL;
786 }
787
788 if (f0 == NULL && f1 == NULL)
789 return;
790
791 if (f0 == NULL)
792 {
793 f0 = f1;
794 }
795 else if (f1 != NULL)
796 {
797 if (frame == f0->frame)
798 {
799 f1 = NULL;
800 }
801 else if (frame == f1->frame)
802 {
803 f0 = f1;
804 f1 = NULL;
805 }
806 }
807
808 buf0->data = f0->vertices[attrib].data;
809 buf0->stride = f0->vertices[attrib].stride;
810 buf0->size = f0->vertices[attrib].size;
811
812 if (f1)
813 {
814 buf1->data = f1->vertices[attrib].data;
815 buf1->stride = f1->vertices[attrib].stride;
816 buf1->size = f1->vertices[attrib].size;
817
818 *weight = (f1->frame - frame) / (Evas_Real)(f1->frame - f0->frame);
819 }
820 else
821 {
822 buf1->data = NULL;
823 buf1->stride = 0;
824 buf1->size = 0;
825
826 *weight = 1.0;
827 }
828}
diff --git a/src/lib/evas/canvas/evas_3d_mesh_loader_md2.c b/src/lib/evas/canvas/evas_3d_mesh_loader_md2.c
new file mode 100644
index 0000000000..7472e27267
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_mesh_loader_md2.c
@@ -0,0 +1,440 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include "evas_common_private.h"
7#include "evas_private.h"
8
9#define PACKED __attribute__((__packed__))
10
11#define MD2_MAGIC_NUMBER 844121161
12#define MD2_VERSION 8
13#define MD2_FRAME_SCALE 256
14
15/* Structures for reading data from file. */
16typedef struct _MD2_Header MD2_Header;
17typedef struct _MD2_Vertex MD2_Vertex;
18typedef struct _MD2_Frame MD2_Frame;
19typedef struct _MD2_Triangle MD2_Triangle;
20typedef struct _MD2_Texcoord MD2_Texcoord;
21
22struct PACKED _MD2_Header
23{
24 int magic;
25 int version;
26
27 int skin_width;
28 int skin_height;
29
30 int frame_size;
31
32 int skins_count;
33 int vertex_count;
34 int texcoord_count;
35 int triangle_count;
36 int glcmd_count;
37 int frame_count;
38
39 int offset_skins;
40 int offset_texcoords;
41 int offset_triangles;
42 int offset_frames;
43 int offset_glcmds;
44 int offset_end;
45};
46
47struct PACKED _MD2_Vertex
48{
49 unsigned char pos[3];
50 unsigned char normal_idx;
51};
52
53struct PACKED _MD2_Frame
54{
55 float scale[3];
56 float trans[3];
57 char name[16];
58 MD2_Vertex vertices[1];
59};
60
61struct PACKED _MD2_Triangle
62{
63 unsigned short vertex_idx[3];
64 unsigned short texcoord_idx[3];
65};
66
67struct PACKED _MD2_Texcoord
68{
69 short s;
70 short t;
71};
72
73typedef struct _MD2_Loader
74{
75 Eina_File *file;
76 char *map;
77 int size;
78
79 int skin_width;
80 int skin_height;
81
82 int frame_count;
83 int frame_size;
84 char *frames;
85
86 int vertex_count;
87 int triangle_count;
88 int texcoord_count;
89
90 MD2_Triangle *triangles;
91 MD2_Texcoord *texcoords;
92} MD2_Loader;
93
94static const float normal_table[162][3] =
95{
96 {-0.525731f, 0.000000f, 0.850651f},
97 {-0.442863f, 0.238856f, 0.864188f},
98 {-0.295242f, 0.000000f, 0.955423f},
99 {-0.309017f, 0.500000f, 0.809017f},
100 {-0.162460f, 0.262866f, 0.951056f},
101 { 0.000000f, 0.000000f, 1.000000f},
102 { 0.000000f, 0.850651f, 0.525731f},
103 {-0.147621f, 0.716567f, 0.681718f},
104 { 0.147621f, 0.716567f, 0.681718f},
105 { 0.000000f, 0.525731f, 0.850651f},
106 { 0.309017f, 0.500000f, 0.809017f},
107 { 0.525731f, 0.000000f, 0.850651f},
108 { 0.295242f, 0.000000f, 0.955423f},
109 { 0.442863f, 0.238856f, 0.864188f},
110 { 0.162460f, 0.262866f, 0.951056f},
111 {-0.681718f, 0.147621f, 0.716567f},
112 {-0.809017f, 0.309017f, 0.500000f},
113 {-0.587785f, 0.425325f, 0.688191f},
114 {-0.850651f, 0.525731f, 0.000000f},
115 {-0.864188f, 0.442863f, 0.238856f},
116 {-0.716567f, 0.681718f, 0.147621f},
117 {-0.688191f, 0.587785f, 0.425325f},
118 {-0.500000f, 0.809017f, 0.309017f},
119 {-0.238856f, 0.864188f, 0.442863f},
120 {-0.425325f, 0.688191f, 0.587785f},
121 {-0.716567f, 0.681718f, -0.147621f},
122 {-0.500000f, 0.809017f, -0.309017f},
123 {-0.525731f, 0.850651f, 0.000000f},
124 { 0.000000f, 0.850651f, -0.525731f},
125 {-0.238856f, 0.864188f, -0.442863f},
126 { 0.000000f, 0.955423f, -0.295242f},
127 {-0.262866f, 0.951056f, -0.162460f},
128 { 0.000000f, 1.000000f, 0.000000f},
129 { 0.000000f, 0.955423f, 0.295242f},
130 {-0.262866f, 0.951056f, 0.162460f},
131 { 0.238856f, 0.864188f, 0.442863f},
132 { 0.262866f, 0.951056f, 0.162460f},
133 { 0.500000f, 0.809017f, 0.309017f},
134 { 0.238856f, 0.864188f, -0.442863f},
135 { 0.262866f, 0.951056f, -0.162460f},
136 { 0.500000f, 0.809017f, -0.309017f},
137 { 0.850651f, 0.525731f, 0.000000f},
138 { 0.716567f, 0.681718f, 0.147621f},
139 { 0.716567f, 0.681718f, -0.147621f},
140 { 0.525731f, 0.850651f, 0.000000f},
141 { 0.425325f, 0.688191f, 0.587785f},
142 { 0.864188f, 0.442863f, 0.238856f},
143 { 0.688191f, 0.587785f, 0.425325f},
144 { 0.809017f, 0.309017f, 0.500000f},
145 { 0.681718f, 0.147621f, 0.716567f},
146 { 0.587785f, 0.425325f, 0.688191f},
147 { 0.955423f, 0.295242f, 0.000000f},
148 { 1.000000f, 0.000000f, 0.000000f},
149 { 0.951056f, 0.162460f, 0.262866f},
150 { 0.850651f, -0.525731f, 0.000000f},
151 { 0.955423f, -0.295242f, 0.000000f},
152 { 0.864188f, -0.442863f, 0.238856f},
153 { 0.951056f, -0.162460f, 0.262866f},
154 { 0.809017f, -0.309017f, 0.500000f},
155 { 0.681718f, -0.147621f, 0.716567f},
156 { 0.850651f, 0.000000f, 0.525731f},
157 { 0.864188f, 0.442863f, -0.238856f},
158 { 0.809017f, 0.309017f, -0.500000f},
159 { 0.951056f, 0.162460f, -0.262866f},
160 { 0.525731f, 0.000000f, -0.850651f},
161 { 0.681718f, 0.147621f, -0.716567f},
162 { 0.681718f, -0.147621f, -0.716567f},
163 { 0.850651f, 0.000000f, -0.525731f},
164 { 0.809017f, -0.309017f, -0.500000f},
165 { 0.864188f, -0.442863f, -0.238856f},
166 { 0.951056f, -0.162460f, -0.262866f},
167 { 0.147621f, 0.716567f, -0.681718f},
168 { 0.309017f, 0.500000f, -0.809017f},
169 { 0.425325f, 0.688191f, -0.587785f},
170 { 0.442863f, 0.238856f, -0.864188f},
171 { 0.587785f, 0.425325f, -0.688191f},
172 { 0.688191f, 0.587785f, -0.425325f},
173 {-0.147621f, 0.716567f, -0.681718f},
174 {-0.309017f, 0.500000f, -0.809017f},
175 { 0.000000f, 0.525731f, -0.850651f},
176 {-0.525731f, 0.000000f, -0.850651f},
177 {-0.442863f, 0.238856f, -0.864188f},
178 {-0.295242f, 0.000000f, -0.955423f},
179 {-0.162460f, 0.262866f, -0.951056f},
180 { 0.000000f, 0.000000f, -1.000000f},
181 { 0.295242f, 0.000000f, -0.955423f},
182 { 0.162460f, 0.262866f, -0.951056f},
183 {-0.442863f, -0.238856f, -0.864188f},
184 {-0.309017f, -0.500000f, -0.809017f},
185 {-0.162460f, -0.262866f, -0.951056f},
186 { 0.000000f, -0.850651f, -0.525731f},
187 {-0.147621f, -0.716567f, -0.681718f},
188 { 0.147621f, -0.716567f, -0.681718f},
189 { 0.000000f, -0.525731f, -0.850651f},
190 { 0.309017f, -0.500000f, -0.809017f},
191 { 0.442863f, -0.238856f, -0.864188f},
192 { 0.162460f, -0.262866f, -0.951056f},
193 { 0.238856f, -0.864188f, -0.442863f},
194 { 0.500000f, -0.809017f, -0.309017f},
195 { 0.425325f, -0.688191f, -0.587785f},
196 { 0.716567f, -0.681718f, -0.147621f},
197 { 0.688191f, -0.587785f, -0.425325f},
198 { 0.587785f, -0.425325f, -0.688191f},
199 { 0.000000f, -0.955423f, -0.295242f},
200 { 0.000000f, -1.000000f, 0.000000f},
201 { 0.262866f, -0.951056f, -0.162460f},
202 { 0.000000f, -0.850651f, 0.525731f},
203 { 0.000000f, -0.955423f, 0.295242f},
204 { 0.238856f, -0.864188f, 0.442863f},
205 { 0.262866f, -0.951056f, 0.162460f},
206 { 0.500000f, -0.809017f, 0.309017f},
207 { 0.716567f, -0.681718f, 0.147621f},
208 { 0.525731f, -0.850651f, 0.000000f},
209 {-0.238856f, -0.864188f, -0.442863f},
210 {-0.500000f, -0.809017f, -0.309017f},
211 {-0.262866f, -0.951056f, -0.162460f},
212 {-0.850651f, -0.525731f, 0.000000f},
213 {-0.716567f, -0.681718f, -0.147621f},
214 {-0.716567f, -0.681718f, 0.147621f},
215 {-0.525731f, -0.850651f, 0.000000f},
216 {-0.500000f, -0.809017f, 0.309017f},
217 {-0.238856f, -0.864188f, 0.442863f},
218 {-0.262866f, -0.951056f, 0.162460f},
219 {-0.864188f, -0.442863f, 0.238856f},
220 {-0.809017f, -0.309017f, 0.500000f},
221 {-0.688191f, -0.587785f, 0.425325f},
222 {-0.681718f, -0.147621f, 0.716567f},
223 {-0.442863f, -0.238856f, 0.864188f},
224 {-0.587785f, -0.425325f, 0.688191f},
225 {-0.309017f, -0.500000f, 0.809017f},
226 {-0.147621f, -0.716567f, 0.681718f},
227 {-0.425325f, -0.688191f, 0.587785f},
228 {-0.162460f, -0.262866f, 0.951056f},
229 { 0.442863f, -0.238856f, 0.864188f},
230 { 0.162460f, -0.262866f, 0.951056f},
231 { 0.309017f, -0.500000f, 0.809017f},
232 { 0.147621f, -0.716567f, 0.681718f},
233 { 0.000000f, -0.525731f, 0.850651f},
234 { 0.425325f, -0.688191f, 0.587785f},
235 { 0.587785f, -0.425325f, 0.688191f},
236 { 0.688191f, -0.587785f, 0.425325f},
237 {-0.955423f, 0.295242f, 0.000000f},
238 {-0.951056f, 0.162460f, 0.262866f},
239 {-1.000000f, 0.000000f, 0.000000f},
240 {-0.850651f, 0.000000f, 0.525731f},
241 {-0.955423f, -0.295242f, 0.000000f},
242 {-0.951056f, -0.162460f, 0.262866f},
243 {-0.864188f, 0.442863f, -0.238856f},
244 {-0.951056f, 0.162460f, -0.262866f},
245 {-0.809017f, 0.309017f, -0.500000f},
246 {-0.864188f, -0.442863f, -0.238856f},
247 {-0.951056f, -0.162460f, -0.262866f},
248 {-0.809017f, -0.309017f, -0.500000f},
249 {-0.681718f, 0.147621f, -0.716567f},
250 {-0.681718f, -0.147621f, -0.716567f},
251 {-0.850651f, 0.000000f, -0.525731f},
252 {-0.688191f, 0.587785f, -0.425325f},
253 {-0.587785f, 0.425325f, -0.688191f},
254 {-0.425325f, 0.688191f, -0.587785f},
255 {-0.425325f, -0.688191f, -0.587785f},
256 {-0.587785f, -0.425325f, -0.688191f},
257 {-0.688191f, -0.587785f, -0.425325f},
258};
259
260static inline void
261_md2_loader_fini(MD2_Loader *loader)
262{
263 if (loader->map)
264 {
265 eina_file_map_free(loader->file, loader->map);
266 loader->map = NULL;
267 }
268
269 if (loader->file)
270 {
271 eina_file_close(loader->file);
272 loader->file = NULL;
273 }
274}
275
276static inline Eina_Bool
277_md2_loader_init(MD2_Loader *loader, const char *file)
278{
279 MD2_Header header;
280
281 memset(loader, 0x00, sizeof(MD2_Loader));
282
283 /* Open given file. */
284 loader->file = eina_file_open(file, 0);
285
286 if (loader->file == NULL)
287 {
288 ERR("Failed to open file %s\n", file);
289 goto error;
290 }
291
292 /* Check file size. We require a file larger than MD2 header size. */
293 loader->size = eina_file_size_get(loader->file);
294
295 if (loader->size < (int)sizeof(MD2_Header))
296 goto error;
297
298 /* Map the file. */
299 loader->map = eina_file_map_all(loader->file, EINA_FILE_SEQUENTIAL);
300
301 if (loader->map == NULL)
302 goto error;
303
304 /* Read header. */
305 memcpy(&header, loader->map, sizeof(MD2_Header));
306
307 /* Check identity */
308 if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION)
309 goto error;
310
311 /* Check offsets */
312 if (header.offset_skins > header.offset_end)
313 goto error;
314
315 if (header.offset_texcoords > header.offset_end)
316 goto error;
317
318 if (header.offset_triangles > header.offset_end)
319 goto error;
320
321 if (header.offset_frames > header.offset_end)
322 goto error;
323
324 if (header.offset_glcmds > header.offset_end)
325 goto error;
326
327 if (header.offset_end > loader->size)
328 goto error;
329
330 loader->skin_width = header.skin_width;
331 loader->skin_height = header.skin_height;
332
333 loader->frame_count = header.frame_count;
334 loader->frame_size = header.frame_size;
335 loader->frames = loader->map + header.offset_frames;
336
337 loader->vertex_count = header.vertex_count;
338 loader->triangle_count = header.triangle_count;
339 loader->texcoord_count = header.texcoord_count;
340
341 loader->triangles = (MD2_Triangle *)(loader->map + header.offset_triangles);
342 loader->texcoords = (MD2_Texcoord *)(loader->map + header.offset_texcoords);
343 return EINA_TRUE;
344
345error:
346 _md2_loader_fini(loader);
347 return EINA_FALSE;
348}
349
350void
351evas_3d_mesh_file_md2_set(Evas_3D_Mesh *mesh, const char *file)
352{
353 MD2_Loader loader;
354 int i, j, k;
355 float *pos, *nor, *tex;
356 int stride_pos, stride_nor, stride_tex;
357 float s_scale, t_scale;
358
359 /* Initialize MD2 loader (Open file and read MD2 head ant etc) */
360 if (!_md2_loader_init(&loader, file))
361 {
362 ERR("Failed to initialize MD2 loader.");
363 return;
364 }
365
366 s_scale = 1.0 / (float)(loader.skin_width - 1);
367 t_scale = 1.0 / (float)(loader.skin_height - 1);
368
369 evas_3d_mesh_vertex_count_set(mesh, loader.triangle_count * 3);
370 evas_3d_mesh_vertex_assembly_set(mesh, EVAS_3D_VERTEX_ASSEMBLY_TRIANGLES);
371
372 /* Load frames */
373 for (i = 0; i < loader.frame_count; i++)
374 {
375 const MD2_Frame *frame = (const MD2_Frame *)(loader.frames + loader.frame_size * i);
376 int f = i * MD2_FRAME_SCALE;
377
378 /* Add a mesh frame. */
379 evas_3d_mesh_frame_add(mesh, f);
380
381 /* Allocate vertex buffer for the frame. */
382 evas_3d_mesh_frame_vertex_data_copy_set(mesh, f, EVAS_3D_VERTEX_POSITION, 0, NULL);
383 evas_3d_mesh_frame_vertex_data_copy_set(mesh, f, EVAS_3D_VERTEX_NORMAL, 0, NULL);
384 evas_3d_mesh_frame_vertex_data_copy_set(mesh, f, EVAS_3D_VERTEX_TEXCOORD, 0, NULL);
385
386 /* Map vertex buffer. */
387 pos = (float *)evas_3d_mesh_frame_vertex_data_map(mesh, f, EVAS_3D_VERTEX_POSITION);
388 nor = (float *)evas_3d_mesh_frame_vertex_data_map(mesh, f, EVAS_3D_VERTEX_NORMAL);
389 tex = (float *)evas_3d_mesh_frame_vertex_data_map(mesh, f, EVAS_3D_VERTEX_TEXCOORD);
390
391 stride_pos = evas_3d_mesh_frame_vertex_stride_get(mesh, f, EVAS_3D_VERTEX_POSITION);
392 stride_nor = evas_3d_mesh_frame_vertex_stride_get(mesh, f, EVAS_3D_VERTEX_NORMAL);
393 stride_tex = evas_3d_mesh_frame_vertex_stride_get(mesh, f, EVAS_3D_VERTEX_TEXCOORD);
394
395 if (stride_pos == 0)
396 stride_pos = sizeof(float) * 3;
397
398 if (stride_nor == 0)
399 stride_nor = sizeof(float) * 3;
400
401 if (stride_tex == 0)
402 stride_tex = sizeof(float) * 2;
403
404 for (j = 0; j < loader.triangle_count; j++)
405 {
406 const MD2_Triangle *tri = &loader.triangles[j];
407
408 for (k = 0; k < 3; k++)
409 {
410 unsigned int tidx, vidx;
411 float *p, *n, *t;
412
413 tidx = tri->texcoord_idx[k];
414 vidx = tri->vertex_idx[k];
415
416 p = (float *)((char *)pos + stride_pos * (j * 3 + k));
417 n = (float *)((char *)nor + stride_nor * (j * 3 + k));
418 t = (float *)((char *)tex + stride_tex * (j * 3 + k));
419
420 p[0] = frame->vertices[vidx].pos[0] * frame->scale[0] + frame->trans[0];
421 p[1] = frame->vertices[vidx].pos[1] * frame->scale[1] + frame->trans[1];
422 p[2] = frame->vertices[vidx].pos[2] * frame->scale[2] + frame->trans[2];
423
424 n[0] = normal_table[frame->vertices[vidx].normal_idx][0];
425 n[1] = normal_table[frame->vertices[vidx].normal_idx][1];
426 n[2] = normal_table[frame->vertices[vidx].normal_idx][2];
427
428 t[0] = loader.texcoords[tidx].s * s_scale;
429 t[1] = 1.0 - loader.texcoords[tidx].t * t_scale;
430 }
431 }
432
433 /* Unmap vertex buffer. */
434 evas_3d_mesh_frame_vertex_data_unmap(mesh, f, EVAS_3D_VERTEX_POSITION);
435 evas_3d_mesh_frame_vertex_data_unmap(mesh, f, EVAS_3D_VERTEX_NORMAL);
436 evas_3d_mesh_frame_vertex_data_unmap(mesh, f, EVAS_3D_VERTEX_TEXCOORD);
437 }
438
439 _md2_loader_fini(&loader);
440}
diff --git a/src/lib/evas/canvas/evas_3d_node.c b/src/lib/evas/canvas/evas_3d_node.c
new file mode 100644
index 0000000000..acbab4a6ab
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_node.c
@@ -0,0 +1,1162 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include "evas_common_private.h"
7#include "evas_private.h"
8
9static inline Evas_3D_Node_Mesh *
10_node_mesh_new(Evas_3D_Node *node, Evas_3D_Mesh *mesh)
11{
12 Evas_3D_Node_Mesh *nm = (Evas_3D_Node_Mesh *)malloc(sizeof(Evas_3D_Node_Mesh));
13
14 if (nm == NULL)
15 {
16 ERR("Failed to allocate memory.");
17 return NULL;
18 }
19
20 nm->node = node;
21 nm->mesh = mesh;
22 nm->frame = 0;
23
24 return nm;
25}
26
27static inline void
28_node_mesh_free(Evas_3D_Node_Mesh *nm)
29{
30 free(nm);
31}
32
33static void
34_node_mesh_free_func(void *data)
35{
36 _node_mesh_free((Evas_3D_Node_Mesh *)data);
37}
38
39static Eina_Bool
40_node_scene_root_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
41 void *data EINA_UNUSED, void *fdata)
42{
43 Evas_3D_Scene *s = *(Evas_3D_Scene **)key;
44 evas_3d_object_change(&s->base, EVAS_3D_STATE_SCENE_ROOT_NODE, (Evas_3D_Object *)fdata);
45 return EINA_TRUE;
46}
47
48static Eina_Bool
49_node_scene_camera_change_notify(const Eina_Hash *hash EINA_UNUSED, const void *key,
50 void *data EINA_UNUSED, void *fdata)
51{
52 Evas_3D_Scene *s = *(Evas_3D_Scene **)key;
53 evas_3d_object_change(&s->base, EVAS_3D_STATE_SCENE_CAMERA_NODE, (Evas_3D_Object *)fdata);
54 return EINA_TRUE;
55}
56
57static void
58_node_change(Evas_3D_Object *obj, Evas_3D_State state EINA_UNUSED, Evas_3D_Object *ref EINA_UNUSED)
59{
60 Evas_3D_Node *node = (Evas_3D_Node *)obj;
61 Eina_List *l;
62 Evas_3D_Node *n;
63
64 /* Notify all scenes using this node that it has changed. */
65 if (node->scenes_root)
66 eina_hash_foreach(node->scenes_root, _node_scene_root_change_notify, obj);
67
68 if (node->scenes_camera)
69 eina_hash_foreach(node->scenes_camera, _node_scene_camera_change_notify, obj);
70
71 /* Notify parent that a member has changed. */
72 if (node->parent)
73 evas_3d_object_change(&node->parent->base, EVAS_3D_STATE_NODE_MEMBER, obj);
74
75 /* Notify members that the parent has changed. */
76 EINA_LIST_FOREACH(node->members, l, n)
77 {
78 evas_3d_object_change(&n->base, EVAS_3D_STATE_NODE_PARENT, obj);
79 }
80}
81
82static Eina_Bool
83_node_transform_update(Evas_3D_Node *node, void *data EINA_UNUSED)
84{
85 if (evas_3d_object_dirty_get(&node->base, EVAS_3D_STATE_NODE_TRANSFORM) ||
86 evas_3d_object_dirty_get(&node->base, EVAS_3D_STATE_NODE_PARENT))
87 {
88 if (node->parent)
89 {
90 const Evas_Vec3 *scale_parent = &node->parent->scale_world;
91 const Evas_Vec4 *orientation_parent = &node->parent->orientation_world;
92
93 /* Orienatation */
94 if (node->orientation_inherit)
95 {
96 evas_vec4_quaternion_multiply(&node->orientation_world,
97 orientation_parent, &node->orientation);
98 }
99 else
100 {
101 node->orientation_world = node->orientation;
102 }
103
104 /* Scale */
105 if (node->scale_inherit)
106 evas_vec3_multiply(&node->scale_world, scale_parent, &node->scale);
107 else
108 node->scale_world = node->scale;
109
110 /* Position */
111 if (node->position_inherit)
112 {
113 evas_vec3_multiply(&node->position_world, &node->position, scale_parent);
114 evas_vec3_quaternion_rotate(&node->position_world, &node->position_world,
115 orientation_parent);
116 evas_vec3_add(&node->position_world, &node->position_world,
117 &node->parent->position_world);
118 }
119 else
120 {
121 node->position_world = node->position;
122 }
123 }
124 else
125 {
126 node->position_world = node->position;
127 node->orientation_world = node->orientation;
128 node->scale_world = node->scale;
129 }
130
131 if (node->type == EVAS_3D_NODE_TYPE_CAMERA)
132 {
133 evas_mat4_inverse_build(&node->data.camera.matrix_world_to_eye,
134 &node->position_world, &node->orientation_world,
135 &node->scale_world);
136 }
137 else if (node->type == EVAS_3D_NODE_TYPE_LIGHT)
138 {
139 }
140 else if (node->type == EVAS_3D_NODE_TYPE_MESH)
141 {
142 evas_mat4_build(&node->data.mesh.matrix_local_to_world,
143 &node->position_world, &node->orientation_world, &node->scale_world);
144 }
145/*
146 if (node->parent)
147 {
148 evas_mat4_nocheck_multiply(&node->matrix_local_to_world,
149 &node->parent->matrix_local_to_world,
150 &node->matrix_local_to_parent);
151 }
152 else
153 {
154 evas_mat4_copy(&node->matrix_local_to_world, &node->matrix_local_to_parent);
155 }*/
156 }
157
158 return EINA_TRUE;
159}
160
161static Eina_Bool
162_node_item_update(Evas_3D_Node *node, void *data EINA_UNUSED)
163{
164 if (node->type == EVAS_3D_NODE_TYPE_CAMERA)
165 {
166 if (node->data.camera.camera)
167 evas_3d_object_update(&node->data.camera.camera->base);
168 }
169 else if (node->type == EVAS_3D_NODE_TYPE_LIGHT)
170 {
171 if (node->data.light.light)
172 evas_3d_object_update(&node->data.light.light->base);
173 }
174 else if (node->type == EVAS_3D_NODE_TYPE_MESH)
175 {
176 Eina_List *l;
177 Evas_3D_Mesh *m;
178
179 EINA_LIST_FOREACH(node->data.mesh.meshes, l, m)
180 {
181 evas_3d_object_update(&m->base);
182 }
183 }
184
185 return EINA_TRUE;
186}
187
188static Eina_Bool
189_node_aabb_update(Evas_3D_Node *node, void *data EINA_UNUSED)
190{
191 if (evas_3d_object_dirty_get(&node->base, EVAS_3D_STATE_NODE_TRANSFORM) ||
192 evas_3d_object_dirty_get(&node->base, EVAS_3D_STATE_NODE_MESH_GEOMETRY) ||
193 evas_3d_object_dirty_get(&node->base, EVAS_3D_STATE_NODE_MESH_FRAME) ||
194 evas_3d_object_dirty_get(&node->base, EVAS_3D_STATE_NODE_MEMBER))
195 {
196 Eina_List *l;
197 Evas_3D_Node *n;
198
199 /* Update AABB of this node. */
200 evas_box3_empty_set(&node->aabb);
201
202 EINA_LIST_FOREACH(node->members, l, n)
203 {
204 evas_box3_union(&node->aabb, &node->aabb, &n->aabb);
205 }
206
207 if (node->type == EVAS_3D_NODE_TYPE_MESH)
208 {
209 /* TODO: */
210 }
211 }
212
213 return EINA_TRUE;
214}
215
216static Eina_Bool
217_node_update_done(Evas_3D_Node *node, void *data EINA_UNUSED)
218{
219 evas_3d_object_update_done(&node->base);
220 return EINA_TRUE;
221}
222
223static void
224_node_update(Evas_3D_Object *obj)
225{
226 Evas_3D_Node *node = (Evas_3D_Node *)obj;
227
228 /* Update transform. */
229 evas_3d_node_tree_traverse(node, EVAS_3D_TREE_TRAVERSE_LEVEL_ORDER, EINA_FALSE,
230 _node_transform_update, NULL);
231
232 /* Update AABB. */
233 evas_3d_node_tree_traverse(node, EVAS_3D_TREE_TRAVERSE_POST_ORDER, EINA_FALSE,
234 _node_aabb_update, NULL);
235
236 /* Update node item. */
237 evas_3d_node_tree_traverse(node, EVAS_3D_TREE_TRAVERSE_ANY_ORDER, EINA_FALSE,
238 _node_item_update, NULL);
239
240 /* Mark all nodes in the tree as up-to-date. */
241 evas_3d_node_tree_traverse(node, EVAS_3D_TREE_TRAVERSE_ANY_ORDER, EINA_FALSE,
242 _node_update_done, NULL);
243}
244
245static void
246_node_free(Evas_3D_Object *obj)
247{
248 Evas_3D_Node *node = (Evas_3D_Node *)obj;
249
250 if (node->members)
251 {
252 Eina_List *l;
253 Evas_3D_Node *n;
254
255 EINA_LIST_FOREACH(node->members, l, n)
256 {
257 evas_3d_object_unreference(&n->base);
258 }
259
260 eina_list_free(node->members);
261 }
262
263 if (node->data.mesh.meshes)
264 {
265 Eina_List *l;
266 Evas_3D_Mesh *m;
267
268 EINA_LIST_FOREACH(node->data.mesh.meshes, l, m)
269 {
270 evas_3d_mesh_node_del(m, node);
271 evas_3d_object_unreference(&m->base);
272 }
273
274 eina_list_free(node->data.mesh.meshes);
275 }
276
277 if (node->data.mesh.node_meshes)
278 eina_hash_free(node->data.mesh.node_meshes);
279
280 if (node->scenes_root)
281 eina_hash_free(node->scenes_root);
282
283 if (node->scenes_camera)
284 eina_hash_free(node->scenes_camera);
285
286 free(node);
287}
288
289static const Evas_3D_Object_Func node_func =
290{
291 _node_free,
292 _node_change,
293 _node_update,
294};
295
296void
297evas_3d_node_scene_root_add(Evas_3D_Node *node, Evas_3D_Scene *scene)
298{
299 int count = 0;
300
301 if (node->scenes_root == NULL)
302 {
303 node->scenes_root = eina_hash_pointer_new(NULL);
304
305 if (node->scenes_root == NULL)
306 {
307 ERR("Failed to create hash table.");
308 return;
309 }
310 }
311 else
312 count = (int)eina_hash_find(node->scenes_root, &scene);
313
314 eina_hash_set(node->scenes_root, &scene, (const void *)(count + 1));
315}
316
317void
318evas_3d_node_scene_root_del(Evas_3D_Node *node, Evas_3D_Scene *scene)
319{
320 int count = 0;
321
322 if (node->scenes_root == NULL)
323 {
324 ERR("No scene to delete.");
325 return;
326 }
327
328 count = (int)eina_hash_find(node->scenes_root, &scene);
329
330 if (count == 1)
331 eina_hash_del(node->scenes_root, &scene, NULL);
332 else
333 eina_hash_set(node->scenes_root, &scene, (const void *)(count - 1));
334}
335
336void
337evas_3d_node_scene_camera_add(Evas_3D_Node *node, Evas_3D_Scene *scene)
338{
339 int count = 0;
340
341 if (node->scenes_camera == NULL)
342 {
343 node->scenes_camera = eina_hash_pointer_new(NULL);
344
345 if (node->scenes_camera == NULL)
346 {
347 ERR("Failed to create hash table.");
348 return;
349 }
350 }
351 else
352 count = (int)eina_hash_find(node->scenes_camera, &scene);
353
354 eina_hash_set(node->scenes_camera, &scene, (const void *)(count + 1));
355}
356
357void
358evas_3d_node_scene_camera_del(Evas_3D_Node *node, Evas_3D_Scene *scene)
359{
360 int count = 0;
361
362 if (node->scenes_camera == NULL)
363 {
364 ERR("No scene to delete.");
365 return;
366 }
367
368 count = (int)eina_hash_find(node->scenes_camera, &scene);
369
370 if (count == 1)
371 eina_hash_del(node->scenes_camera, &scene, NULL);
372 else
373 eina_hash_set(node->scenes_camera, &scene, (const void *)(count - 1));
374}
375
376Evas_3D_Node *
377evas_3d_node_new(Evas *e, Evas_3D_Node_Type type)
378{
379 Evas_3D_Node *node = NULL;
380
381 node = (Evas_3D_Node *)calloc(1, sizeof(Evas_3D_Node));
382
383 if (node == NULL)
384 {
385 ERR("Failed to allocate memory.");
386 return NULL;
387 }
388
389 evas_3d_object_init(&node->base, e, EVAS_3D_OBJECT_TYPE_NODE, &node_func);
390
391 evas_vec3_set(&node->position, 0.0, 0.0, 0.0);
392 evas_vec4_set(&node->orientation, 0.0, 0.0, 0.0, 0.0);
393 evas_vec3_set(&node->scale, 1.0, 1.0, 1.0);
394
395 evas_vec3_set(&node->position_world, 0.0, 0.0, 0.0);
396 evas_vec4_set(&node->orientation_world, 0.0, 0.0, 0.0, 1.0);
397 evas_vec3_set(&node->scale_world, 1.0, 1.0, 1.0);
398
399 node->position_inherit = EINA_TRUE;
400 node->orientation_inherit = EINA_TRUE;
401 node->scale_inherit = EINA_TRUE;
402
403 evas_box3_set(&node->aabb, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
404
405 node->type = type;
406
407 if (type == EVAS_3D_NODE_TYPE_MESH)
408 {
409 node->data.mesh.node_meshes = eina_hash_pointer_new(_node_mesh_free_func);
410
411 if (node->data.mesh.node_meshes == NULL)
412 {
413 ERR("Failed to create node mesh table.");
414 _node_free(&node->base);
415 return NULL;
416 }
417 }
418
419 return node;
420}
421
422void
423evas_3d_node_traverse(Evas_3D_Node *from, Evas_3D_Node *to, Evas_3D_Node_Traverse_Type type,
424 Eina_Bool skip, Evas_3D_Node_Func func, void *data)
425{
426 Eina_List *nodes = NULL, *n;
427 Evas_3D_Node *node = NULL;
428
429 if (from == NULL || func == NULL)
430 goto error;
431
432 if (type == EVAS_3D_NODE_TRAVERSE_DOWNWARD)
433 {
434 if (to == NULL)
435 goto error;
436
437 node = to;
438
439 do {
440 nodes = eina_list_prepend(nodes, (const void *)node);
441
442 if (node == from)
443 break;
444
445 node = node->parent;
446
447 if (node == NULL)
448 goto error;
449 } while (1);
450 }
451 else if (type == EVAS_3D_NODE_TRAVERSE_UPWARD)
452 {
453 node = from;
454
455 do {
456 nodes = eina_list_append(nodes, (const void *)node);
457
458 if (node == to)
459 break;
460
461 node = node->parent;
462
463 if (node == NULL)
464 {
465 if (to == NULL)
466 break;
467
468 goto error;
469 }
470 } while (1);
471 }
472
473 EINA_LIST_FOREACH(nodes, n, node)
474 {
475 if (!func(node, data) && skip)
476 break;
477 }
478
479 eina_list_free(nodes);
480 return;
481
482error:
483 ERR("Node traverse error.");
484
485 if (nodes)
486 eina_list_free(nodes);
487}
488
489void
490evas_3d_node_tree_traverse(Evas_3D_Node *root, Evas_3D_Tree_Traverse_Type type,
491 Eina_Bool skip, Evas_3D_Node_Func func, void *data)
492{
493 Eina_List *nodes = NULL, *l;
494 Evas_3D_Node *node = NULL, *n, *last;
495
496 if (root == NULL || func == NULL)
497 return;
498
499 if (type == EVAS_3D_TREE_TRAVERSE_LEVEL_ORDER)
500 {
501 /* Put the root node in the queue. */
502 nodes = eina_list_append(nodes, root);
503
504 while (eina_list_count(nodes) > 0)
505 {
506 /* Dequeue a node. */
507 node = eina_list_data_get(nodes);
508 nodes = eina_list_remove_list(nodes, nodes);
509
510 /* Call node function on the node. */
511 if (func(node, data) || !skip)
512 {
513 /* Enqueue member nodes. */
514 EINA_LIST_FOREACH(node->members, l, n)
515 {
516 nodes = eina_list_append(nodes, n);
517 }
518 }
519 }
520 }
521 else if (type == EVAS_3D_TREE_TRAVERSE_PRE_ORDER)
522 {
523 /* Put the root node in the stack. */
524 nodes = eina_list_append(nodes, root);
525
526 while (eina_list_count(nodes) > 0)
527 {
528 /* Pop a node from the stack. */
529 node = eina_list_data_get(nodes);
530 nodes = eina_list_remove_list(nodes, nodes);
531
532 /* Call node function on the node. */
533 if (func(node, data) || !skip)
534 {
535 /* Push member nodes into the stack. */
536 EINA_LIST_REVERSE_FOREACH(node->members, l, n)
537 {
538 nodes = eina_list_prepend(nodes, n);
539 }
540 }
541 }
542 }
543 else if (type == EVAS_3D_TREE_TRAVERSE_POST_ORDER)
544 {
545 if (skip)
546 {
547 ERR("Using skip with post order traversal has no effect.");
548 return;
549 }
550
551 /* Put the root node in the stack. */
552 nodes = eina_list_append(nodes, root);
553 last = NULL;
554
555 while (eina_list_count(nodes) > 0)
556 {
557 /* Peek a node from the stack. */
558 node = eina_list_data_get(nodes);
559
560 if (eina_list_count(node->members) == 0)
561 {
562 /* The peeked node is a leaf node,
563 * so visit it and pop from the stack. */
564 func(node, data);
565 nodes = eina_list_remove_list(nodes, nodes);
566
567 /* Save the last visited node. */
568 last = node;
569 }
570 else
571 {
572 /* If the peeked node is not a leaf node,
573 * there can be only two possible cases.
574 *
575 * 1. the parent of the last visited node.
576 * 2. a sibling of the last visited node.
577 *
578 * If the last visited node is a direct child of the peeked node,
579 * we have no unvisted child nodes for the peeked node, so we have to visit
580 * the peeked node and pop from the stack.
581 *
582 * Otherwise it should be a sibling of the peeked node, so we have to push
583 * its childs into the stack. */
584
585 if (last && last->parent == node)
586 {
587 /* Visit the node as it doesn't have any unvisited child node. */
588 func(node, data);
589 nodes = eina_list_remove_list(nodes, nodes);
590
591 /* Save the last visited node. */
592 last = node;
593 }
594 else
595 {
596 /* Push child nodes into the stack. */
597 EINA_LIST_REVERSE_FOREACH(node->members, l, n)
598 {
599 nodes = eina_list_prepend(nodes, n);
600 }
601 }
602 }
603 }
604 }
605
606 if (nodes != NULL)
607 eina_list_free(nodes);
608}
609
610Eina_Bool
611_node_is_visible(Evas_3D_Node *node EINA_UNUSED, Evas_3D_Node *camera_node EINA_UNUSED)
612{
613 /* TODO: */
614 return EINA_TRUE;
615}
616
617Eina_Bool
618evas_3d_node_mesh_collect(Evas_3D_Node *node, void *data)
619{
620 Evas_3D_Scene_Data *scene_data = (Evas_3D_Scene_Data *)data;
621
622 if (!_node_is_visible(node, scene_data->camera_node))
623 {
624 /* Skip entire sub-tree of this node. */
625 return EINA_FALSE;
626 }
627
628 if (node->type == EVAS_3D_NODE_TYPE_MESH)
629 scene_data->mesh_nodes = eina_list_append(scene_data->mesh_nodes, node);
630
631 return EINA_TRUE;
632}
633
634Eina_Bool
635evas_3d_node_light_collect(Evas_3D_Node *node, void *data)
636{
637 Evas_3D_Scene_Data *scene_data = (Evas_3D_Scene_Data *)data;
638
639 if (node->type == EVAS_3D_NODE_TYPE_LIGHT)
640 scene_data->light_nodes = eina_list_append(scene_data->light_nodes, node);
641
642 return EINA_TRUE;
643}
644
645EAPI Evas_3D_Node *
646evas_3d_node_add(Evas *e, Evas_3D_Node_Type type)
647{
648 return evas_3d_node_new(e, type);
649}
650
651EAPI void
652evas_3d_node_del(Evas_3D_Node *node)
653{
654 evas_3d_object_unreference(&node->base);
655}
656
657EAPI Evas_3D_Node_Type
658evas_3d_node_type_get(const Evas_3D_Node *node)
659{
660 return node->type;
661}
662
663EAPI Evas *
664evas_3d_node_evas_get(const Evas_3D_Node *node)
665{
666 return node->base.evas;
667}
668
669EAPI void
670evas_3d_node_member_add(Evas_3D_Node *node, Evas_3D_Node *member)
671{
672 if (node == member)
673 {
674 ERR("Failed to add a member node (adding to itself).");
675 return;
676 }
677
678 if (member->parent == node)
679 return;
680
681 if (member->parent)
682 {
683 /* Detaching from previous parent. */
684 member->parent->members = eina_list_remove(member->parent->members, member);
685
686 /* Mark changed. */
687 evas_3d_object_change(&member->parent->base, EVAS_3D_STATE_NODE_MEMBER, NULL);
688 }
689 else
690 {
691 /* Should get a new reference. */
692 evas_3d_object_reference(&member->base);
693 }
694
695 /* Add the member node. */
696 node->members = eina_list_append(node->members, (const void *)member);
697 member->parent = node;
698
699 /* Mark changed. */
700 evas_3d_object_change(&member->base, EVAS_3D_STATE_NODE_PARENT, NULL);
701 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_MEMBER, NULL);
702}
703
704EAPI void
705evas_3d_node_member_del(Evas_3D_Node *node, Evas_3D_Node *member)
706{
707 if (member->parent != node)
708 {
709 ERR("Failed to delete a member node (not a member of the given node)");
710 return;
711 }
712
713 /* Delete the member node. */
714 node->members = eina_list_remove(node->members, member);
715 member->parent = NULL;
716
717 /* Mark modified object as changed. */
718 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_MEMBER, NULL);
719 evas_3d_object_change(&member->base, EVAS_3D_STATE_NODE_PARENT, NULL);
720
721 /* Decrease reference count. */
722 evas_3d_object_unreference(&member->base);
723}
724
725EAPI Evas_3D_Node *
726evas_3d_node_parent_get(const Evas_3D_Node *node)
727{
728 return node->parent;
729}
730
731EAPI const Eina_List *
732evas_3d_node_member_list_get(const Evas_3D_Node *node)
733{
734 return node->members;
735}
736
737EAPI void
738evas_3d_node_position_set(Evas_3D_Node *node, Evas_Real x, Evas_Real y, Evas_Real z)
739{
740 node->position.x = x;
741 node->position.y = y;
742 node->position.z = z;
743
744 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
745}
746
747EAPI void
748evas_3d_node_orientation_set(Evas_3D_Node *node, Evas_Real x, Evas_Real y, Evas_Real z, Evas_Real w)
749{
750 node->orientation.x = x;
751 node->orientation.y = y;
752 node->orientation.z = z;
753 node->orientation.w = w;
754
755 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
756}
757
758EAPI void
759evas_3d_node_orientation_angle_axis_set(Evas_3D_Node *node,
760 Evas_Real angle, Evas_Real x, Evas_Real y, Evas_Real z)
761{
762 Evas_Real half_angle = 0.5 * DEGREE_TO_RADIAN(angle);
763 Evas_Real s = sin(half_angle);
764 Evas_Vec3 axis;
765
766 evas_vec3_set(&axis, x, y, z);
767 evas_vec3_normalize(&axis, &axis);
768
769 node->orientation.w = cos(half_angle);
770 node->orientation.x = s * axis.x;
771 node->orientation.y = s * axis.y;
772 node->orientation.z = s * axis.z;
773
774 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
775}
776
777EAPI void
778evas_3d_node_scale_set(Evas_3D_Node *node, Evas_Real x, Evas_Real y, Evas_Real z)
779{
780 node->scale.x = x;
781 node->scale.y = y;
782 node->scale.z = z;
783
784 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
785}
786
787EAPI void
788evas_3d_node_position_get(const Evas_3D_Node *node, Evas_3D_Space space,
789 Evas_Real *x, Evas_Real *y, Evas_Real *z)
790{
791 if (space == EVAS_3D_SPACE_LOCAL)
792 {
793 if (x) *x = 0.0;
794 if (y) *y = 0.0;
795 if (z) *z = 0.0;
796 }
797 else if (space == EVAS_3D_SPACE_PARENT)
798 {
799 if (x) *x = node->position.x;
800 if (y) *y = node->position.y;
801 if (z) *z = node->position.z;
802 }
803 else if (space == EVAS_3D_SPACE_WORLD)
804 {
805 evas_3d_object_update((Evas_3D_Object *)&node->base);
806
807 if (x) *x = node->position_world.x;
808 if (y) *y = node->position_world.y;
809 if (z) *z = node->position_world.z;
810 }
811}
812
813EAPI void
814evas_3d_node_orientation_get(const Evas_3D_Node *node, Evas_3D_Space space,
815 Evas_Real *x, Evas_Real *y, Evas_Real *z, Evas_Real *w)
816{
817 if (space == EVAS_3D_SPACE_LOCAL)
818 {
819 if (x) *x = 0.0;
820 if (y) *y = 0.0;
821 if (z) *z = 0.0;
822 if (w) *w = 0.0;
823 }
824 else if (space == EVAS_3D_SPACE_PARENT)
825 {
826 if (x) *x = node->orientation.x;
827 if (y) *y = node->orientation.y;
828 if (z) *z = node->orientation.z;
829 if (w) *w = node->orientation.w;
830 }
831 else if (space == EVAS_3D_SPACE_WORLD)
832 {
833 evas_3d_object_update((Evas_3D_Object *)&node->base);
834
835 if (x) *x = node->orientation_world.x;
836 if (y) *y = node->orientation_world.y;
837 if (z) *z = node->orientation_world.z;
838 if (w) *w = node->orientation_world.w;
839 }
840
841}
842
843EAPI void
844evas_3d_node_scale_get(const Evas_3D_Node *node, Evas_3D_Space space,
845 Evas_Real *x, Evas_Real *y, Evas_Real *z)
846{
847 if (space == EVAS_3D_SPACE_LOCAL)
848 {
849 if (x) *x = 0.0;
850 if (y) *y = 0.0;
851 if (z) *z = 0.0;
852 }
853 else if (space == EVAS_3D_SPACE_PARENT)
854 {
855 if (x) *x = node->scale.x;
856 if (y) *y = node->scale.y;
857 if (z) *z = node->scale.z;
858 }
859 else if (space == EVAS_3D_SPACE_WORLD)
860 {
861 evas_3d_object_update((Evas_3D_Object *)&node->base);
862
863 if (x) *x = node->scale_world.x;
864 if (y) *y = node->scale_world.y;
865 if (z) *z = node->scale_world.z;
866 }
867}
868
869EAPI void
870evas_3d_node_position_inherit_set(Evas_3D_Node *node, Eina_Bool inherit)
871{
872 node->position_inherit = inherit;
873 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
874}
875
876EAPI void
877evas_3d_node_orientation_inherit_set(Evas_3D_Node *node, Eina_Bool inherit)
878{
879 node->orientation_inherit = inherit;
880 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
881}
882
883EAPI void
884evas_3d_node_scale_inherit_set(Evas_3D_Node *node, Eina_Bool inherit)
885{
886 node->scale_inherit = inherit;
887 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
888}
889
890EAPI Eina_Bool
891evas_3d_node_position_inherit_get(const Evas_3D_Node *node)
892{
893 return node->position_inherit;
894}
895
896EAPI Eina_Bool
897evas_3d_node_orientation_inherit_get(const Evas_3D_Node *node)
898{
899 return node->orientation_inherit;
900}
901
902EAPI Eina_Bool
903evas_3d_node_scale_inherit_get(const Evas_3D_Node *node)
904{
905 return node->scale_inherit;
906}
907
908EAPI void
909evas_3d_node_look_at_set(Evas_3D_Node *node,
910 Evas_3D_Space target_space, Evas_Real tx, Evas_Real ty, Evas_Real tz,
911 Evas_3D_Space up_space, Evas_Real ux, Evas_Real uy, Evas_Real uz)
912{
913 Evas_Vec3 target;
914 Evas_Vec3 up;
915 Evas_Vec3 x, y, z;
916
917 /* Target position in parent space. */
918 if (target_space == EVAS_3D_SPACE_LOCAL)
919 {
920 ERR("TODO:");
921 return;
922 }
923 else if (target_space == EVAS_3D_SPACE_PARENT)
924 {
925 evas_vec3_set(&target, tx, ty, tz);
926 }
927 else if (target_space == EVAS_3D_SPACE_WORLD)
928 {
929 ERR("TODO:");
930 return;
931 }
932 else
933 {
934 ERR("Invalid coordinate space.");
935 return;
936 }
937
938 if (up_space == EVAS_3D_SPACE_LOCAL)
939 {
940 ERR("TODO:");
941 return;
942 }
943 else if (up_space == EVAS_3D_SPACE_PARENT)
944 {
945 evas_vec3_set(&up, ux, uy, uz);
946 }
947 else if (up_space == EVAS_3D_SPACE_WORLD)
948 {
949 ERR("TODO:");
950 return;
951 }
952 else
953 {
954 ERR("Invalid coordinate space.");
955 return;
956 }
957
958 /* From now on, everything takes place in parent space. */
959 evas_vec3_subtract(&z, &node->position, &target);
960 evas_vec3_normalize(&z, &z);
961
962 evas_vec3_cross_product(&x, &up, &z);
963 evas_vec3_normalize(&x, &x);
964
965 evas_vec3_cross_product(&y, &z, &x);
966 evas_vec3_normalize(&y, &y);
967
968 Evas_Real w = sqrt(1.0 + x.x + y.y + z.z);
969
970 node->orientation.w = 0.5 * w;
971
972 w = 0.5 / w;
973
974 /* Inverse the axis. */
975 node->orientation.x = (y.z - z.y) * w;
976 node->orientation.y = (z.x - x.z) * w;
977 node->orientation.z = (x.y - y.x) * w;
978
979 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_TRANSFORM, NULL);
980}
981
982EAPI void
983evas_3d_node_camera_set(Evas_3D_Node *node, Evas_3D_Camera *camera)
984{
985 if (node->type != EVAS_3D_NODE_TYPE_CAMERA)
986 {
987 ERR("Node type mismatch.");
988 return;
989 }
990
991 if (node->data.camera.camera == camera)
992 return;
993
994 if (node->data.camera.camera)
995 {
996 /* Detach previous camera object. */
997 evas_3d_camera_node_del(node->data.camera.camera, node);
998 evas_3d_object_unreference(&node->data.camera.camera->base);
999 }
1000
1001 node->data.camera.camera = camera;
1002 evas_3d_object_reference(&camera->base);
1003
1004 /* Register change notification on the camera for this node. */
1005 evas_3d_camera_node_add(camera, node);
1006
1007 /* Mark changed. */
1008 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_CAMERA, NULL);
1009}
1010
1011EAPI Evas_3D_Camera *
1012evas_3d_node_camera_get(const Evas_3D_Node *node)
1013{
1014 return node->data.camera.camera;
1015}
1016
1017EAPI void
1018evas_3d_node_light_set(Evas_3D_Node *node, Evas_3D_Light *light)
1019{
1020 if (node->type != EVAS_3D_NODE_TYPE_LIGHT)
1021 {
1022 ERR("Node type mismatch.");
1023 return;
1024 }
1025
1026 if (node->data.light.light == light)
1027 return;
1028
1029 if (node->data.light.light)
1030 {
1031 /* Detach previous light object. */
1032 evas_3d_light_node_del(node->data.light.light, node);
1033 evas_3d_object_unreference(&node->data.light.light->base);
1034 }
1035
1036 node->data.light.light = light;
1037 evas_3d_object_reference(&light->base);
1038
1039 /* Register change notification on the light for this node. */
1040 evas_3d_light_node_add(light, node);
1041
1042 /* Mark changed. */
1043 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_LIGHT, NULL);
1044}
1045
1046EAPI Evas_3D_Light *
1047evas_3d_node_light_get(const Evas_3D_Node *node)
1048{
1049 return node->data.light.light;
1050}
1051
1052EAPI void
1053evas_3d_node_mesh_add(Evas_3D_Node *node, Evas_3D_Mesh *mesh)
1054{
1055 Evas_3D_Node_Mesh *nm = NULL;
1056
1057 if (node->type != EVAS_3D_NODE_TYPE_MESH)
1058 {
1059 ERR("Node type mismatch.");
1060 return;
1061 }
1062
1063 if (eina_hash_find(node->data.mesh.node_meshes, mesh) != NULL)
1064 {
1065 ERR("The mesh is already added to the node.");
1066 return;
1067 }
1068
1069 if ((nm = _node_mesh_new(node, mesh)) == NULL)
1070 {
1071 ERR("Failed to create node mesh.");
1072 return;
1073 }
1074
1075 /* TODO: Find node mesh and add if it does not exist. */
1076 if (!eina_hash_add(node->data.mesh.node_meshes, mesh, nm))
1077 {
1078 ERR("Failed to add a mesh to mesh table.");
1079 _node_mesh_free(nm);
1080 return;
1081 }
1082
1083 node->data.mesh.meshes = eina_list_append(node->data.mesh.meshes, mesh);
1084 evas_3d_object_reference(&mesh->base);
1085
1086 /* Register change notification. */
1087 evas_3d_mesh_node_add(mesh, node);
1088
1089 /* Mark changed. */
1090 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_MESH_GEOMETRY, NULL);
1091 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_MESH_MATERIAL, NULL);
1092}
1093
1094EAPI void
1095evas_3d_node_mesh_del(Evas_3D_Node *node, Evas_3D_Mesh *mesh)
1096{
1097 if (node->type != EVAS_3D_NODE_TYPE_MESH)
1098 {
1099 ERR("Node type mismatch.");
1100 return;
1101 }
1102
1103 if (!eina_hash_del(node->data.mesh.node_meshes, mesh, NULL))
1104 {
1105 ERR("The given mesh doesn't belong to this node.");
1106 return;
1107 }
1108
1109 node->data.mesh.meshes = eina_list_remove(node->data.mesh.meshes, mesh);
1110 evas_3d_mesh_node_del(mesh, node);
1111 evas_3d_object_unreference(&mesh->base);
1112
1113 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_MESH_GEOMETRY, NULL);
1114 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_MESH_MATERIAL, NULL);
1115}
1116
1117EAPI const Eina_List *
1118evas_3d_node_mesh_list_get(const Evas_3D_Node *node)
1119{
1120 return node->data.mesh.meshes;
1121}
1122
1123EAPI void
1124evas_3d_node_mesh_frame_set(Evas_3D_Node *node, Evas_3D_Mesh *mesh, int frame)
1125{
1126 Evas_3D_Node_Mesh *nm = NULL;
1127
1128 if (node->type != EVAS_3D_NODE_TYPE_MESH)
1129 {
1130 ERR("Node type mismatch.");
1131 return;
1132 }
1133
1134 if ((nm = eina_hash_find(node->data.mesh.node_meshes, mesh)) == NULL)
1135 {
1136 ERR("The given mesh doesn't belongs to this node.");
1137 return;
1138 }
1139
1140 nm->frame = frame;
1141 evas_3d_object_change(&node->base, EVAS_3D_STATE_NODE_MESH_FRAME, NULL);
1142}
1143
1144EAPI int
1145evas_3d_node_mesh_frame_get(const Evas_3D_Node *node, Evas_3D_Mesh *mesh)
1146{
1147 Evas_3D_Node_Mesh *nm = NULL;
1148
1149 if (node->type != EVAS_3D_NODE_TYPE_MESH)
1150 {
1151 ERR("Node type mismatch.");
1152 return 0;
1153 }
1154
1155 if ((nm = eina_hash_find(node->data.mesh.node_meshes, mesh)) == NULL)
1156 {
1157 ERR("The given mesh doesn't belongs to this node.");
1158 return 0;
1159 }
1160
1161 return nm->frame;
1162}
diff --git a/src/lib/evas/canvas/evas_3d_object.c b/src/lib/evas/canvas/evas_3d_object.c
new file mode 100644
index 0000000000..75bd241519
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_object.c
@@ -0,0 +1,129 @@
1#include "evas_common_private.h"
2#include "evas_private.h"
3
4#define REF_COUNT_CHECK(obj) \
5 do { \
6 if ((obj)->ref_count < 1) \
7 { \
8 ERR("Invalid reference count.")
9
10#define REF_COUNT_CHECK_END() \
11 } \
12 } while (0)
13
14#define OBJ_TYPE_CHECK(obj, type) \
15 do { \
16 if ((obj)->type != type) \
17 { \
18 ERR("3D object type check failed.")
19
20#define OBJ_TYPE_CHECK_END() \
21 } \
22 } while (0)
23
24void
25evas_3d_object_init(Evas_3D_Object *obj,
26 Evas *e, Evas_3D_Object_Type type, const Evas_3D_Object_Func *func)
27{
28 obj->evas = e;
29 obj->type = type;
30 obj->ref_count = 1;
31 obj->func = *func;
32 memset(&obj->dirty[0], 0x00, sizeof(Eina_Bool) * EVAS_3D_STATE_MAX);
33}
34
35void
36evas_3d_object_reference(Evas_3D_Object *obj)
37{
38 REF_COUNT_CHECK(obj);
39 return;
40 REF_COUNT_CHECK_END();
41
42 obj->ref_count++;
43}
44
45void
46evas_3d_object_unreference(Evas_3D_Object *obj)
47{
48 if (obj->ref_count < 1)
49 {
50 printf("gotcha\n");
51 }
52
53 REF_COUNT_CHECK(obj);
54 return;
55 REF_COUNT_CHECK_END();
56
57 obj->ref_count--;
58
59 if (obj->ref_count == 0)
60 obj->func.free(obj);
61}
62
63int
64evas_3d_object_reference_count_get(const Evas_3D_Object *obj)
65{
66 REF_COUNT_CHECK(obj);
67 return 0;
68 REF_COUNT_CHECK_END();
69
70 return obj->ref_count;
71}
72
73Evas *
74evas_3d_object_evas_get(const Evas_3D_Object *obj)
75{
76 REF_COUNT_CHECK(obj);
77 return NULL;
78 REF_COUNT_CHECK_END();
79
80 return obj->evas;
81}
82
83Evas_3D_Object_Type
84evas_3d_object_type_get(const Evas_3D_Object *obj)
85{
86 REF_COUNT_CHECK(obj);
87 return EVAS_3D_OBJECT_TYPE_INVALID;
88 REF_COUNT_CHECK_END();
89
90 return obj->type;
91}
92
93Eina_Bool
94evas_3d_object_dirty_get(const Evas_3D_Object *obj, Evas_3D_State state)
95{
96 return obj->dirty[state];
97}
98
99void
100evas_3d_object_change(Evas_3D_Object *obj, Evas_3D_State state, Evas_3D_Object *ref)
101{
102 /* Skip already dirty properties. */
103 if (obj->dirty[state])
104 return;
105
106 obj->dirty[state] = EINA_TRUE;
107 obj->dirty[EVAS_3D_STATE_ANY] = EINA_TRUE;
108
109 if (obj->func.change)
110 obj->func.change(obj, state, ref);
111}
112
113void
114evas_3d_object_update(Evas_3D_Object *obj)
115{
116 if (!obj->dirty[EVAS_3D_STATE_ANY])
117 return;
118
119 if (obj->func.update)
120 obj->func.update(obj);
121
122 evas_3d_object_update_done(obj);
123}
124
125void
126evas_3d_object_update_done(Evas_3D_Object *obj)
127{
128 memset(&obj->dirty[0], 0x00, sizeof(Eina_Bool) * EVAS_3D_STATE_MAX);
129}
diff --git a/src/lib/evas/canvas/evas_3d_scene.c b/src/lib/evas/canvas/evas_3d_scene.c
new file mode 100644
index 0000000000..3327fee559
--- /dev/null
+++ b/src/lib/evas/canvas/evas_3d_scene.c
@@ -0,0 +1,622 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdlib.h>
6#include "evas_common_private.h"
7#include "evas_private.h"
8
9void
10evas_3d_scene_data_init(Evas_3D_Scene_Data *data)
11{
12 data->camera_node = NULL;
13 data->light_nodes = NULL;
14 data->mesh_nodes = NULL;
15}
16
17void
18evas_3d_scene_data_fini(Evas_3D_Scene_Data *data)
19{
20 if (data->light_nodes)
21 eina_list_free(data->light_nodes);
22
23 if (data->mesh_nodes)
24 eina_list_free(data->mesh_nodes);
25}
26
27static void
28_scene_change(Evas_3D_Object *obj, Evas_3D_State state EINA_UNUSED, Evas_3D_Object *ref EINA_UNUSED)
29{
30 Evas_3D_Scene *scene = (Evas_3D_Scene *)obj;
31 Eina_List *l;
32 Evas_Object *eo;
33
34 EINA_LIST_FOREACH(scene->images, l, eo)
35 {
36 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo, EVAS_OBJ_CLASS);
37 evas_object_change(eo, obj);
38 }
39}
40
41static void
42_scene_update(Evas_3D_Object *obj)
43{
44 Evas_3D_Scene *scene = (Evas_3D_Scene *)obj;
45
46 if (scene->root_node)
47 evas_3d_object_update(&scene->root_node->base);
48
49 if (scene->camera_node)
50 evas_3d_object_update(&scene->camera_node->base);
51}
52
53static void
54_scene_free(Evas_3D_Object *obj)
55{
56 Evas_3D_Scene *scene = (Evas_3D_Scene *)obj;
57
58 if (scene->root_node)
59 {
60 evas_3d_node_scene_root_del(scene->root_node, scene);
61 evas_3d_object_unreference(&scene->root_node->base);
62 }
63
64 if (scene->camera_node)
65 {
66 evas_3d_node_scene_camera_del(scene->camera_node, scene);
67 evas_3d_object_unreference(&scene->camera_node->base);
68 }
69
70 if (scene->images)
71 eina_list_free(scene->images);
72
73 free(scene);
74}
75
76static const Evas_3D_Object_Func scene_func =
77{
78 _scene_free,
79 _scene_change,
80 _scene_update,
81};
82
83Evas_3D_Scene *
84evas_3d_scene_new(Evas *e)
85{
86 Evas_3D_Scene *scene = NULL;
87
88 scene = (Evas_3D_Scene *)calloc(1, sizeof(Evas_3D_Scene));
89
90 if (scene == NULL)
91 {
92 ERR("Failed to allocate memory.");
93 return NULL;
94 }
95
96 evas_3d_object_init(&scene->base, e, EVAS_3D_OBJECT_TYPE_SCENE, &scene_func);
97 evas_color_set(&scene->bg_color, 0.0, 0.0, 0.0, 0.0);
98
99 return scene;
100}
101
102EAPI Evas_3D_Scene *
103evas_3d_scene_add(Evas *e)
104{
105 return evas_3d_scene_new(e);
106}
107
108EAPI void
109evas_3d_scene_del(Evas_3D_Scene *scene)
110{
111 evas_3d_object_unreference(&scene->base);
112}
113
114EAPI Evas *
115evas_3d_scene_evas_get(const Evas_3D_Scene *scene)
116{
117 return scene->base.evas;
118}
119
120EAPI void
121evas_3d_scene_root_node_set(Evas_3D_Scene *scene, Evas_3D_Node *node)
122{
123 if (scene->root_node == node)
124 return;
125
126 if (scene->root_node)
127 {
128 evas_3d_node_scene_root_del(scene->root_node, scene);
129 evas_3d_object_unreference(&scene->root_node->base);
130 }
131
132 scene->root_node = node;
133
134 if (node)
135 {
136 evas_3d_object_reference(&node->base);
137 evas_3d_node_scene_root_add(node, scene);
138 }
139
140 evas_3d_object_change(&scene->base, EVAS_3D_STATE_SCENE_ROOT_NODE, NULL);
141}
142
143EAPI Evas_3D_Node *
144evas_3d_scene_root_node_get(const Evas_3D_Scene *scene)
145{
146 return scene->root_node;
147}
148
149EAPI void
150evas_3d_scene_camera_node_set(Evas_3D_Scene *scene, Evas_3D_Node *node)
151{
152 if (scene->camera_node == node)
153 return;
154
155 if (scene->camera_node)
156 {
157 evas_3d_node_scene_camera_del(scene->camera_node, scene);
158 evas_3d_object_unreference(&scene->camera_node->base);
159 }
160
161 scene->camera_node = node;
162
163 if (node)
164 {
165 evas_3d_object_reference(&node->base);
166 evas_3d_node_scene_camera_add(node, scene);
167 }
168
169 evas_3d_object_change(&scene->base, EVAS_3D_STATE_SCENE_CAMERA_NODE, NULL);
170}
171
172EAPI Evas_3D_Node *
173evas_3d_scene_camera_node_get(const Evas_3D_Scene *scene)
174{
175 return scene->camera_node;
176}
177
178EAPI void
179evas_3d_scene_size_set(Evas_3D_Scene *scene, int w, int h)
180{
181 scene->w = w;
182 scene->h = h;
183 evas_3d_object_change(&scene->base, EVAS_3D_STATE_SCENE_SIZE, NULL);
184}
185
186EAPI void
187evas_3d_scene_size_get(const Evas_3D_Scene *scene, int *w, int *h)
188{
189 if (w) *w = scene->w;
190 if (h) *h = scene->h;
191}
192
193EAPI void
194evas_3d_scene_background_color_set(Evas_3D_Scene *scene,
195 Evas_Real r, Evas_Real g, Evas_Real b, Evas_Real a)
196{
197 evas_color_set(&scene->bg_color, r, g, b, a);
198 evas_3d_object_change(&scene->base, EVAS_3D_STATE_SCENE_BACKGROUND_COLOR, NULL);
199}
200
201EAPI void
202evas_3d_scene_background_color_get(const Evas_3D_Scene *scene,
203 Evas_Real *r, Evas_Real *g, Evas_Real *b, Evas_Real *a)
204{
205 if (r) *r = scene->bg_color.r;
206 if (g) *g = scene->bg_color.g;
207 if (b) *b = scene->bg_color.b;
208 if (a) *a = scene->bg_color.a;
209}
210
211static inline Eina_Bool
212_pick_data_triangle_add(Evas_3D_Pick_Data *data, const Evas_Ray3 *ray,
213 const Evas_Triangle3 *tri)
214{
215 Evas_Vec3 e1, e2, tvec, pvec, qvec;
216 Evas_Real det, inv_det, u, v, t;
217
218 evas_vec3_subtract(&e1, &tri->p1, &tri->p0);
219 evas_vec3_subtract(&e2, &tri->p2, &tri->p0);
220
221 evas_vec3_cross_product(&pvec, &ray->dir, &e2);
222 det = evas_vec3_dot_product(&e1, &pvec);
223
224 /* If determinant is near zero, ray lies in plane of triangle. */
225 if (det > -0.0000001 && det < 0.0000001)
226 return EINA_FALSE;
227
228 inv_det = 1.0 / det;
229
230 /* Calculate distance from p0 to ray origin. */
231 evas_vec3_subtract(&tvec, &ray->org, &tri->p0);
232
233 /* Calculate U parameter and test bounds. */
234 u = evas_vec3_dot_product(&tvec, &pvec) * inv_det;
235
236 if (u < 0.0 || u > 1.0)
237 return EINA_FALSE;