forked from enlightenment/efl
evas: Evas_3D - add .obj export/import.
@feature Reviewers: raster, Hermet, cedric Reviewed By: cedric CC: cedric Differential Revision: https://phab.enlightenment.org/D954 Signed-off-by: Cedric BAIL <c.bail@partner.samsung.com>
This commit is contained in:
parent
125bbf67b9
commit
700f4396e1
|
@ -295,7 +295,9 @@ lib/evas/canvas/evas_3d_light.c \
|
||||||
lib/evas/canvas/evas_3d_mesh.c \
|
lib/evas/canvas/evas_3d_mesh.c \
|
||||||
lib/evas/canvas/evas_3d_texture.c \
|
lib/evas/canvas/evas_3d_texture.c \
|
||||||
lib/evas/canvas/evas_3d_material.c \
|
lib/evas/canvas/evas_3d_material.c \
|
||||||
lib/evas/canvas/evas_3d_mesh_loader_md2.c
|
lib/evas/canvas/evas_3d_mesh_loader_md2.c \
|
||||||
|
lib/evas/canvas/evas_3d_mesh_loader_obj.c \
|
||||||
|
lib/evas/canvas/evas_3d_mesh_saver_obj.c
|
||||||
|
|
||||||
# Engine
|
# Engine
|
||||||
lib_evas_libevas_la_SOURCES += \
|
lib_evas_libevas_la_SOURCES += \
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
/**
|
||||||
|
* Simple Evas example illustrating import/export of .obj format.
|
||||||
|
*
|
||||||
|
* Read mesh from "man_mesh.obj".
|
||||||
|
* After that cheange some properties of material.
|
||||||
|
* After that save material to "saved_man.mtl"
|
||||||
|
* and geometry to "saved_man.obj".
|
||||||
|
*
|
||||||
|
* @verbatim
|
||||||
|
* gcc -o evas-3d-obj evas-3d-obj.c `pkg-config --libs --cflags evas ecore ecore-evas`
|
||||||
|
* @endverbatim
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EFL_EO_API_SUPPORT
|
||||||
|
#define EFL_BETA_API_SUPPORT
|
||||||
|
|
||||||
|
#include <Eo.h>
|
||||||
|
#include <Evas.h>
|
||||||
|
#include <Ecore.h>
|
||||||
|
#include <Ecore_Evas.h>
|
||||||
|
|
||||||
|
#define WIDTH 1024
|
||||||
|
#define HEIGHT 1024
|
||||||
|
|
||||||
|
Ecore_Evas *ecore_evas = NULL;
|
||||||
|
Evas *evas = NULL;
|
||||||
|
Eo *background = NULL;
|
||||||
|
Eo *image = NULL;
|
||||||
|
|
||||||
|
Eo *scene = NULL;
|
||||||
|
Eo *root_node = NULL;
|
||||||
|
Eo *camera_node = NULL;
|
||||||
|
Eo *light_node = NULL;
|
||||||
|
Eo *camera = NULL;
|
||||||
|
Eo *mesh_node = NULL;
|
||||||
|
Eo *mesh = NULL;
|
||||||
|
Eo *material = NULL;
|
||||||
|
Eo *texture = NULL;
|
||||||
|
Eo *light = NULL;
|
||||||
|
|
||||||
|
static float angle = 0;
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_animate_scene(void *data)
|
||||||
|
{
|
||||||
|
angle += 0.5;
|
||||||
|
|
||||||
|
eo_do((Evas_3D_Node *)data, evas_3d_node_orientation_angle_axis_set(angle, 1.0, 1.0, 1.0));
|
||||||
|
|
||||||
|
/* Rotate */
|
||||||
|
if (angle > 360.0) angle -= 360.0f;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_on_delete(Ecore_Evas *ee EINA_UNUSED)
|
||||||
|
{
|
||||||
|
ecore_main_loop_quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_on_canvas_resize(Ecore_Evas *ee)
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
|
||||||
|
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
|
||||||
|
eo_do(background, evas_obj_size_set(w, h));
|
||||||
|
eo_do(image, evas_obj_size_set(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
//Unless Evas 3D supports Software renderer, we set gl backened forcely.
|
||||||
|
setenv("ECORE_EVAS_ENGINE", "opengl_x11", 1);
|
||||||
|
|
||||||
|
if (!ecore_evas_init()) return 0;
|
||||||
|
|
||||||
|
ecore_evas = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
|
||||||
|
|
||||||
|
if (!ecore_evas) return 0;
|
||||||
|
|
||||||
|
ecore_evas_callback_delete_request_set(ecore_evas, _on_delete);
|
||||||
|
ecore_evas_callback_resize_set(ecore_evas, _on_canvas_resize);
|
||||||
|
ecore_evas_show(ecore_evas);
|
||||||
|
|
||||||
|
evas = ecore_evas_get(ecore_evas);
|
||||||
|
|
||||||
|
/* Add a scene object .*/
|
||||||
|
scene = eo_add(EVAS_3D_SCENE_CLASS, evas);
|
||||||
|
|
||||||
|
/* Add the root node for the scene. */
|
||||||
|
root_node = eo_add_custom(EVAS_3D_NODE_CLASS, evas,
|
||||||
|
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_NODE));
|
||||||
|
|
||||||
|
/* Add the camera. */
|
||||||
|
camera = eo_add(EVAS_3D_CAMERA_CLASS, evas);
|
||||||
|
eo_do(camera,
|
||||||
|
evas_3d_camera_projection_perspective_set(60.0, 1.0, 1.0, 500.0));
|
||||||
|
|
||||||
|
camera_node =
|
||||||
|
eo_add_custom(EVAS_3D_NODE_CLASS, evas,
|
||||||
|
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_CAMERA));
|
||||||
|
eo_do(camera_node,
|
||||||
|
evas_3d_node_camera_set(camera));
|
||||||
|
eo_do(root_node,
|
||||||
|
evas_3d_node_member_add(camera_node));
|
||||||
|
eo_do(camera_node,
|
||||||
|
evas_3d_node_position_set(100.0, 0.0, 20.0),
|
||||||
|
evas_3d_node_look_at_set(EVAS_3D_SPACE_PARENT, 0.0, 0.0, 20.0,
|
||||||
|
EVAS_3D_SPACE_PARENT, 0.0, 0.0, 1.0));
|
||||||
|
/* Add the light. */
|
||||||
|
light = eo_add(EVAS_3D_LIGHT_CLASS, evas);
|
||||||
|
eo_do(light,
|
||||||
|
evas_3d_light_ambient_set(1.0, 1.0, 1.0, 1.0),
|
||||||
|
evas_3d_light_diffuse_set(1.0, 1.0, 1.0, 1.0),
|
||||||
|
evas_3d_light_specular_set(1.0, 1.0, 1.0, 1.0),
|
||||||
|
evas_3d_light_directional_set(EINA_TRUE));
|
||||||
|
|
||||||
|
light_node =
|
||||||
|
eo_add_custom(EVAS_3D_NODE_CLASS, evas,
|
||||||
|
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_LIGHT));
|
||||||
|
eo_do(light_node,
|
||||||
|
evas_3d_node_light_set(light),
|
||||||
|
evas_3d_node_position_set(1000.0, 0.0, 1000.0),
|
||||||
|
evas_3d_node_look_at_set(EVAS_3D_SPACE_PARENT, 0.0, 0.0, 0.0,
|
||||||
|
EVAS_3D_SPACE_PARENT, 0.0, 1.0, 0.0));
|
||||||
|
eo_do(root_node,
|
||||||
|
evas_3d_node_member_add(light_node));
|
||||||
|
|
||||||
|
/* Add the mesh. */
|
||||||
|
mesh = eo_add(EVAS_3D_MESH_CLASS, evas);
|
||||||
|
material = eo_add(EVAS_3D_MATERIAL_CLASS, evas);
|
||||||
|
|
||||||
|
eo_do(mesh,
|
||||||
|
evas_3d_mesh_file_set(EVAS_3D_MESH_FILE_TYPE_OBJ, "man_mesh.obj", NULL),
|
||||||
|
evas_3d_mesh_frame_material_set(0, material),
|
||||||
|
evas_3d_mesh_shade_mode_set(EVAS_3D_SHADE_MODE_PHONG));
|
||||||
|
|
||||||
|
texture = eo_add(EVAS_3D_TEXTURE_CLASS, evas);
|
||||||
|
eo_do(texture,
|
||||||
|
evas_3d_texture_file_set("indian_DIFF3.png", NULL),
|
||||||
|
evas_3d_texture_filter_set(EVAS_3D_TEXTURE_FILTER_NEAREST,
|
||||||
|
EVAS_3D_TEXTURE_FILTER_NEAREST),
|
||||||
|
evas_3d_texture_wrap_set(EVAS_3D_WRAP_MODE_REPEAT,
|
||||||
|
EVAS_3D_WRAP_MODE_REPEAT));
|
||||||
|
eo_do(material,
|
||||||
|
evas_3d_material_texture_set(EVAS_3D_MATERIAL_DIFFUSE, texture),
|
||||||
|
evas_3d_material_enable_set(EVAS_3D_MATERIAL_AMBIENT, EINA_TRUE),
|
||||||
|
evas_3d_material_enable_set(EVAS_3D_MATERIAL_DIFFUSE, EINA_TRUE),
|
||||||
|
evas_3d_material_enable_set(EVAS_3D_MATERIAL_SPECULAR, EINA_TRUE),
|
||||||
|
evas_3d_material_enable_set(EVAS_3D_MATERIAL_NORMAL, EINA_TRUE),
|
||||||
|
evas_3d_material_color_set(EVAS_3D_MATERIAL_AMBIENT,
|
||||||
|
0.01, 0.01, 0.01, 1.0),
|
||||||
|
evas_3d_material_color_set(EVAS_3D_MATERIAL_DIFFUSE,
|
||||||
|
1.0, 1.0, 1.0, 1.0),
|
||||||
|
evas_3d_material_color_set(EVAS_3D_MATERIAL_SPECULAR,
|
||||||
|
1.0, 1.0, 1.0, 1.0),
|
||||||
|
evas_3d_material_shininess_set(50.0));
|
||||||
|
|
||||||
|
eo_do(mesh, evas_3d_mesh_save(EVAS_3D_MESH_FILE_TYPE_OBJ, "saved_man", NULL));
|
||||||
|
|
||||||
|
mesh_node = eo_add_custom(EVAS_3D_NODE_CLASS, evas,
|
||||||
|
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_MESH));
|
||||||
|
eo_do(root_node,
|
||||||
|
evas_3d_node_member_add(mesh_node));
|
||||||
|
eo_do(mesh_node,
|
||||||
|
evas_3d_node_mesh_add(mesh));
|
||||||
|
|
||||||
|
/* Set up scene. */
|
||||||
|
eo_do(scene,
|
||||||
|
evas_3d_scene_root_node_set(root_node),
|
||||||
|
evas_3d_scene_camera_node_set(camera_node),
|
||||||
|
evas_3d_scene_size_set(WIDTH, HEIGHT));
|
||||||
|
|
||||||
|
/* Add a background rectangle objects. */
|
||||||
|
background = eo_add(EVAS_OBJ_RECTANGLE_CLASS, evas);
|
||||||
|
eo_unref(background);
|
||||||
|
eo_do(background,
|
||||||
|
evas_obj_color_set(0, 0, 0, 255),
|
||||||
|
evas_obj_size_set(WIDTH, HEIGHT),
|
||||||
|
evas_obj_visibility_set(EINA_TRUE));
|
||||||
|
|
||||||
|
/* Add an image object for 3D scene rendering. */
|
||||||
|
image = evas_object_image_filled_add(evas);
|
||||||
|
eo_do(image,
|
||||||
|
evas_obj_size_set(WIDTH, HEIGHT),
|
||||||
|
evas_obj_visibility_set(EINA_TRUE));
|
||||||
|
|
||||||
|
/* Set the image object as render target for 3D scene. */
|
||||||
|
eo_do(image, evas_obj_image_scene_set(scene));
|
||||||
|
|
||||||
|
ecore_timer_add(0.01, _animate_scene, mesh_node);
|
||||||
|
|
||||||
|
/* Enter main loop. */
|
||||||
|
ecore_main_loop_begin();
|
||||||
|
|
||||||
|
ecore_evas_free(ecore_evas);
|
||||||
|
ecore_evas_shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 284 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
# Blender MTL File: 'None'
|
||||||
|
# Material Count: 1
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
File diff suppressed because it is too large
Load Diff
|
@ -744,6 +744,7 @@ typedef enum _Evas_3D_Material_Attrib
|
||||||
typedef enum _Evas_3D_Mesh_File_Type
|
typedef enum _Evas_3D_Mesh_File_Type
|
||||||
{
|
{
|
||||||
EVAS_3D_MESH_FILE_TYPE_MD2 = 0, /**< Quake's MD2 mesh file format */
|
EVAS_3D_MESH_FILE_TYPE_MD2 = 0, /**< Quake's MD2 mesh file format */
|
||||||
|
EVAS_3D_MESH_FILE_TYPE_OBJ,
|
||||||
} Evas_3D_Mesh_File_Type;
|
} Evas_3D_Mesh_File_Type;
|
||||||
|
|
||||||
#include "canvas/evas_image.eo.h"
|
#include "canvas/evas_image.eo.h"
|
||||||
|
|
|
@ -748,17 +748,46 @@ _evas_3d_mesh_file_set(Eo *obj, Evas_3D_Mesh_Data *pd, Evas_3D_Mesh_File_Type ty
|
||||||
_mesh_fini(pd);
|
_mesh_fini(pd);
|
||||||
_mesh_init(pd);
|
_mesh_init(pd);
|
||||||
|
|
||||||
if (file == NULL)
|
if (file == NULL) return;
|
||||||
return;
|
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case EVAS_3D_MESH_FILE_TYPE_MD2:
|
case EVAS_3D_MESH_FILE_TYPE_MD2:
|
||||||
evas_3d_mesh_file_md2_set(obj, file);
|
evas_3d_mesh_file_md2_set(obj, file);
|
||||||
break;
|
break;
|
||||||
|
case EVAS_3D_MESH_FILE_TYPE_OBJ:
|
||||||
|
evas_3d_mesh_file_obj_set(obj, file);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ERR("Invalid mesh file type.");
|
ERR("Invalid mesh file type.");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static void
|
||||||
|
_evas_3d_mesh_save(Eo *obj, Evas_3D_Mesh_Data *pd, Evas_3D_Mesh_File_Type type,
|
||||||
|
const char *file, const char *key EINA_UNUSED)
|
||||||
|
{
|
||||||
|
if ((file == NULL) || (obj == NULL) || (pd == NULL)) return;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EVAS_3D_MESH_FILE_TYPE_OBJ:
|
||||||
|
{
|
||||||
|
Evas_3D_Mesh_Frame *f = evas_3d_mesh_frame_find(pd, 0);
|
||||||
|
|
||||||
|
if (f == NULL)
|
||||||
|
{
|
||||||
|
ERR("Not existing mesh frame.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
evas_3d_mesh_save_obj(obj, file, f);//file without extension!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ERR("Invalid mesh file type.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,23 @@ class Evas_3D_Mesh (Evas_3D_Object, Evas_Common_Interface)
|
||||||
/**
|
/**
|
||||||
* Load mesh data from file.
|
* Load mesh data from file.
|
||||||
*
|
*
|
||||||
* Loading a mesh from existing file is supported. Currently, only MD2 file
|
* Loading a mesh from existing file is supported. Currently, only MD2 and OBJ file
|
||||||
|
* formats are supported.
|
||||||
|
*
|
||||||
|
* @ingroup Evas_3D_Mesh
|
||||||
|
*/
|
||||||
|
params {
|
||||||
|
@in Evas_3D_Mesh_File_Type type; /*@ The type of the mesh file. */
|
||||||
|
@in const char *file; /*@ Path to the mesh file. */
|
||||||
|
@in const char *key; /*@ Key in the mesh file. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
save {
|
||||||
|
/**
|
||||||
|
* Save mesh data to file.
|
||||||
|
*
|
||||||
|
* Saving a mesh to file is supported. Currently, only OBJ file
|
||||||
* format is supported.
|
* format is supported.
|
||||||
*
|
*
|
||||||
* @ingroup Evas_3D_Mesh
|
* @ingroup Evas_3D_Mesh
|
||||||
|
|
|
@ -0,0 +1,397 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "evas_common_private.h"
|
||||||
|
#include "evas_private.h"
|
||||||
|
|
||||||
|
/* set value to position [x][y] to array name which have. */
|
||||||
|
#define ARRAY_2D(name, x, y, count_y) (*(name + x * count_y + y))
|
||||||
|
|
||||||
|
/* read 3 float values in string and put it in array */
|
||||||
|
#define PUT_DATA_TO_ARRAY(array_name, name) \
|
||||||
|
sscanf (current,"%f %f %f", \
|
||||||
|
&ARRAY_2D(_##array_name##_obj, counts.current_##name##_counter, 0, 3), \
|
||||||
|
&ARRAY_2D(_##array_name##_obj, counts.current_##name##_counter, 1, 3), \
|
||||||
|
&ARRAY_2D(_##array_name##_obj, counts.current_##name##_counter, 2, 3)); \
|
||||||
|
counts.current_##name##_counter++;
|
||||||
|
|
||||||
|
/* Structures for reading data from file. */
|
||||||
|
typedef struct _OBJ_Counts OBJ_Counts;
|
||||||
|
|
||||||
|
struct _OBJ_Counts
|
||||||
|
{
|
||||||
|
int _vertex_counter;
|
||||||
|
int _normal_counter;
|
||||||
|
int _texture_point_counter;
|
||||||
|
int _triangles_counter;
|
||||||
|
|
||||||
|
int current_vertex_counter;
|
||||||
|
int current_normal_counter;
|
||||||
|
int current_texture_point_counter;
|
||||||
|
int current_triangles_counter;
|
||||||
|
|
||||||
|
Eina_Bool existence_of_normal;
|
||||||
|
Eina_Bool existence_of_tex_point;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline char*
|
||||||
|
_file_to_buf(const char *file, long *length)//prepare text file for reading
|
||||||
|
{
|
||||||
|
FILE *file_for_print;
|
||||||
|
char *buf;
|
||||||
|
int unused __attribute__((unused));//this variable fixes warning "ignoring return value of fread"
|
||||||
|
|
||||||
|
*length = 0;
|
||||||
|
file_for_print = fopen(file, "rb");
|
||||||
|
if (!file_for_print) return NULL;
|
||||||
|
fseek(file_for_print, 0, SEEK_END);//set file_for_print to the end of file
|
||||||
|
*length = ftell(file_for_print);//set current position of file_for_print
|
||||||
|
buf = malloc(*length + 1);
|
||||||
|
fseek(file_for_print, 0, SEEK_SET);//set file_for_print to the begining of file
|
||||||
|
unused = fread(buf, *length, 1, file_for_print);
|
||||||
|
fclose(file_for_print);
|
||||||
|
buf[*length] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create new counter */
|
||||||
|
static inline OBJ_Counts
|
||||||
|
_new_count_elements()
|
||||||
|
{
|
||||||
|
OBJ_Counts counts;
|
||||||
|
|
||||||
|
counts._vertex_counter = 0;
|
||||||
|
counts._normal_counter = 0;
|
||||||
|
counts._texture_point_counter = 0;
|
||||||
|
counts._triangles_counter = 0;
|
||||||
|
|
||||||
|
counts.current_vertex_counter = 0;
|
||||||
|
counts.current_normal_counter = 0;
|
||||||
|
counts.current_texture_point_counter = 0;
|
||||||
|
counts.current_triangles_counter = 0;
|
||||||
|
|
||||||
|
counts.existence_of_normal = EINA_FALSE;
|
||||||
|
counts.existence_of_tex_point = EINA_FALSE;
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* count triangles in face */
|
||||||
|
static void
|
||||||
|
_analyze_face_line(char * face_analyzer,
|
||||||
|
int * count_of_triangles_in_line)
|
||||||
|
{
|
||||||
|
int polygon_checker = -2;
|
||||||
|
Eina_Bool previous_is_space = EINA_TRUE;
|
||||||
|
while ((*face_analyzer != '\n') && (*face_analyzer != '#'))
|
||||||
|
{
|
||||||
|
if (*face_analyzer == ' ')
|
||||||
|
{
|
||||||
|
previous_is_space = EINA_TRUE;
|
||||||
|
}
|
||||||
|
else if ((previous_is_space) && (*face_analyzer >= '0') && (*face_analyzer <= '9'))
|
||||||
|
{
|
||||||
|
polygon_checker++;
|
||||||
|
previous_is_space = EINA_FALSE;
|
||||||
|
}
|
||||||
|
face_analyzer++;
|
||||||
|
}
|
||||||
|
*count_of_triangles_in_line = polygon_checker;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline OBJ_Counts
|
||||||
|
_count_elements(char *start, long length)//count elements of mesh in .obj
|
||||||
|
{
|
||||||
|
OBJ_Counts counts = _new_count_elements();
|
||||||
|
|
||||||
|
char * current = start;
|
||||||
|
int polygon_checker = -2;//polygons with n vertices can be represented as n-2 triangles
|
||||||
|
Eina_Bool will_check_next_char = EINA_FALSE;
|
||||||
|
Eina_Bool first_char_is_v = EINA_FALSE;
|
||||||
|
Eina_Bool first_char_is_f = EINA_FALSE;
|
||||||
|
Eina_Bool previous_is_space = EINA_FALSE;
|
||||||
|
|
||||||
|
long i = 0;
|
||||||
|
/* count elements of mesh in .obj */
|
||||||
|
for (; length > i; i++)
|
||||||
|
{
|
||||||
|
if (will_check_next_char)
|
||||||
|
{
|
||||||
|
if (first_char_is_v)
|
||||||
|
{
|
||||||
|
switch (*current)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
counts._vertex_counter++;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
counts._texture_point_counter++;
|
||||||
|
counts.existence_of_tex_point = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
counts._normal_counter++;
|
||||||
|
counts.existence_of_normal = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first_char_is_v = EINA_FALSE;
|
||||||
|
will_check_next_char = EINA_FALSE;
|
||||||
|
}
|
||||||
|
else if (first_char_is_f)
|
||||||
|
{
|
||||||
|
switch (*current)
|
||||||
|
{
|
||||||
|
case '\n':
|
||||||
|
first_char_is_f = EINA_FALSE;
|
||||||
|
counts._triangles_counter += polygon_checker;
|
||||||
|
polygon_checker = -2;
|
||||||
|
previous_is_space = EINA_FALSE;
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
first_char_is_f = EINA_FALSE;
|
||||||
|
counts._triangles_counter += polygon_checker;
|
||||||
|
polygon_checker = -2;
|
||||||
|
previous_is_space = EINA_FALSE;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
previous_is_space = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ((previous_is_space) && (*current >= '0') && (*current <= '9'))
|
||||||
|
{
|
||||||
|
polygon_checker++;
|
||||||
|
previous_is_space = EINA_FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (*current)
|
||||||
|
{
|
||||||
|
case 'v':
|
||||||
|
first_char_is_v = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
first_char_is_f = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
will_check_next_char = EINA_FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
will_check_next_char = EINA_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*current == '\n')
|
||||||
|
{
|
||||||
|
will_check_next_char = EINA_TRUE;
|
||||||
|
}
|
||||||
|
current++;
|
||||||
|
}
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_3d_mesh_file_obj_set(Evas_3D_Mesh *mesh, const char *file)
|
||||||
|
{
|
||||||
|
long length, i;
|
||||||
|
char * start = _file_to_buf(file, &length);
|
||||||
|
OBJ_Counts counts = _count_elements(start, length);//count elements of mesh in .obj
|
||||||
|
Eina_Bool will_check_next_char = EINA_FALSE;
|
||||||
|
Eina_Bool first_char_is_v = EINA_FALSE;
|
||||||
|
Eina_Bool first_char_is_f = EINA_FALSE;
|
||||||
|
float *pos, *nor, *tex;
|
||||||
|
int stride_pos, stride_nor, stride_tex;
|
||||||
|
int j, k;
|
||||||
|
char * current;
|
||||||
|
|
||||||
|
float *_vertices_obj = malloc(counts._vertex_counter * 3 * sizeof(float));
|
||||||
|
float *_normales_obj = malloc(counts._normal_counter * 3 * sizeof(float));
|
||||||
|
float *_tex_coords_obj = malloc(counts._texture_point_counter * 3 * sizeof(float));
|
||||||
|
/* triangle has 3 points, every point has 3(vertix, texture and normal) coord */
|
||||||
|
int *_triangles = malloc(counts._triangles_counter * 9 * sizeof(int));
|
||||||
|
|
||||||
|
if ((start == NULL) || (_vertices_obj == NULL) ||
|
||||||
|
(_normales_obj == NULL) || (_tex_coords_obj == NULL) || (_triangles == NULL))
|
||||||
|
{
|
||||||
|
ERR("Allocate memory is failed.");
|
||||||
|
free(start);
|
||||||
|
free(_vertices_obj);
|
||||||
|
free(_normales_obj);
|
||||||
|
free(_tex_coords_obj);
|
||||||
|
free(_triangles);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = start;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* put data to arrays */
|
||||||
|
for (; length > i; i++)
|
||||||
|
{
|
||||||
|
if (will_check_next_char)
|
||||||
|
{
|
||||||
|
if (first_char_is_v)
|
||||||
|
{
|
||||||
|
switch (*current)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
PUT_DATA_TO_ARRAY(vertices, vertex)
|
||||||
|
i--;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
current++;
|
||||||
|
PUT_DATA_TO_ARRAY(tex_coords, texture_point)
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
current++;
|
||||||
|
PUT_DATA_TO_ARRAY(normales, normal)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first_char_is_v = EINA_FALSE;
|
||||||
|
will_check_next_char = EINA_FALSE;
|
||||||
|
}
|
||||||
|
else if (first_char_is_f)
|
||||||
|
{
|
||||||
|
char * auxiliary_pointer = current;
|
||||||
|
int count_of_triangles_in_line;
|
||||||
|
|
||||||
|
_analyze_face_line(auxiliary_pointer,
|
||||||
|
&count_of_triangles_in_line);
|
||||||
|
int j;
|
||||||
|
current++;
|
||||||
|
i++;
|
||||||
|
int first_pos, first_tex, first_norm;
|
||||||
|
sscanf (current,"%i/%i/%i",
|
||||||
|
&first_pos,
|
||||||
|
&first_tex,
|
||||||
|
&first_norm);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
current++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while (*current != ' ');
|
||||||
|
|
||||||
|
current++;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
for (j = 0; j < count_of_triangles_in_line; j++)
|
||||||
|
{
|
||||||
|
auxiliary_pointer = current;
|
||||||
|
ARRAY_2D(_triangles, counts.current_triangles_counter, 0, 9) = first_pos;
|
||||||
|
ARRAY_2D(_triangles, counts.current_triangles_counter, 1, 9) = first_tex;
|
||||||
|
ARRAY_2D(_triangles, counts.current_triangles_counter, 2, 9) = first_norm;
|
||||||
|
sscanf (auxiliary_pointer,"%i/%i/%i %i/%i/%i",
|
||||||
|
&ARRAY_2D(_triangles, counts.current_triangles_counter, 3, 9),
|
||||||
|
&ARRAY_2D(_triangles, counts.current_triangles_counter, 4, 9),
|
||||||
|
&ARRAY_2D(_triangles, counts.current_triangles_counter, 5, 9),
|
||||||
|
&ARRAY_2D(_triangles, counts.current_triangles_counter, 6, 9),
|
||||||
|
&ARRAY_2D(_triangles, counts.current_triangles_counter, 7, 9),
|
||||||
|
&ARRAY_2D(_triangles, counts.current_triangles_counter, 8, 9));
|
||||||
|
|
||||||
|
while (*current != ' ')
|
||||||
|
{
|
||||||
|
current++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
counts.current_triangles_counter++;
|
||||||
|
}
|
||||||
|
first_char_is_f = EINA_FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (*current)
|
||||||
|
{
|
||||||
|
case 'v':
|
||||||
|
first_char_is_v = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
first_char_is_f = EINA_TRUE;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
will_check_next_char = EINA_FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
will_check_next_char = EINA_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*current == '\n')
|
||||||
|
{
|
||||||
|
will_check_next_char = EINA_TRUE;
|
||||||
|
}
|
||||||
|
current++;
|
||||||
|
}
|
||||||
|
free(start);
|
||||||
|
|
||||||
|
/* prepare of mesh and take pointers to data which must be read */
|
||||||
|
eo_do(mesh,
|
||||||
|
evas_3d_mesh_vertex_count_set(counts._triangles_counter * 3),
|
||||||
|
evas_3d_mesh_vertex_assembly_set(EVAS_3D_VERTEX_ASSEMBLY_TRIANGLES),
|
||||||
|
evas_3d_mesh_frame_add(0),
|
||||||
|
evas_3d_mesh_frame_vertex_data_copy_set(0, EVAS_3D_VERTEX_POSITION, 0, NULL),
|
||||||
|
evas_3d_mesh_frame_vertex_data_copy_set(0, EVAS_3D_VERTEX_NORMAL, 0, NULL),
|
||||||
|
evas_3d_mesh_frame_vertex_data_copy_set(0, EVAS_3D_VERTEX_TEXCOORD, 0, NULL),
|
||||||
|
|
||||||
|
pos = (float *)evas_3d_mesh_frame_vertex_data_map(0, EVAS_3D_VERTEX_POSITION),
|
||||||
|
nor = (float *)evas_3d_mesh_frame_vertex_data_map(0, EVAS_3D_VERTEX_NORMAL),
|
||||||
|
tex = (float *)evas_3d_mesh_frame_vertex_data_map(0, EVAS_3D_VERTEX_TEXCOORD),
|
||||||
|
|
||||||
|
stride_pos = evas_3d_mesh_frame_vertex_stride_get(0, EVAS_3D_VERTEX_POSITION),
|
||||||
|
stride_nor = evas_3d_mesh_frame_vertex_stride_get(0, EVAS_3D_VERTEX_NORMAL),
|
||||||
|
stride_tex = evas_3d_mesh_frame_vertex_stride_get(0, EVAS_3D_VERTEX_TEXCOORD));
|
||||||
|
|
||||||
|
if (stride_pos == 0) stride_pos = sizeof(float) * 3;
|
||||||
|
if (stride_nor == 0) stride_nor = sizeof(float) * 3;
|
||||||
|
if (stride_tex == 0) stride_tex = sizeof(float) * 2;
|
||||||
|
|
||||||
|
for (j = 0; j < counts._triangles_counter; j++)
|
||||||
|
{
|
||||||
|
for (k = 0; k < 3; k++)
|
||||||
|
{
|
||||||
|
float *p, *n, *t;
|
||||||
|
|
||||||
|
p = (float *)((char *)pos + stride_pos * (j * 3 + k));
|
||||||
|
n = (float *)((char *)nor + stride_nor * (j * 3 + k));
|
||||||
|
t = (float *)((char *)tex + stride_tex * (j * 3 + k));
|
||||||
|
|
||||||
|
p[0] = ARRAY_2D(_vertices_obj, (ARRAY_2D(_triangles, j, (3 * k), 9) - 1), 0, 3);
|
||||||
|
p[1] = ARRAY_2D(_vertices_obj, (ARRAY_2D(_triangles, j, (3 * k), 9) - 1), 1, 3);
|
||||||
|
p[2] = ARRAY_2D(_vertices_obj, (ARRAY_2D(_triangles, j, (3 * k), 9) - 1), 2, 3);
|
||||||
|
|
||||||
|
n[0] = ARRAY_2D(_normales_obj, (ARRAY_2D(_triangles, j, (3 * k + 2), 9) - 1), 0, 3);
|
||||||
|
n[1] = ARRAY_2D(_normales_obj, (ARRAY_2D(_triangles, j, (3 * k + 2), 9) - 1), 1, 3);
|
||||||
|
n[2] = ARRAY_2D(_normales_obj, (ARRAY_2D(_triangles, j, (3 * k + 2), 9) - 1), 2, 3);
|
||||||
|
|
||||||
|
t[0] = ARRAY_2D(_tex_coords_obj, (ARRAY_2D(_triangles, j, (3 * k + 1), 9) - 1), 0, 3);
|
||||||
|
t[1] = ARRAY_2D(_tex_coords_obj, (ARRAY_2D(_triangles, j, (3 * k + 1), 9) - 1), 1, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(_vertices_obj);
|
||||||
|
free(_normales_obj);
|
||||||
|
free(_tex_coords_obj);
|
||||||
|
free(_triangles);
|
||||||
|
/* Unmap vertex buffer. */
|
||||||
|
eo_do(mesh,
|
||||||
|
evas_3d_mesh_frame_vertex_data_unmap(0, EVAS_3D_VERTEX_POSITION),
|
||||||
|
evas_3d_mesh_frame_vertex_data_unmap(0, EVAS_3D_VERTEX_NORMAL),
|
||||||
|
evas_3d_mesh_frame_vertex_data_unmap(0, EVAS_3D_VERTEX_TEXCOORD));
|
||||||
|
|
||||||
|
Evas_3D_Mesh_Data *pd = eo_data_scope_get(mesh, EVAS_3D_MESH_CLASS);
|
||||||
|
|
||||||
|
if (!evas_3d_mesh_aabb_add_to_frame(pd, 0, stride_pos))
|
||||||
|
{
|
||||||
|
ERR("Axis-Aligned Bounding Box wan't added in frame %d ", 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "evas_common_private.h"
|
||||||
|
#include "evas_private.h"
|
||||||
|
|
||||||
|
#define OPEN_FILE(extension)\
|
||||||
|
int length=strlen(file);\
|
||||||
|
char * extension = "."#extension;\
|
||||||
|
char * _##extension##_file_name = (char *)malloc(length+4);\
|
||||||
|
strcpy(_##extension##_file_name,file);\
|
||||||
|
strcpy(_##extension##_file_name+length,extension);\
|
||||||
|
FILE * _##extension##_file = fopen(_##extension##_file_name, "w+");\
|
||||||
|
free(_##extension##_file_name);
|
||||||
|
|
||||||
|
#define SAVE_GEOMETRICS(a, format)\
|
||||||
|
vb = &f->vertices[a];\
|
||||||
|
fprintf(_obj_file, "o %s\n",file);\
|
||||||
|
if (vb->data == NULL)\
|
||||||
|
{\
|
||||||
|
ERR("Reading of geometrics is failed.");\
|
||||||
|
fclose(_obj_file);\
|
||||||
|
return;\
|
||||||
|
}\
|
||||||
|
src = (float *)vb->data;\
|
||||||
|
for (i = 0; i < pd->vertex_count; i++)\
|
||||||
|
{\
|
||||||
|
fprintf(_obj_file, format, src[0], src[1], src[2]);\
|
||||||
|
src += f->vertices[a].element_count;\
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_save_mesh(Evas_3D_Mesh_Data *pd, const char *file, Evas_3D_Mesh_Frame *f)
|
||||||
|
{
|
||||||
|
Evas_3D_Vertex_Buffer *vb;
|
||||||
|
time_t current_time;
|
||||||
|
char* c_time_string;
|
||||||
|
int i;
|
||||||
|
float *src;
|
||||||
|
|
||||||
|
OPEN_FILE(obj)
|
||||||
|
fprintf(_obj_file, "# Evas_3D saver OBJ v0.03 \n");//_obj_file created in macro
|
||||||
|
/* Adding time comment to .obj file. */
|
||||||
|
current_time = time(NULL);
|
||||||
|
|
||||||
|
if (current_time == ((time_t)-1))
|
||||||
|
{
|
||||||
|
ERR("Failure to compute the current time.");
|
||||||
|
fclose(_obj_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_time_string = ctime(¤t_time);
|
||||||
|
|
||||||
|
if (c_time_string == NULL)
|
||||||
|
{
|
||||||
|
ERR("Failure to convert the current time.");
|
||||||
|
fclose(_obj_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(_obj_file,"# Current time is %s \n", c_time_string);
|
||||||
|
fprintf(_obj_file,"mtllib %s.mtl \n\n", file);
|
||||||
|
|
||||||
|
/* Adding geometrics to file. */
|
||||||
|
if (f == NULL)
|
||||||
|
{
|
||||||
|
ERR("Not existing mesh frame.");
|
||||||
|
fclose(_obj_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAVE_GEOMETRICS(EVAS_3D_VERTEX_POSITION, "v %.4f %.4f %.4f \n")
|
||||||
|
SAVE_GEOMETRICS(EVAS_3D_VERTEX_NORMAL, "vn %.4f %.4f %.4f \n")
|
||||||
|
SAVE_GEOMETRICS(EVAS_3D_VERTEX_TEXCOORD, "vt %.4f %.4f %.4f \n")
|
||||||
|
fprintf(_obj_file,"usemtl Material\n s off\n");
|
||||||
|
for (i = 1; i <= pd->vertex_count; i++)//numeration of faces in .obj started from 1
|
||||||
|
{
|
||||||
|
fprintf(_obj_file,"f %i/%i/%i ", i, i, i);
|
||||||
|
i++;
|
||||||
|
fprintf(_obj_file,"%i/%i/%i ", i, i, i);
|
||||||
|
i++;
|
||||||
|
fprintf(_obj_file,"%i/%i/%i \n", i, i, i);
|
||||||
|
}
|
||||||
|
fclose(_obj_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_save_material(Evas_3D_Mesh_Data *pd EINA_UNUSED, const char *file, Evas_3D_Mesh_Frame *f)
|
||||||
|
{
|
||||||
|
Evas_3D_Material_Data *mat = eo_data_scope_get(f->material, EVAS_3D_MATERIAL_CLASS);
|
||||||
|
|
||||||
|
OPEN_FILE(mtl)
|
||||||
|
|
||||||
|
fprintf(_mtl_file, "# Evas_3D saver OBJ v0.03 \n");//_mtl_file created in macro
|
||||||
|
fprintf(_mtl_file, "# Material Count: 1 \n\n");
|
||||||
|
fprintf(_mtl_file, "newmtl Material \n");
|
||||||
|
fprintf(_mtl_file, "Ns 1.000000 \n");//exp factor for specular highlight
|
||||||
|
fprintf(_mtl_file, "Ka %.6f %.6f %.6f \n",
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_AMBIENT].color.r,
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_AMBIENT].color.g,
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_AMBIENT].color.b);
|
||||||
|
fprintf(_mtl_file, "Kd %.6f %.6f %.6f \n",
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_DIFFUSE].color.r,
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_DIFFUSE].color.g,
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_DIFFUSE].color.b);
|
||||||
|
fprintf(_mtl_file, "Ks %.6f %.6f %.6f \n",
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_SPECULAR].color.r,
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_SPECULAR].color.g,
|
||||||
|
(float)mat->attribs[EVAS_3D_MATERIAL_SPECULAR].color.b);
|
||||||
|
fprintf(_mtl_file, "Ni 1.000000 \n");//optical density
|
||||||
|
fprintf(_mtl_file, "d 1.000000 \n");//a factor d of 1.0 is fully opaque material
|
||||||
|
fprintf(_mtl_file, "illum 2 \n");//illumination properties
|
||||||
|
|
||||||
|
fclose(_mtl_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evas_3d_mesh_save_obj(Evas_3D_Mesh *mesh, const char *file, Evas_3D_Mesh_Frame *f)
|
||||||
|
{
|
||||||
|
Evas_3D_Mesh_Data *pd = eo_data_scope_get(mesh, EVAS_3D_MESH_CLASS);
|
||||||
|
_save_mesh(pd, file, f);
|
||||||
|
_save_material(pd, file, f);
|
||||||
|
}
|
|
@ -1504,6 +1504,8 @@ void evas_3d_mesh_node_add(Evas_3D_Mesh *mesh, Evas_3D_Node *node);
|
||||||
void evas_3d_mesh_node_del(Evas_3D_Mesh *mesh, Evas_3D_Node *node);
|
void evas_3d_mesh_node_del(Evas_3D_Mesh *mesh, Evas_3D_Node *node);
|
||||||
void evas_3d_mesh_interpolate_vertex_buffer_get(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib, Evas_3D_Vertex_Buffer *buffer0, Evas_3D_Vertex_Buffer *buffer1, Evas_Real *weight);
|
void evas_3d_mesh_interpolate_vertex_buffer_get(Evas_3D_Mesh *mesh, int frame, Evas_3D_Vertex_Attrib attrib, Evas_3D_Vertex_Buffer *buffer0, Evas_3D_Vertex_Buffer *buffer1, Evas_Real *weight);
|
||||||
void evas_3d_mesh_file_md2_set(Evas_3D_Mesh *mesh, const char *file);
|
void evas_3d_mesh_file_md2_set(Evas_3D_Mesh *mesh, const char *file);
|
||||||
|
void evas_3d_mesh_save_obj(Evas_3D_Mesh *mesh, const char *file, Evas_3D_Mesh_Frame *f);
|
||||||
|
void evas_3d_mesh_file_obj_set(Evas_3D_Mesh *mesh, const char *file);
|
||||||
Eina_Bool evas_3d_mesh_aabb_add_to_frame(Evas_3D_Mesh_Data *pd, int frame, int stride);
|
Eina_Bool evas_3d_mesh_aabb_add_to_frame(Evas_3D_Mesh_Data *pd, int frame, int stride);
|
||||||
|
|
||||||
/* Texture functions. */
|
/* Texture functions. */
|
||||||
|
|
Loading…
Reference in New Issue