added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / 3dengfx / sceneloader.cpp
1 /*
2 This file is part of the 3dengfx, realtime visualization system.
3
4 Copyright (c) 2005 John Tsiombikas <nuclear@siggraph.org>
5
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.
10
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.
15
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
19 */
20
21 /* Scene loader from 3ds files.
22  *
23  * author: John Tsiombikas 2005
24  */
25
26 #include "3dengfx_config.h"
27
28 #include <algorithm>
29
30 #include <cstdio>
31 #include <cassert>
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"
41 #include "object.hpp"
42 #include "light.hpp"
43 #include "camera.hpp"
44 #include "texman.hpp"
45 #include "gfx/curves.hpp"
46 #include "common/err_msg.h"
47
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])
54
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);
62
63 TriMesh *load_mesh_ply(const char *fname);      // defined in ply.cpp
64
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);
69
70 #define TPATH_SIZE      256
71
72 #ifdef __unix__
73 #define DIR_SEP '/'
74 #else
75 #define DIR_SEP '\\'
76 #endif  /* __unix__ */
77
78 static char data_path[TPATH_SIZE];
79
80 void set_scene_data_path(const char *path) {
81         if(!path || !*path) {
82                 data_path[0] = 0;
83         } else {
84                 strncpy(data_path, path, TPATH_SIZE);
85                 data_path[TPATH_SIZE - 1] = 0;
86
87                 char *ptr = data_path + strlen(data_path);
88                 if(*ptr != DIR_SEP && ptr - data_path < TPATH_SIZE) {
89                         *ptr++ = DIR_SEP;
90                         *ptr = 0;
91                 }
92         }
93 }
94
95
96 Scene *load_scene(const char *fname) {
97
98         Lib3dsFile *file;
99         if(!(file = lib3ds_file_load(fname))) {
100                 error("%s: could not load %s", __func__, fname);
101                 return 0;
102         }
103         lib3ds_file_eval(file, 0);
104
105         Scene *scene = new Scene;
106
107         load_objects(file, scene);
108         load_lights(file, scene);
109         load_cameras(file, scene);
110
111         construct_hierarchy(file, scene);
112
113         /*
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++);
118         }
119         */
120         
121         lib3ds_file_free(file);
122
123         return scene;
124 }
125
126 TriMesh *load_mesh(const char *fname, const char *name) {
127         TriMesh *mesh = 0;
128         
129         Lib3dsFile *file = lib3ds_file_load(fname);
130         if(file && name) {
131                 Scene *scene = new Scene;
132                 load_objects(file, scene);
133
134                 Object *obj = scene->get_object(name);
135                 if(obj) {
136                         mesh = new TriMesh;
137                         *mesh = obj->get_mesh();
138                 }
139                 lib3ds_file_free(file);
140                 return mesh;
141         }
142
143         mesh = load_mesh_ply(fname);
144         return mesh;
145 }
146         
147
148 static bool load_objects(Lib3dsFile *file, Scene *scene) {
149         // load meshes
150         unsigned long poly_count = 0;
151         Lib3dsMesh *m = file->meshes;
152         while(m) {
153
154                 Lib3dsNode *node = lib3ds_file_node_by_name(file, m->name, LIB3DS_OBJECT_NODE);
155                 if(!node) {
156                         warning("object \"%s\" does not have a corresponding node!", m->name);
157                 }
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();
162
163                 // load the vertices
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);
169                         
170                         if(m->texels) {
171                                 vptr->tex[0] = vptr->tex[1] = CONV_TEXCOORD(m->texelL[i]);
172                         }
173                         
174                         vptr++;
175                 }
176                 
177                 if(m->faces) {
178                         poly_count += m->faces;
179                         // -------- object ---------
180                         Object *obj = new Object;
181                         obj->set_dynamic(false);
182
183                         obj->name = m->name;
184
185                         obj->set_position(node_pos - pivot);
186                         obj->set_rotation(node_rot);
187                         obj->set_scaling(node_scl);
188
189                         obj->set_pivot(pivot);
190                 
191                         // load the polygons
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;
198
199                                 tptr++;
200                         }
201
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();
205                 
206                         delete [] tarray;
207
208                         // load the material
209                         load_material(file, m->faceL[0].material, obj->get_material_ptr());
210
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));
216                         }
217
218                         scene->add_object(obj);
219                         
220                 } else {
221                         // --------- curve ------------
222                         Curve *curve = new CatmullRomSplineCurve;
223                         curve->name = m->name;
224
225                         Vector3 offs = node_pos - pivot;
226                         
227                         for(int i=0; i<(int)m->points; i++) {
228                                 curve->add_control_point(varray[i].pos + offs);
229                         }
230
231                         scene->add_curve(curve);
232                 }
233
234                 delete [] varray;
235
236
237                 m = m->next;
238         }
239         
240         scene->set_poly_count(poly_count);
241         return true;
242 }
243
244 static bool is_pow_two(unsigned long val) {
245         int count_ones = 0;
246         while(val && count_ones <= 1) {
247                 if(val & 1) count_ones++;
248                 val >>= 1;
249         }
250         return (count_ones == 1 && !(val & 1)) ? true : false;
251 }
252
253 static bool load_material(Lib3dsFile *file, const char *name, Material *mat) {
254         Lib3dsMaterial *m;
255         if(!name || !*name || !(m = lib3ds_file_material_by_name(file, name))) {
256                 return false;
257         }
258         
259         mat->name = 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;
263         if(m->self_illum) {
264                 std::cerr << "self illuminating material: " << name << std::endl;
265                 mat->emissive_color = 1.0;
266         }
267         
268         scalar_t s = pow(2.0, 10.0 * m->shininess);
269         mat->specular_power = s > 128.0 ? 128.0 : s;
270
271         mat->alpha = 1.0 - m->transparency;
272
273         if(m->shading == LIB3DS_WIRE_FRAME || m->use_wire) {
274                 mat->wireframe = true;
275         }
276         
277         if(m->shading == LIB3DS_FLAT) {
278                 mat->shading = SHADING_FLAT;
279         }
280
281         // load the textures
282         Texture *tex = 0, *detail = 0, *env = 0, *light = 0, *bump = 0;
283         const char *tpath;
284         
285         tpath = tex_path(m->texture1_map.name);
286         if(tpath && (tex = get_texture(tpath))) {
287                 mat->set_texture(tex, TEXTYPE_DIFFUSE);
288         }
289
290         tpath = tex_path(m->texture2_map.name);
291         if(tpath && (detail = get_texture(tpath))) {
292                 mat->set_texture(detail, TEXTYPE_DETAIL);
293         }
294
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;
299         }
300         
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);
304         }
305
306         tpath = tex_path(m->self_illum_map.name);
307         if(tpath && (light = get_texture(tpath))) {
308                 mat->set_texture(light, TEXTYPE_LIGHTMAP);
309         }
310
311         if(m->autorefl_map.flags & LIB3DS_USE_REFL_MAP) {
312                 mat->env_intensity = m->reflection_map.percent;
313                 
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);
317                 }
318                 
319                 Texture *cube_tex = new Texture(cube_sz, cube_sz, TEX_CUBE);
320                 add_texture(cube_tex);
321
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;
328                 }
329         }
330                 
331
332         return true;
333 }
334
335 static const char *tex_path(const char *path) {
336         if(!path || !*path) return 0;
337
338         static char texpath[TPATH_SIZE];
339
340         strncpy(texpath, data_path, TPATH_SIZE);
341         texpath[TPATH_SIZE - 1] = 0;
342
343         const char *tmp = strrchr(path, '\\');
344         if(tmp) path = tmp + 1;
345
346         char *tp_ptr = texpath + strlen(texpath);
347         do {
348                 *tp_ptr++ = tolower(*path++);
349         } while(*path);
350                 
351         return texpath;
352 }
353
354
355 bool load_lights(Lib3dsFile *file, Scene *scene) {
356         Lib3dsLight *lt = file->lights;
357         while(lt) {
358                 Light *light;
359                 
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);
366                         //TODO: attenuation
367                 } else {
368                         light = 0;      // TODO: support spotlights at some point
369                 }
370
371                 if(light) {
372                         if(load_keyframes(file, lt->name, LIB3DS_LIGHT_NODE, light)) {
373                                 light->set_position(Vector3());
374                         }
375                         scene->add_light(light);
376                 }
377
378                 lt = lt->next;
379         }
380
381         return true;
382 }
383
384 bool load_cameras(Lib3dsFile *file, Scene *scene) {
385         Lib3dsCamera *c = file->cameras;
386         while(c) {
387                 TargetCamera *cam = new TargetCamera;
388                 cam->name = c->name;
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);
392                 
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());
396
397                 if(load_keyframes(file, c->name, LIB3DS_CAMERA_NODE, cam)) {
398                         cam->set_position(Vector3());
399                 }
400                 //TODO: load_keyframes(file, ... hmmm where is the target node?
401                 
402                 scene->add_camera(cam);
403                 c = c->next;
404         }
405         return true;
406 }
407
408
409 #define FPS     30
410 #define FRAME_TO_TIME(x)        (((x) * 1000) / FPS)
411
412 static bool load_keyframes(Lib3dsFile *file, const char *name, Lib3dsNodeTypes type, XFormNode *node) {
413         if(!name || !*name) return false;
414         
415         Lib3dsNode *n = lib3ds_file_node_by_name(file, name, type);
416         if(!n) return false;
417
418         switch(type) {
419         case LIB3DS_OBJECT_NODE:
420                 {
421                         Lib3dsObjectData *obj = &n->data.object;
422                         std::vector<int> *frames = get_frames(obj);
423                         if(!frames) return false;
424
425                         for(int i=0; i<(int)frames->size(); i++) {
426                                 lib3ds_node_eval(n, (float)(*frames)[i]);
427                                         
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);
431
432                                 Keyframe key(PRS(pos, rot, scl), FRAME_TO_TIME((*frames)[i]));
433                                 node->add_keyframe(key);
434                         }
435                 }
436                 break;
437
438         case LIB3DS_LIGHT_NODE:
439                 {
440                         Lib3dsLightData *light = &n->data.light;
441                         std::vector<int> *frames = get_frames(light);
442                         if(!frames) return false;
443
444                         for(int i=0; i<(int)frames->size(); i++) {
445                                 lib3ds_node_eval(n, (float)(*frames)[i]);
446
447                                 Vector3 pos = CONV_VEC3(light->pos);
448
449                                 Keyframe key(PRS(pos, Quaternion()), FRAME_TO_TIME((*frames)[i]));
450                                 node->add_keyframe(key);
451                         }
452                 }
453                 break;
454
455         case LIB3DS_CAMERA_NODE:
456                 {
457                         Lib3dsCameraData *cam = &n->data.camera;
458                         std::vector<int> *frames = get_frames(cam);
459                         if(!frames) return false;
460
461                         for(int i=0; i<(int)frames->size(); i++) {
462                                 lib3ds_node_eval(n, (float)(*frames)[i]);
463
464                                 Vector3 pos = CONV_VEC3(cam->pos);
465
466                                 Keyframe key(PRS(pos, Quaternion()), FRAME_TO_TIME((*frames)[i]));
467                                 node->add_keyframe(key);
468                         }
469                 }
470                 break;
471
472                 /*
473         case LIB3DS_TARGET_NODE:
474                 {
475                         Lib3dsCameraData *targ = &n->data.target;
476                         std::vector<int> *frames = get_frames(targ);
477                         if(!frames) return false;
478
479                         for(int i=0; i<(int)frames->size(); i++) {
480                                 lib3ds_node_eval(n, (float)(*frames)[i]);
481
482                                 Vector3 pos = CONV_VEC3(targ->pos);
483
484                                 Keyframe key(PRS(pos, Quaternion()), FRAME_TO_TIME((*frames)[i]));
485                                 node->add_keyframe(key);
486                         }
487
488                 }
489                 break;
490                 */
491
492         default:
493                 break;
494         }
495
496         return true;
497 }
498
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()) {
503                 Object *obj = *iter;
504                 Lib3dsNode *n = lib3ds_file_node_by_name(file, obj->name.c_str(), LIB3DS_OBJECT_NODE);
505                 if(!n) {
506                         iter++;
507                         continue;
508                 }
509
510                 // get parent
511                 if(n->parent) {
512                         obj->parent = scene->get_node(n->parent->name);
513                 }
514                 
515                 // get children
516                 Lib3dsNode *child = n->childs;
517                 while(child) {
518                         XFormNode *child_node = scene->get_node(child->name);
519                         if(child_node) {
520                                 (*iter)->children.push_back(child_node);
521                         }
522                         child = child->next;
523                 }
524
525                 iter++;
526         }
527 }
528
529
530 /*
531 static void fix_hierarchy(XFormNode *node) {
532         if(!node) return;
533
534         if(node->parent) {
535                 XFormNode *parent = node->parent;
536                 node->parent = 0;
537                 PRS prs = node->get_prs(XFORM_LOCAL_PRS);
538                 node->parent = parent;
539                 
540                 PRS pprs = node->parent->get_prs(XFORM_LOCAL_PRS);
541
542                 Vector3 pos = prs.position.transformed(pprs.rotation.conjugate());
543                 
544                 node->set_position(pos);
545         }
546
547         for(int i=0; i<(int)node->children.size(); i++) {
548                 fix_hierarchy(node->children[i]);
549         }
550 }
551 */                      
552
553 static std::vector<int> *get_frames(Lib3dsObjectData *o) {
554         static std::vector<int> frames;
555         
556         Lib3dsLin3Key *pos_key = o->pos_track.keyL;
557         while(pos_key) {
558                 int frame = pos_key->tcb.frame;
559                 if(find(frames.begin(), frames.end(), frame) == frames.end()) {
560                         frames.push_back(frame);
561                 }
562                 pos_key = pos_key->next;
563         }
564
565         Lib3dsQuatKey *rot_key = o->rot_track.keyL;
566         while(rot_key) {
567                 int frame = rot_key->tcb.frame;
568                 if(find(frames.begin(), frames.end(), frame) == frames.end()) {
569                         frames.push_back(frame);
570                 }
571                 rot_key = rot_key->next;
572         }
573
574         Lib3dsLin3Key *scl_key = o->scl_track.keyL;
575         while(scl_key) {
576                 int frame = scl_key->tcb.frame;
577                 if(find(frames.begin(), frames.end(), frame) == frames.end()) {
578                         frames.push_back(frame);
579                 }
580                 scl_key = scl_key->next;
581         }
582
583         if(frames.size() > 1) return &frames;
584         return 0;
585 }
586
587 static std::vector<int> *get_frames(Lib3dsLightData *lt) {
588         static std::vector<int> frames;
589         
590         Lib3dsLin3Key *pos_key = lt->pos_track.keyL;
591         while(pos_key) {
592                 int frame = pos_key->tcb.frame;
593                 frames.push_back(frame);
594                 pos_key = pos_key->next;
595         }
596
597         if(frames.size() > 1) return &frames;
598         return 0;
599 }
600
601 static std::vector<int> *get_frames(Lib3dsCameraData *cam) {
602         static std::vector<int> frames;
603         
604         Lib3dsLin3Key *pos_key = cam->pos_track.keyL;
605         while(pos_key) {
606                 int frame = pos_key->tcb.frame;
607                 frames.push_back(frame);
608                 pos_key = pos_key->next;
609         }
610
611         if(frames.size() > 1) return &frames;
612         return 0;
613 }