2 This file is part of the 3dengfx, realtime visualization system.
4 Copyright (c) 2005 John Tsiombikas <nuclear@siggraph.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* Scene loader from 3ds files.
23 * author: John Tsiombikas 2005
26 #include "3dengfx_config.h"
32 #include <lib3ds/file.h>
33 #include <lib3ds/camera.h>
34 #include <lib3ds/mesh.h>
35 #include <lib3ds/node.h>
36 #include <lib3ds/material.h>
37 #include <lib3ds/matrix.h>
38 #include <lib3ds/vector.h>
39 #include <lib3ds/light.h>
40 #include "3dscene.hpp"
45 #include "gfx/curves.hpp"
46 #include "common/err_msg.h"
48 #define CONV_VEC3(v) Vector3((v)[0], (v)[2], (v)[1])
49 #define CONV_QUAT(q) Quaternion((q)[3], Vector3((q)[0], (q)[2], (q)[1]))
50 #define CONV_TEXCOORD(t) TexCoord((t)[0], (t)[1])
51 #define CONV_TRIANGLE(t) Triangle((t).points[0], (t).points[2], (t).points[1])
52 #define CONV_RGBA(c) Color((c)[0], (c)[1], (c)[2], (c)[3])
53 #define CONV_RGB(c) Color((c)[0], (c)[1], (c)[2])
55 static bool load_objects(Lib3dsFile *file, Scene *scene);
56 static bool load_lights(Lib3dsFile *file, Scene *scene);
57 static bool load_cameras(Lib3dsFile *file, Scene *scene);
58 static bool load_material(Lib3dsFile *file, const char *name, Material *mat);
59 static bool load_keyframes(Lib3dsFile *file, const char *name, Lib3dsNodeTypes type, XFormNode *node);
60 static void construct_hierarchy(Lib3dsFile *file, Scene *scene);
61 //static void fix_hierarchy(XFormNode *node);
63 TriMesh *load_mesh_ply(const char *fname); // defined in ply.cpp
65 static const char *tex_path(const char *path);
66 static std::vector<int> *get_frames(Lib3dsObjectData *o);
67 static std::vector<int> *get_frames(Lib3dsLightData *lt);
68 static std::vector<int> *get_frames(Lib3dsCameraData *cam);
70 #define TPATH_SIZE 256
78 static char data_path[TPATH_SIZE];
80 void set_scene_data_path(const char *path) {
84 strncpy(data_path, path, TPATH_SIZE);
85 data_path[TPATH_SIZE - 1] = 0;
87 char *ptr = data_path + strlen(data_path);
88 if(*ptr != DIR_SEP && ptr - data_path < TPATH_SIZE) {
96 Scene *load_scene(const char *fname) {
99 if(!(file = lib3ds_file_load(fname))) {
100 error("%s: could not load %s", __func__, fname);
103 lib3ds_file_eval(file, 0);
105 Scene *scene = new Scene;
107 load_objects(file, scene);
108 load_lights(file, scene);
109 load_cameras(file, scene);
111 construct_hierarchy(file, scene);
114 std::list<Object*> *obj_list = scene->get_objects_list();
115 std::list<Object*>::iterator iter = obj_list->begin();
116 while(iter != obj_list->end()) {
117 fix_hierarchy(*iter++);
121 lib3ds_file_free(file);
126 TriMesh *load_mesh(const char *fname, const char *name) {
129 Lib3dsFile *file = lib3ds_file_load(fname);
131 Scene *scene = new Scene;
132 load_objects(file, scene);
134 Object *obj = scene->get_object(name);
137 *mesh = obj->get_mesh();
139 lib3ds_file_free(file);
143 mesh = load_mesh_ply(fname);
148 static bool load_objects(Lib3dsFile *file, Scene *scene) {
150 unsigned long poly_count = 0;
151 Lib3dsMesh *m = file->meshes;
154 Lib3dsNode *node = lib3ds_file_node_by_name(file, m->name, LIB3DS_OBJECT_NODE);
156 warning("object \"%s\" does not have a corresponding node!", m->name);
158 Vector3 node_pos = node ? CONV_VEC3(node->data.object.pos) : Vector3();
159 Quaternion node_rot = node ? CONV_QUAT(node->data.object.rot) : Quaternion();
160 Vector3 node_scl = node ? CONV_VEC3(node->data.object.scl) : Vector3(1,1,1);
161 Vector3 pivot = node ? CONV_VEC3(node->data.object.pivot) : Vector3();
164 Vertex *varray = new Vertex[m->points];
165 Vertex *vptr = varray;
166 for(int i=0; i<(int)m->points; i++) {
167 vptr->pos = CONV_VEC3(m->pointL[i].pos) - node_pos;
168 vptr->pos.transform(node_rot);
171 vptr->tex[0] = vptr->tex[1] = CONV_TEXCOORD(m->texelL[i]);
178 poly_count += m->faces;
179 // -------- object ---------
180 Object *obj = new Object;
181 obj->set_dynamic(false);
185 obj->set_position(node_pos - pivot);
186 obj->set_rotation(node_rot);
187 obj->set_scaling(node_scl);
189 obj->set_pivot(pivot);
192 Triangle *tarray = new Triangle[m->faces];
193 Triangle *tptr = tarray;
194 for(int i=0; i<(int)m->faces; i++) {
195 *tptr = CONV_TRIANGLE(m->faceL[i]);
196 tptr->normal = CONV_VEC3(m->faceL[i].normal);
197 tptr->smoothing_group = m->faceL[i].smoothing;
202 // set the geometry data to the object
203 obj->get_mesh_ptr()->set_data(varray, m->points, tarray, m->faces);
204 obj->get_mesh_ptr()->calculate_normals();
209 load_material(file, m->faceL[0].material, obj->get_material_ptr());
211 // load the keyframes (if any)
212 if(load_keyframes(file, m->name, LIB3DS_OBJECT_NODE, obj)) {
213 obj->set_position(Vector3());
214 obj->set_rotation(Quaternion());
215 obj->set_scaling(Vector3(1, 1, 1));
218 scene->add_object(obj);
221 // --------- curve ------------
222 Curve *curve = new CatmullRomSplineCurve;
223 curve->name = m->name;
225 Vector3 offs = node_pos - pivot;
227 for(int i=0; i<(int)m->points; i++) {
228 curve->add_control_point(varray[i].pos + offs);
231 scene->add_curve(curve);
240 scene->set_poly_count(poly_count);
244 static bool is_pow_two(unsigned long val) {
246 while(val && count_ones <= 1) {
247 if(val & 1) count_ones++;
250 return (count_ones == 1 && !(val & 1)) ? true : false;
253 static bool load_material(Lib3dsFile *file, const char *name, Material *mat) {
255 if(!name || !*name || !(m = lib3ds_file_material_by_name(file, name))) {
260 mat->ambient_color = CONV_RGBA(m->ambient);
261 mat->diffuse_color = CONV_RGBA(m->diffuse);
262 mat->specular_color = CONV_RGBA(m->specular) * m->shin_strength;
264 std::cerr << "self illuminating material: " << name << std::endl;
265 mat->emissive_color = 1.0;
268 scalar_t s = pow(2.0, 10.0 * m->shininess);
269 mat->specular_power = s > 128.0 ? 128.0 : s;
271 mat->alpha = 1.0 - m->transparency;
273 if(m->shading == LIB3DS_WIRE_FRAME || m->use_wire) {
274 mat->wireframe = true;
277 if(m->shading == LIB3DS_FLAT) {
278 mat->shading = SHADING_FLAT;
282 Texture *tex = 0, *detail = 0, *env = 0, *light = 0, *bump = 0;
285 tpath = tex_path(m->texture1_map.name);
286 if(tpath && (tex = get_texture(tpath))) {
287 mat->set_texture(tex, TEXTYPE_DIFFUSE);
290 tpath = tex_path(m->texture2_map.name);
291 if(tpath && (detail = get_texture(tpath))) {
292 mat->set_texture(detail, TEXTYPE_DETAIL);
295 tpath = tex_path(m->reflection_map.name);
296 if(tpath && (env = get_texture(tpath))) {
297 mat->set_texture(env, TEXTYPE_ENVMAP);
298 mat->env_intensity = m->reflection_map.percent;
301 tpath = tex_path(m->bump_map.name);
302 if(tpath && (bump = get_texture(tpath))) {
303 //FIXME: make dot3 work first mat->set_texture(bump, TEXTYPE_BUMPMAP);
306 tpath = tex_path(m->self_illum_map.name);
307 if(tpath && (light = get_texture(tpath))) {
308 mat->set_texture(light, TEXTYPE_LIGHTMAP);
311 if(m->autorefl_map.flags & LIB3DS_USE_REFL_MAP) {
312 mat->env_intensity = m->reflection_map.percent;
314 int cube_sz = m->autorefl_map.size;
315 if(!is_pow_two(cube_sz)) {
316 warning("Material \"%s\" specifies a non power of 2 cube map and won't render correctly!", m->name);
319 Texture *cube_tex = new Texture(cube_sz, cube_sz, TEX_CUBE);
320 add_texture(cube_tex);
322 mat->set_texture(cube_tex, TEXTYPE_ENVMAP);
323 mat->auto_refl_upd = m->autorefl_map.frame_step;
324 if(m->autorefl_map.flags & LIB3DS_READ_FIRST_FRAME_ONLY ||
325 m->autorefl_map.flags & 0x8 || m->autorefl_map.frame_step == 1000) {
326 mat->auto_refl = true;
327 mat->auto_refl_upd = 0;
335 static const char *tex_path(const char *path) {
336 if(!path || !*path) return 0;
338 static char texpath[TPATH_SIZE];
340 strncpy(texpath, data_path, TPATH_SIZE);
341 texpath[TPATH_SIZE - 1] = 0;
343 const char *tmp = strrchr(path, '\\');
344 if(tmp) path = tmp + 1;
346 char *tp_ptr = texpath + strlen(texpath);
348 *tp_ptr++ = tolower(*path++);
355 bool load_lights(Lib3dsFile *file, Scene *scene) {
356 Lib3dsLight *lt = file->lights;
360 if(!lt->spot_light) {
361 light = new PointLight;
362 light->name = lt->name;
363 light->set_position(CONV_VEC3(lt->position));
364 light->set_color(CONV_RGB(lt->color));
365 light->set_intensity(lt->multiplier);
368 light = 0; // TODO: support spotlights at some point
372 if(load_keyframes(file, lt->name, LIB3DS_LIGHT_NODE, light)) {
373 light->set_position(Vector3());
375 scene->add_light(light);
384 bool load_cameras(Lib3dsFile *file, Scene *scene) {
385 Lib3dsCamera *c = file->cameras;
387 TargetCamera *cam = new TargetCamera;
389 cam->set_position(CONV_VEC3(c->position));
390 cam->set_target(CONV_VEC3(c->target));
391 //cam->set_clipping_planes(c->near_range, c->far_range);
393 //scalar_t angle = atan(1.0 / cam->get_aspect());
394 //cam->set_fov(sin(angle) * DEG_TO_RAD(c->fov));
395 cam->set_fov(DEG_TO_RAD(c->fov) / cam->get_aspect());
397 if(load_keyframes(file, c->name, LIB3DS_CAMERA_NODE, cam)) {
398 cam->set_position(Vector3());
400 //TODO: load_keyframes(file, ... hmmm where is the target node?
402 scene->add_camera(cam);
410 #define FRAME_TO_TIME(x) (((x) * 1000) / FPS)
412 static bool load_keyframes(Lib3dsFile *file, const char *name, Lib3dsNodeTypes type, XFormNode *node) {
413 if(!name || !*name) return false;
415 Lib3dsNode *n = lib3ds_file_node_by_name(file, name, type);
419 case LIB3DS_OBJECT_NODE:
421 Lib3dsObjectData *obj = &n->data.object;
422 std::vector<int> *frames = get_frames(obj);
423 if(!frames) return false;
425 for(int i=0; i<(int)frames->size(); i++) {
426 lib3ds_node_eval(n, (float)(*frames)[i]);
428 Vector3 pos = CONV_VEC3(obj->pos) - CONV_VEC3(obj->pivot);
429 Quaternion rot = CONV_QUAT(obj->rot);
430 Vector3 scl = CONV_VEC3(obj->scl);
432 Keyframe key(PRS(pos, rot, scl), FRAME_TO_TIME((*frames)[i]));
433 node->add_keyframe(key);
438 case LIB3DS_LIGHT_NODE:
440 Lib3dsLightData *light = &n->data.light;
441 std::vector<int> *frames = get_frames(light);
442 if(!frames) return false;
444 for(int i=0; i<(int)frames->size(); i++) {
445 lib3ds_node_eval(n, (float)(*frames)[i]);
447 Vector3 pos = CONV_VEC3(light->pos);
449 Keyframe key(PRS(pos, Quaternion()), FRAME_TO_TIME((*frames)[i]));
450 node->add_keyframe(key);
455 case LIB3DS_CAMERA_NODE:
457 Lib3dsCameraData *cam = &n->data.camera;
458 std::vector<int> *frames = get_frames(cam);
459 if(!frames) return false;
461 for(int i=0; i<(int)frames->size(); i++) {
462 lib3ds_node_eval(n, (float)(*frames)[i]);
464 Vector3 pos = CONV_VEC3(cam->pos);
466 Keyframe key(PRS(pos, Quaternion()), FRAME_TO_TIME((*frames)[i]));
467 node->add_keyframe(key);
473 case LIB3DS_TARGET_NODE:
475 Lib3dsCameraData *targ = &n->data.target;
476 std::vector<int> *frames = get_frames(targ);
477 if(!frames) return false;
479 for(int i=0; i<(int)frames->size(); i++) {
480 lib3ds_node_eval(n, (float)(*frames)[i]);
482 Vector3 pos = CONV_VEC3(targ->pos);
484 Keyframe key(PRS(pos, Quaternion()), FRAME_TO_TIME((*frames)[i]));
485 node->add_keyframe(key);
499 static void construct_hierarchy(Lib3dsFile *file, Scene *scene) {
500 std::list<Object*> *list = scene->get_object_list();
501 std::list<Object*>::iterator iter = list->begin();
502 while(iter != list->end()) {
504 Lib3dsNode *n = lib3ds_file_node_by_name(file, obj->name.c_str(), LIB3DS_OBJECT_NODE);
512 obj->parent = scene->get_node(n->parent->name);
516 Lib3dsNode *child = n->childs;
518 XFormNode *child_node = scene->get_node(child->name);
520 (*iter)->children.push_back(child_node);
531 static void fix_hierarchy(XFormNode *node) {
535 XFormNode *parent = node->parent;
537 PRS prs = node->get_prs(XFORM_LOCAL_PRS);
538 node->parent = parent;
540 PRS pprs = node->parent->get_prs(XFORM_LOCAL_PRS);
542 Vector3 pos = prs.position.transformed(pprs.rotation.conjugate());
544 node->set_position(pos);
547 for(int i=0; i<(int)node->children.size(); i++) {
548 fix_hierarchy(node->children[i]);
553 static std::vector<int> *get_frames(Lib3dsObjectData *o) {
554 static std::vector<int> frames;
556 Lib3dsLin3Key *pos_key = o->pos_track.keyL;
558 int frame = pos_key->tcb.frame;
559 if(find(frames.begin(), frames.end(), frame) == frames.end()) {
560 frames.push_back(frame);
562 pos_key = pos_key->next;
565 Lib3dsQuatKey *rot_key = o->rot_track.keyL;
567 int frame = rot_key->tcb.frame;
568 if(find(frames.begin(), frames.end(), frame) == frames.end()) {
569 frames.push_back(frame);
571 rot_key = rot_key->next;
574 Lib3dsLin3Key *scl_key = o->scl_track.keyL;
576 int frame = scl_key->tcb.frame;
577 if(find(frames.begin(), frames.end(), frame) == frames.end()) {
578 frames.push_back(frame);
580 scl_key = scl_key->next;
583 if(frames.size() > 1) return &frames;
587 static std::vector<int> *get_frames(Lib3dsLightData *lt) {
588 static std::vector<int> frames;
590 Lib3dsLin3Key *pos_key = lt->pos_track.keyL;
592 int frame = pos_key->tcb.frame;
593 frames.push_back(frame);
594 pos_key = pos_key->next;
597 if(frames.size() > 1) return &frames;
601 static std::vector<int> *get_frames(Lib3dsCameraData *cam) {
602 static std::vector<int> frames;
604 Lib3dsLin3Key *pos_key = cam->pos_track.keyL;
606 int frame = pos_key->tcb.frame;
607 frames.push_back(frame);
608 pos_key = pos_key->next;
611 if(frames.size() > 1) return &frames;