root/OpenSceneGraph/branches/OpenSceneGraph-3.2/src/osgPlugins/3ds/lib3ds/lib3ds_file.c @ 14038

Revision 14038, 37.5 kB (checked in by robert, 31 hours ago)

From Alberto Luaces,"the current code uses the preprocessor for generating the plugin path in
a way that when CMAKE_INSTALL_PREFIX contains something along the lines
of

/usr/x86_64-linux-gnu/

it gets substituted as

/usr/x86_64-1-gnu/

that is, the string is preprocessed again, thereby making changes to
anything that matches any defined symbol, as "linux" in this example
(https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=763816).

Quoting that path directly in CMake scripts solves that problem.
"

  • Property svn:eol-style set to native
Line 
1/*
2    Copyright (C) 1996-2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
3    All rights reserved.
4
5    This program is free  software: you can redistribute it and/or modify
6    it under the terms of the GNU Lesser General Public License as published
7    by the Free Software Foundation, either version 2.1 of the License, or
8    (at your option) any later version.
9
10    Thisprogram  is  distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    GNU Lesser General Public License for more details.
14
15    You should  have received a copy of the GNU Lesser General Public License
16    along with  this program; If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "lib3ds_impl.h"
19
20
21static long
22fileio_seek_func(void *self, long offset, Lib3dsIoSeek origin) {
23    FILE *f = (FILE*)self;
24    int o;
25    switch (origin) {
26        case LIB3DS_SEEK_SET:
27            o = SEEK_SET;
28            break;
29
30        case LIB3DS_SEEK_CUR:
31            o = SEEK_CUR;
32            break;
33
34        case LIB3DS_SEEK_END:
35            o = SEEK_END;
36            break;
37
38        default:
39            assert(0);
40            return(0);
41    }
42    return (fseek(f, offset, o));
43}
44
45
46static long
47fileio_tell_func(void *self) {
48    FILE *f = (FILE*)self;
49    return(ftell(f));
50}
51
52
53static size_t
54fileio_read_func(void *self, void *buffer, size_t size) {
55    FILE *f = (FILE*)self;
56    return(fread(buffer, 1, size, f));
57}
58
59
60static size_t
61fileio_write_func(void *self, const void *buffer, size_t size) {
62    FILE *f = (FILE*)self;
63    return(fwrite(buffer, 1, size, f));
64}
65
66
67/*!
68 * Loads a .3DS file from disk into memory.
69 *
70 * \param filename  The filename of the .3DS file
71 *
72 * \return   A pointer to the Lib3dsFile structure containing the
73 *           data of the .3DS file.
74 *           If the .3DS file can not be loaded NULL is returned.
75 *
76 * \note     To free the returned structure use lib3ds_free.
77 *
78 * \see lib3ds_file_save
79 * \see lib3ds_file_new
80 * \see lib3ds_file_free
81 */
82Lib3dsFile*
83lib3ds_file_open(const char *filename) {
84    FILE *f;
85    Lib3dsFile *file;
86    Lib3dsIo io;
87
88    f = fopen(filename, "rb");
89    if (!f) {
90        return NULL;
91    }
92    file = lib3ds_file_new();
93    if (!file) {
94        fclose(f);
95        return NULL;
96    }
97
98    memset(&io, 0, sizeof(io));
99    io.self = f;
100    io.seek_func = fileio_seek_func;
101    io.tell_func = fileio_tell_func;
102    io.read_func = fileio_read_func;
103    io.write_func = fileio_write_func;
104    io.log_func = NULL;
105
106    if (!lib3ds_file_read(file, &io)) {
107        fclose(f);
108        free(file);
109        return NULL;
110    }
111
112    fclose(f);
113    return file;
114}
115
116
117/*!
118 * Saves a .3DS file from memory to disk.
119 *
120 * \param file      A pointer to a Lib3dsFile structure containing the
121 *                  the data that should be stored.
122 * \param filename  The filename of the .3DS file to store the data in.
123 *
124 * \return          TRUE on success, FALSE otherwise.
125 *
126 * \see lib3ds_file_open
127 */
128int
129lib3ds_file_save(Lib3dsFile *file, const char *filename) {
130    FILE *f;
131    Lib3dsIo io;
132    int result;
133
134    f = fopen(filename, "wb");
135    if (!f) {
136        return FALSE;
137    }
138
139    memset(&io, 0, sizeof(io));
140    io.self = f;
141    io.seek_func = fileio_seek_func;
142    io.tell_func = fileio_tell_func;
143    io.read_func = fileio_read_func;
144    io.write_func = fileio_write_func;
145    io.log_func = NULL;
146
147    result = lib3ds_file_write(file, &io);
148    fclose(f);
149    return result;
150}
151
152
153/*!
154 * Creates and returns a new, empty Lib3dsFile object.
155 *
156 * \return A pointer to the Lib3dsFile structure.
157 *  If the structure cannot be allocated, NULL is returned.
158 */
159Lib3dsFile*
160lib3ds_file_new() {
161    Lib3dsFile *file;
162
163    file = (Lib3dsFile*)calloc(sizeof(Lib3dsFile), 1);
164    if (!file) {
165        return(0);
166    }
167    file->mesh_version = 3;
168    file->master_scale = 1.0f;
169    file->keyf_revision = 5;
170    strcpy(file->name, "LIB3DS");
171
172    file->frames = 100;
173    file->segment_from = 0;
174    file->segment_to = 100;
175    file->current_frame = 0;
176
177    return(file);
178}
179
180
181/*!
182 * Free a Lib3dsFile object and all of its resources.
183 *
184 * \param file The Lib3dsFile object to be freed.
185 */
186void
187lib3ds_file_free(Lib3dsFile* file) {
188    assert(file);
189    lib3ds_file_reserve_materials(file, 0, TRUE);
190    lib3ds_file_reserve_cameras(file, 0, TRUE);
191    lib3ds_file_reserve_lights(file, 0, TRUE);
192    lib3ds_file_reserve_meshes(file, 0, TRUE);
193    {
194        Lib3dsNode *p, *q;
195
196        for (p = file->nodes; p; p = q) {
197            q = p->next;
198            lib3ds_node_free(p);
199        }
200    }
201    free(file);
202}
203
204
205/*!
206 * Evaluate all of the nodes in this Lib3dsFile object.
207 *
208 * \param file The Lib3dsFile object to be evaluated.
209 * \param t time value, between 0. and file->frames
210 *
211 * \see lib3ds_node_eval
212 */
213void
214lib3ds_file_eval(Lib3dsFile *file, float t) {
215    Lib3dsNode *p;
216
217    for (p = file->nodes; p != 0; p = p->next) {
218        lib3ds_node_eval(p, t);
219    }
220}
221
222
223static void
224named_object_read(Lib3dsFile *file, Lib3dsIo *io) {
225    Lib3dsChunk c;
226    char name[64];
227    uint16_t chunk;
228    Lib3dsMesh *mesh = NULL;
229    Lib3dsCamera *camera = NULL;
230    Lib3dsLight *light = NULL;
231    uint32_t object_flags;
232
233    lib3ds_chunk_read_start(&c, CHK_NAMED_OBJECT, io);
234
235    lib3ds_io_read_string(io, name, 64);
236    lib3ds_io_log(io, LIB3DS_LOG_INFO, "  NAME=%s", name);
237    lib3ds_chunk_read_tell(&c, io);
238
239    object_flags = 0;
240    while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
241        switch (chunk) {
242            case CHK_N_TRI_OBJECT: {
243                mesh = lib3ds_mesh_new(name);
244                lib3ds_file_insert_mesh(file, mesh, -1);
245                lib3ds_chunk_read_reset(&c, io);
246                lib3ds_mesh_read(file, mesh, io);
247                break;
248            }
249
250            case CHK_N_CAMERA: {
251                camera = lib3ds_camera_new(name);
252                lib3ds_file_insert_camera(file, camera, -1);
253                lib3ds_chunk_read_reset(&c, io);
254                lib3ds_camera_read(camera, io);
255                break;
256            }
257
258            case CHK_N_DIRECT_LIGHT: {
259                light = lib3ds_light_new(name);
260                lib3ds_file_insert_light(file, light, -1);
261                lib3ds_chunk_read_reset(&c, io);
262                lib3ds_light_read(light, io);
263                break;
264            }
265
266            case CHK_OBJ_HIDDEN:
267                object_flags |= LIB3DS_OBJECT_HIDDEN;
268                break;
269
270            case CHK_OBJ_DOESNT_CAST:
271                object_flags |= LIB3DS_OBJECT_DOESNT_CAST;
272                break;
273
274            case CHK_OBJ_VIS_LOFTER:
275                object_flags |= LIB3DS_OBJECT_VIS_LOFTER;
276                break;
277
278            case CHK_OBJ_MATTE:
279                object_flags |= LIB3DS_OBJECT_MATTE;
280                break;
281
282            case CHK_OBJ_DONT_RCVSHADOW:
283                object_flags |= LIB3DS_OBJECT_DONT_RCVSHADOW;
284                break;
285
286            case CHK_OBJ_FAST:
287                object_flags |= LIB3DS_OBJECT_FAST;
288                break;
289
290            case CHK_OBJ_FROZEN:
291                object_flags |= LIB3DS_OBJECT_FROZEN;
292                break;
293
294            default:
295                lib3ds_chunk_unknown(chunk, io);
296        }
297    }
298
299    if (mesh)
300        mesh->object_flags = object_flags;
301    if (camera)
302        camera->object_flags = object_flags;
303    if (light)
304        light->object_flags = object_flags;
305
306    lib3ds_chunk_read_end(&c, io);
307}
308
309
310static void
311ambient_read(Lib3dsFile *file, Lib3dsIo *io) {
312    Lib3dsChunk c;
313    uint16_t chunk;
314    int have_lin = FALSE;
315
316    lib3ds_chunk_read_start(&c, CHK_AMBIENT_LIGHT, io);
317
318    while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
319        switch (chunk) {
320            case CHK_LIN_COLOR_F: {
321                int i;
322                for (i = 0; i < 3; ++i) {
323                    file->ambient[i] = lib3ds_io_read_float(io);
324                }
325                have_lin = TRUE;
326                break;
327            }
328
329            case CHK_COLOR_F: {
330                /* gamma corrected color chunk
331                   replaced in 3ds R3 by LIN_COLOR_24 */
332                if (!have_lin) {
333                    int i;
334                    for (i = 0; i < 3; ++i) {
335                        file->ambient[i] = lib3ds_io_read_float(io);
336                    }
337                }
338                break;
339            }
340
341            default:
342                lib3ds_chunk_unknown(chunk, io);
343        }
344    }
345
346    lib3ds_chunk_read_end(&c, io);
347}
348
349
350static void
351mdata_read(Lib3dsFile *file, Lib3dsIo *io) {
352    Lib3dsChunk c;
353    uint16_t chunk;
354
355    lib3ds_chunk_read_start(&c, CHK_MDATA, io);
356
357    while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
358        switch (chunk) {
359            case CHK_MESH_VERSION: {
360                file->mesh_version = lib3ds_io_read_intd(io);
361                break;
362            }
363
364            case CHK_MASTER_SCALE: {
365                file->master_scale = lib3ds_io_read_float(io);
366                break;
367            }
368
369            case CHK_SHADOW_MAP_SIZE:
370            case CHK_LO_SHADOW_BIAS:
371            case CHK_HI_SHADOW_BIAS:
372            case CHK_SHADOW_SAMPLES:
373            case CHK_SHADOW_RANGE:
374            case CHK_SHADOW_FILTER:
375            case CHK_RAY_BIAS: {
376                lib3ds_chunk_read_reset(&c, io);
377                lib3ds_shadow_read(&file->shadow, io);
378                break;
379            }
380
381            case CHK_VIEWPORT_LAYOUT:
382            case CHK_DEFAULT_VIEW: {
383                lib3ds_chunk_read_reset(&c, io);
384                lib3ds_viewport_read(&file->viewport, io);
385                break;
386            }
387
388            case CHK_O_CONSTS: {
389                int i;
390                for (i = 0; i < 3; ++i) {
391                    file->construction_plane[i] = lib3ds_io_read_float(io);
392                }
393                break;
394            }
395
396            case CHK_AMBIENT_LIGHT: {
397                lib3ds_chunk_read_reset(&c, io);
398                ambient_read(file, io);
399                break;
400            }
401
402            case CHK_BIT_MAP:
403            case CHK_SOLID_BGND:
404            case CHK_V_GRADIENT:
405            case CHK_USE_BIT_MAP:
406            case CHK_USE_SOLID_BGND:
407            case CHK_USE_V_GRADIENT: {
408                lib3ds_chunk_read_reset(&c, io);
409                lib3ds_background_read(&file->background, io);
410                break;
411            }
412
413            case CHK_FOG:
414            case CHK_LAYER_FOG:
415            case CHK_DISTANCE_CUE:
416            case CHK_USE_FOG:
417            case CHK_USE_LAYER_FOG:
418            case CHK_USE_DISTANCE_CUE: {
419                lib3ds_chunk_read_reset(&c, io);
420                lib3ds_atmosphere_read(&file->atmosphere, io);
421                break;
422            }
423
424            case CHK_MAT_ENTRY: {
425                Lib3dsMaterial *material = lib3ds_material_new(NULL);
426                lib3ds_file_insert_material(file, material, -1);
427                lib3ds_chunk_read_reset(&c, io);
428                lib3ds_material_read(material, io);
429                break;
430            }
431
432            case CHK_NAMED_OBJECT: {
433                lib3ds_chunk_read_reset(&c, io);
434                named_object_read(file, io);
435                break;
436            }
437
438            default:
439                lib3ds_chunk_unknown(chunk, io);
440        }
441    }
442
443    lib3ds_chunk_read_end(&c, io);
444}
445
446
447static int
448compare_node_id( const void *a, const void *b ) {
449   return (int)((*((Lib3dsNode**)a))->node_id) - (int)((*((Lib3dsNode**)b))->node_id);
450}
451
452
453static int
454compare_node_id2( const void *a, const void *b ) {
455   // not a is a pointer in the calling bsearch routine the user_id is an unsigned, while the node_id is an unsigned short?!
456   return (int)(*((unsigned*)a)) - (int)((*((Lib3dsNode**)b))->node_id);
457}
458
459
460static void
461kfdata_read(Lib3dsFile *file, Lib3dsIo *io) {
462    Lib3dsChunk c;
463    uint16_t chunk;
464    unsigned num_nodes = 0;
465    //Lib3dsIoImpl *impl = (Lib3dsIoImpl*)io->impl;
466    Lib3dsNode *last = NULL;
467
468    lib3ds_chunk_read_start(&c, CHK_KFDATA, io);
469
470    while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
471        switch (chunk) {
472            case CHK_KFHDR: {
473                file->keyf_revision = lib3ds_io_read_word(io);
474                lib3ds_io_read_string(io, file->name, 12 + 1);
475                file->frames = lib3ds_io_read_intd(io);
476                break;
477            }
478
479            case CHK_KFSEG: {
480                file->segment_from = lib3ds_io_read_intd(io);
481                file->segment_to = lib3ds_io_read_intd(io);
482                break;
483            }
484
485            case CHK_KFCURTIME: {
486                file->current_frame = lib3ds_io_read_intd(io);
487                break;
488            }
489
490            case CHK_VIEWPORT_LAYOUT:
491            case CHK_DEFAULT_VIEW: {
492                lib3ds_chunk_read_reset(&c, io);
493                lib3ds_viewport_read(&file->viewport_keyf, io);
494                break;
495            }
496
497            case CHK_AMBIENT_NODE_TAG:
498            case CHK_OBJECT_NODE_TAG:
499            case CHK_CAMERA_NODE_TAG:
500            case CHK_TARGET_NODE_TAG:
501            case CHK_LIGHT_NODE_TAG:
502            case CHK_SPOTLIGHT_NODE_TAG:
503            case CHK_L_TARGET_NODE_TAG: {
504                Lib3dsNodeType type = 0;
505                Lib3dsNode *node;
506
507                switch (chunk) {
508                    case CHK_AMBIENT_NODE_TAG:
509                        type = LIB3DS_NODE_AMBIENT_COLOR;
510                        break;
511                    case CHK_OBJECT_NODE_TAG:
512                        type = LIB3DS_NODE_MESH_INSTANCE;
513                        break;
514                    case CHK_CAMERA_NODE_TAG:
515                        type = LIB3DS_NODE_CAMERA;
516                        break;
517                    case CHK_TARGET_NODE_TAG:
518                        type = LIB3DS_NODE_CAMERA_TARGET;
519                        break;
520                    case CHK_LIGHT_NODE_TAG:
521                        type = LIB3DS_NODE_OMNILIGHT;
522                        break;
523                    case CHK_SPOTLIGHT_NODE_TAG:
524                        type = LIB3DS_NODE_SPOTLIGHT;
525                        break;
526                    case CHK_L_TARGET_NODE_TAG:
527                        type = LIB3DS_NODE_SPOTLIGHT_TARGET;
528                        break;
529                }
530
531                node = lib3ds_node_new(type);
532                node->node_id = (unsigned short)(num_nodes++);
533                if (last) {
534                    last->next = node;
535                } else {
536                    file->nodes = node;
537                }
538                node->user_ptr = last;
539                last = node;
540                lib3ds_chunk_read_reset(&c, io);
541                lib3ds_node_read(node, io);
542                break;
543            }
544
545            default:
546                lib3ds_chunk_unknown(chunk, io);
547        }
548    }
549
550    {
551        Lib3dsNode **nodes = (Lib3dsNode **)malloc(num_nodes * sizeof(Lib3dsNode*));
552        unsigned i;
553        Lib3dsNode *p, *q, *parent;
554
555        p = file->nodes;
556        for (i = 0; i < num_nodes; ++i) {
557            nodes[i] = p;
558            p = p->next;
559        }
560        qsort(nodes, num_nodes, sizeof(Lib3dsNode*), compare_node_id);
561
562        p = last;
563        while (p) {
564            q = (Lib3dsNode *)p->user_ptr;
565            if (p->user_id != 65535) {
566                parent = *(Lib3dsNode**)bsearch(&p->user_id, nodes, num_nodes, sizeof(Lib3dsNode*), compare_node_id2);
567                if (parent) {
568                    q->next = p->next;
569                    p->next = parent->childs;
570                    p->parent = parent;
571                    parent->childs = p;
572                } else {
573                    /* TODO: warning */
574                }
575            }
576            p->user_id = 0;
577            p->user_ptr = NULL;
578            p = q;
579        }
580        free(nodes);
581    }
582
583    lib3ds_chunk_read_end(&c, io);
584}
585
586
587/*!
588 * Read 3ds file data into a Lib3dsFile object.
589 *
590 * \param file The Lib3dsFile object to be filled.
591 * \param io A Lib3dsIo object previously set up by the caller.
592 *
593 * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
594 */
595int
596lib3ds_file_read(Lib3dsFile *file, Lib3dsIo *io) {
597    Lib3dsChunk c;
598    uint16_t chunk;
599    Lib3dsIoImpl *impl;
600
601    lib3ds_io_setup(io);
602    impl = (Lib3dsIoImpl*)io->impl;
603
604    if (setjmp(impl->jmpbuf) != 0) {
605        lib3ds_io_cleanup(io);
606        return FALSE;
607    }
608
609    lib3ds_chunk_read_start(&c, 0, io);
610    switch (c.chunk) {
611        case CHK_MDATA: {
612            lib3ds_chunk_read_reset(&c, io);
613            mdata_read(file, io);
614            break;
615        }
616
617        case CHK_M3DMAGIC:
618        case CHK_MLIBMAGIC:
619        case CHK_CMAGIC: {
620            while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
621                switch (chunk) {
622                    case CHK_M3D_VERSION: {
623                        file->mesh_version = lib3ds_io_read_dword(io);
624                        break;
625                    }
626
627                    case CHK_MDATA: {
628                        lib3ds_chunk_read_reset(&c, io);
629                        mdata_read(file, io);
630                        break;
631                    }
632
633                    case CHK_KFDATA: {
634                        lib3ds_chunk_read_reset(&c, io);
635                        kfdata_read(file, io);
636                        break;
637                    }
638
639                    default:
640                        lib3ds_chunk_unknown(chunk, io);
641                }
642            }
643            break;
644        }
645
646        default:
647            lib3ds_chunk_unknown(c.chunk, io);
648            return FALSE;
649    }
650
651    lib3ds_chunk_read_end(&c, io);
652
653    memset(impl->jmpbuf, 0, sizeof(impl->jmpbuf));
654    lib3ds_io_cleanup(io);
655    return TRUE;
656}
657
658
659static void
660colorf_write(float rgb[3], Lib3dsIo *io) {
661    Lib3dsChunk c;
662
663    c.chunk = CHK_COLOR_F;
664    c.size = 18;
665    lib3ds_chunk_write(&c, io);
666    lib3ds_io_write_rgb(io, rgb);
667
668    c.chunk = CHK_LIN_COLOR_F;
669    c.size = 18;
670    lib3ds_chunk_write(&c, io);
671    lib3ds_io_write_rgb(io, rgb);
672}
673
674
675static void
676object_flags_write(uint32_t flags, Lib3dsIo *io) {
677    if (flags) {
678        Lib3dsChunk c;
679        c.size = 6;
680
681        if (flags & LIB3DS_OBJECT_HIDDEN) {
682            c.chunk = CHK_OBJ_HIDDEN;
683            lib3ds_chunk_write(&c, io);
684        }
685        if (flags & LIB3DS_OBJECT_VIS_LOFTER) {
686            c.chunk = CHK_OBJ_VIS_LOFTER;
687            lib3ds_chunk_write(&c, io);
688        }
689        if (flags & LIB3DS_OBJECT_DOESNT_CAST) {
690            c.chunk = CHK_OBJ_DOESNT_CAST;
691            lib3ds_chunk_write(&c, io);
692        }
693        if (flags & LIB3DS_OBJECT_MATTE) {
694            c.chunk = CHK_OBJ_MATTE;
695            lib3ds_chunk_write(&c, io);
696        }
697        if (flags & LIB3DS_OBJECT_DONT_RCVSHADOW) {
698            c.chunk = CHK_OBJ_DOESNT_CAST;
699            lib3ds_chunk_write(&c, io);
700        }
701        if (flags & LIB3DS_OBJECT_FAST) {
702            c.chunk = CHK_OBJ_FAST;
703            lib3ds_chunk_write(&c, io);
704        }
705        if (flags & LIB3DS_OBJECT_FROZEN) {
706            c.chunk = CHK_OBJ_FROZEN;
707            lib3ds_chunk_write(&c, io);
708        }
709    }
710}
711
712
713static void
714mdata_write(Lib3dsFile *file, Lib3dsIo *io) {
715    Lib3dsChunk c;
716
717    c.chunk = CHK_MDATA;
718    lib3ds_chunk_write_start(&c, io);
719
720    { /*---- LIB3DS_MESH_VERSION ----*/
721        Lib3dsChunk c;
722        c.chunk = CHK_MESH_VERSION;
723        c.size = 10;
724        lib3ds_chunk_write(&c, io);
725        lib3ds_io_write_intd(io, file->mesh_version);
726    }
727    { /*---- LIB3DS_MASTER_SCALE ----*/
728        Lib3dsChunk c;
729        c.chunk = CHK_MASTER_SCALE;
730        c.size = 10;
731        lib3ds_chunk_write(&c, io);
732        lib3ds_io_write_float(io, file->master_scale);
733    }
734    { /*---- LIB3DS_O_CONSTS ----*/
735        int i;
736        for (i = 0; i < 3; ++i) {
737            if (fabs(file->construction_plane[i]) > LIB3DS_EPSILON) {
738                break;
739            }
740        }
741        if (i < 3) {
742            Lib3dsChunk c;
743            c.chunk = CHK_O_CONSTS;
744            c.size = 18;
745            lib3ds_chunk_write(&c, io);
746            lib3ds_io_write_vector(io, file->construction_plane);
747        }
748    }
749
750    { /*---- LIB3DS_AMBIENT_LIGHT ----*/
751        int i;
752        for (i = 0; i < 3; ++i) {
753            if (fabs(file->ambient[i]) > LIB3DS_EPSILON) {
754                break;
755            }
756        }
757        if (i < 3) {
758            Lib3dsChunk c;
759            c.chunk = CHK_AMBIENT_LIGHT;
760            c.size = 42;
761            lib3ds_chunk_write(&c, io);
762            colorf_write(file->ambient, io);
763        }
764    }
765    lib3ds_background_write(&file->background, io);
766    lib3ds_atmosphere_write(&file->atmosphere, io);
767    lib3ds_shadow_write(&file->shadow, io);
768    lib3ds_viewport_write(&file->viewport, io);
769    {
770        int i;
771        for (i = 0; i < file->nmaterials; ++i) {
772            lib3ds_material_write(file->materials[i], io);
773        }
774    }
775    {
776        Lib3dsChunk c;
777        int i;
778
779        for (i = 0; i < file->ncameras; ++i) {
780            c.chunk = CHK_NAMED_OBJECT;
781            lib3ds_chunk_write_start(&c, io);
782            lib3ds_io_write_string(io, file->cameras[i]->name);
783            lib3ds_camera_write(file->cameras[i], io);
784            object_flags_write(file->cameras[i]->object_flags, io);
785            lib3ds_chunk_write_end(&c, io);
786        }
787    }
788    {
789        Lib3dsChunk c;
790        int i;
791
792        for (i = 0; i < file->nlights; ++i) {
793            c.chunk = CHK_NAMED_OBJECT;
794            lib3ds_chunk_write_start(&c, io);
795            lib3ds_io_write_string(io, file->lights[i]->name);
796            lib3ds_light_write(file->lights[i], io);
797            object_flags_write(file->lights[i]->object_flags, io);
798            lib3ds_chunk_write_end(&c, io);
799        }
800    }
801    {
802        Lib3dsChunk c;
803        int i;
804
805        for (i = 0; i < file->nmeshes; ++i) {
806            c.chunk = CHK_NAMED_OBJECT;
807            lib3ds_chunk_write_start(&c, io);
808            lib3ds_io_write_string(io, file->meshes[i]->name);
809            lib3ds_mesh_write(file, file->meshes[i], io);
810            object_flags_write(file->meshes[i]->object_flags, io);
811            lib3ds_chunk_write_end(&c, io);
812        }
813    }
814
815    lib3ds_chunk_write_end(&c, io);
816}
817
818
819
820static void
821nodes_write(Lib3dsNode *first_node, uint16_t *default_id, uint16_t parent_id, Lib3dsIo *io) {
822    Lib3dsNode *p;
823    for (p = first_node; p != NULL; p = p->next) {
824        uint16_t node_id;
825        if ((p->type == LIB3DS_NODE_AMBIENT_COLOR) || (p->node_id != 65535)) {
826            node_id = p->node_id;
827        } else {
828            node_id = *default_id;
829        }
830        ++(*default_id);
831        lib3ds_node_write(p, node_id, parent_id, io);
832
833        nodes_write(p->childs, default_id, node_id, io);
834    }
835}
836
837
838static void
839kfdata_write(Lib3dsFile *file, Lib3dsIo *io) {
840    Lib3dsChunk c;
841
842    if (!file->nodes) {
843        return;
844    }
845
846    c.chunk = CHK_KFDATA;
847    lib3ds_chunk_write_start(&c, io);
848
849    { /*---- LIB3DS_KFHDR ----*/
850        Lib3dsChunk c;
851        c.chunk = CHK_KFHDR;
852        c.size = 6 + 2 + (uint32_t)strlen(file->name) + 1 + 4;
853        lib3ds_chunk_write(&c, io);
854        lib3ds_io_write_intw(io, (int16_t)file->keyf_revision);
855        lib3ds_io_write_string(io, file->name);
856        lib3ds_io_write_intd(io, file->frames);
857    }
858    { /*---- LIB3DS_KFSEG ----*/
859        Lib3dsChunk c;
860        c.chunk = CHK_KFSEG;
861        c.size = 14;
862        lib3ds_chunk_write(&c, io);
863        lib3ds_io_write_intd(io, file->segment_from);
864        lib3ds_io_write_intd(io, file->segment_to);
865    }
866    { /*---- LIB3DS_KFCURTIME ----*/
867        Lib3dsChunk c;
868        c.chunk = CHK_KFCURTIME;
869        c.size = 10;
870        lib3ds_chunk_write(&c, io);
871        lib3ds_io_write_intd(io, file->current_frame);
872    }
873    lib3ds_viewport_write(&file->viewport_keyf, io);
874
875    {
876        uint16_t default_id = 0;
877        nodes_write(file->nodes, &default_id, 65535, io);
878    }
879
880    lib3ds_chunk_write_end(&c, io);
881}
882
883
884/*!
885 * Write 3ds file data from a Lib3dsFile object to a file.
886 *
887 * \param file The Lib3dsFile object to be written.
888 * \param io A Lib3dsIo object previously set up by the caller.
889 *
890 * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
891 */
892int
893lib3ds_file_write(Lib3dsFile *file, Lib3dsIo *io) {
894    Lib3dsChunk c;
895    Lib3dsIoImpl *impl;
896
897    lib3ds_io_setup(io);
898    impl = (Lib3dsIoImpl*)io->impl;
899
900    if (setjmp(impl->jmpbuf) != 0) {
901        lib3ds_io_cleanup(io);
902        return FALSE;
903    }
904
905    c.chunk = CHK_M3DMAGIC;
906    lib3ds_chunk_write_start(&c, io);
907
908    { /*---- LIB3DS_M3D_VERSION ----*/
909        Lib3dsChunk c;
910
911        c.chunk = CHK_M3D_VERSION;
912        c.size = 10;
913        lib3ds_chunk_write(&c, io);
914        lib3ds_io_write_dword(io, file->mesh_version);
915    }
916
917    mdata_write(file, io);
918    kfdata_write(file, io);
919
920    lib3ds_chunk_write_end(&c, io);
921
922    memset(impl->jmpbuf, 0, sizeof(impl->jmpbuf));
923    lib3ds_io_cleanup(io);
924    return TRUE;
925}
926
927
928void lib3ds_file_reserve_materials(Lib3dsFile *file, int size, int force) {
929    assert(file);
930    lib3ds_util_reserve_array((void***)&file->materials, &file->nmaterials, &file->materials_size,
931                              size, force, (Lib3dsFreeFunc)lib3ds_material_free);
932}
933
934
935void
936lib3ds_file_insert_material(Lib3dsFile *file, Lib3dsMaterial *material, int index) {
937    assert(file);
938    lib3ds_util_insert_array((void***)&file->materials, &file->nmaterials, &file->materials_size, material, index);
939}
940
941
942void
943lib3ds_file_remove_material(Lib3dsFile *file, int index) {
944    assert(file);
945    lib3ds_util_remove_array((void***)&file->materials, &file->nmaterials, index, (Lib3dsFreeFunc)lib3ds_material_free);
946}
947
948
949int
950lib3ds_file_material_by_name(Lib3dsFile *file, const char *name) {
951    int i;
952
953    assert(file);
954    for (i = 0; i < file->nmaterials; ++i) {
955        if (strcmp(file->materials[i]->name, name) == 0) {
956            return(i);
957        }
958    }
959    return -1;
960}
961
962
963void
964lib3ds_file_reserve_cameras(Lib3dsFile *file, int size, int force) {
965    assert(file);
966    lib3ds_util_reserve_array((void***)&file->cameras, &file->ncameras, &file->cameras_size,
967                              size, force, (Lib3dsFreeFunc)lib3ds_camera_free);
968}
969
970
971void
972lib3ds_file_insert_camera(Lib3dsFile *file, Lib3dsCamera *camera, int index) {
973    assert(file);
974    lib3ds_util_insert_array((void***)&file->cameras, &file->ncameras, &file->cameras_size, camera, index);
975}
976
977
978void
979lib3ds_file_remove_camera(Lib3dsFile *file, int index) {
980    assert(file);
981    lib3ds_util_remove_array((void***)&file->cameras, &file->ncameras, index, (Lib3dsFreeFunc)lib3ds_camera_free);
982}
983
984
985int
986lib3ds_file_camera_by_name(Lib3dsFile *file, const char *name) {
987    int i;
988
989    assert(file);
990    for (i = 0; i < file->ncameras; ++i) {
991        if (strcmp(file->cameras[i]->name, name) == 0) {
992            return(i);
993        }
994    }
995    return -1;
996}
997
998
999void
1000lib3ds_file_reserve_lights(Lib3dsFile *file, int size, int force) {
1001    assert(file);
1002    lib3ds_util_reserve_array((void***)&file->lights, &file->nlights, &file->lights_size,
1003                              size, force, (Lib3dsFreeFunc)lib3ds_light_free);
1004}
1005
1006
1007void
1008lib3ds_file_insert_light(Lib3dsFile *file, Lib3dsLight *light, int index) {
1009    assert(file);
1010    lib3ds_util_insert_array((void***)&file->lights, &file->nlights, &file->lights_size, light, index);
1011}
1012
1013
1014void
1015lib3ds_file_remove_light(Lib3dsFile *file, int index) {
1016    assert(file);
1017    lib3ds_util_remove_array((void***)&file->lights, &file->nlights, index, (Lib3dsFreeFunc)lib3ds_light_free);
1018}
1019
1020
1021int
1022lib3ds_file_light_by_name(Lib3dsFile *file, const char *name) {
1023    int i;
1024
1025    assert(file);
1026    for (i = 0; i < file->nlights; ++i) {
1027        if (strcmp(file->lights[i]->name, name) == 0) {
1028            return(i);
1029        }
1030    }
1031    return -1;
1032}
1033
1034
1035void
1036lib3ds_file_reserve_meshes(Lib3dsFile *file, int size, int force) {
1037    assert(file);
1038    lib3ds_util_reserve_array((void***)&file->meshes, &file->nmeshes, &file->meshes_size,
1039                               size, force, (Lib3dsFreeFunc)lib3ds_mesh_free);
1040}
1041
1042
1043void
1044lib3ds_file_insert_mesh(Lib3dsFile *file, Lib3dsMesh *mesh, int index) {
1045    assert(file);
1046    lib3ds_util_insert_array((void***)&file->meshes, &file->nmeshes, &file->meshes_size, mesh, index);
1047}
1048
1049
1050void
1051lib3ds_file_remove_mesh(Lib3dsFile *file, int index) {
1052    assert(file);
1053    lib3ds_util_remove_array((void***)&file->meshes, &file->nmeshes, index, (Lib3dsFreeFunc)lib3ds_mesh_free);
1054}
1055
1056
1057int
1058lib3ds_file_mesh_by_name(Lib3dsFile *file, const char *name) {
1059    int i;
1060
1061    assert(file);
1062    for (i = 0; i < file->nmeshes; ++i) {
1063        if (strcmp(file->meshes[i]->name, name) == 0) {
1064            return(i);
1065        }
1066    }
1067    return -1;
1068}
1069
1070
1071Lib3dsMesh*
1072lib3ds_file_mesh_for_node(Lib3dsFile *file, Lib3dsNode *node) {
1073    int index;
1074    Lib3dsMeshInstanceNode *n;
1075
1076    if (node->type != LIB3DS_NODE_MESH_INSTANCE)
1077        return NULL;
1078    n = (Lib3dsMeshInstanceNode*)node;
1079
1080    index = lib3ds_file_mesh_by_name(file, node->name);
1081
1082    return (index >= 0)? file->meshes[index] : NULL;
1083}
1084
1085
1086/*!
1087 * Return a node object by name and type.
1088 *
1089 * This function performs a recursive search for the specified node.
1090 * Both name and type must match.
1091 *
1092 * \param file The Lib3dsFile to be searched.
1093 * \param name The target node name.
1094 * \param type The target node type
1095 *
1096 * \return A pointer to the first matching node, or NULL if not found.
1097 *
1098 * \see lib3ds_node_by_name
1099 */
1100Lib3dsNode*
1101lib3ds_file_node_by_name(Lib3dsFile *file, const char* name, Lib3dsNodeType type) {
1102    Lib3dsNode *p, *q;
1103
1104    assert(file);
1105    for (p = file->nodes; p != 0; p = p->next) {
1106        if ((p->type == type) && (strcmp(p->name, name) == 0)) {
1107            return(p);
1108        }
1109        q = lib3ds_node_by_name(p, name, type);
1110        if (q) {
1111            return(q);
1112        }
1113    }
1114    return(0);
1115}
1116
1117
1118/*!
1119 * Return a node object by id.
1120 *
1121 * This function performs a recursive search for the specified node.
1122 *
1123 * \param file The Lib3dsFile to be searched.
1124 * \param node_id The target node id.
1125 *
1126 * \return A pointer to the first matching node, or NULL if not found.
1127 *
1128 * \see lib3ds_node_by_id
1129 */
1130Lib3dsNode*
1131lib3ds_file_node_by_id(Lib3dsFile *file, uint16_t node_id) {
1132    Lib3dsNode *p, *q;
1133
1134    assert(file);
1135    for (p = file->nodes; p != 0; p = p->next) {
1136        if (p->node_id == node_id) {
1137            return(p);
1138        }
1139        q = lib3ds_node_by_id(p, node_id);
1140        if (q) {
1141            return(q);
1142        }
1143    }
1144    return(0);
1145}
1146
1147
1148void
1149lib3ds_file_append_node(Lib3dsFile *file, Lib3dsNode *node, Lib3dsNode *parent) {
1150    Lib3dsNode *p;
1151
1152    assert(file);
1153    assert(node);
1154    p = parent? parent->childs : file->nodes;
1155    if (p) {
1156        while (p->next) {
1157            p = p->next;
1158        }
1159        p->next = node;
1160    } else {
1161        if (parent) {
1162            parent->childs = node;
1163        } else {
1164            file->nodes = node;
1165        }
1166    }
1167    node->parent = parent;
1168    node->next = NULL;
1169}
1170
1171
1172void
1173lib3ds_file_insert_node(Lib3dsFile *file, Lib3dsNode *node, Lib3dsNode *before) {
1174    Lib3dsNode *p, *q;
1175
1176    assert(node);
1177    assert(file);
1178
1179    if (before) {
1180        p = before->parent? before->parent->childs : file->nodes;
1181        assert(p);
1182        q = NULL;
1183        while (p != before) {
1184            q = p;
1185            p = p->next;
1186        }
1187        if (q) {
1188            node->next = q->next;
1189            q->next = node;
1190        } else {
1191            node->next = file->nodes;
1192            file->nodes = node;
1193        }
1194        node->parent = before->parent;
1195    } else {
1196        node->next = file->nodes;
1197        node->parent = NULL;
1198        file->nodes = node;
1199    }
1200}
1201
1202
1203/*!
1204 * Remove a node from the a Lib3dsFile object.
1205 *
1206 * \param file The Lib3dsFile object to be modified.
1207 * \param node The Lib3dsNode object to be removed from file
1208 *
1209 * \return LIB3DS_TRUE on success, LIB3DS_FALSE if node is not found in file
1210 */
1211void
1212lib3ds_file_remove_node(Lib3dsFile *file, Lib3dsNode *node) {
1213    Lib3dsNode *p, *n;
1214
1215    if (node->parent) {
1216        for (p = 0, n = node->parent->childs; n; p = n, n = n->next) {
1217            if (n == node) {
1218                break;
1219            }
1220        }
1221        if (!n) {
1222            return;
1223        }
1224
1225        if (!p) {
1226            node->parent->childs = n->next;
1227        } else {
1228            p->next = n->next;
1229        }
1230    } else {
1231        for (p = 0, n = file->nodes; n; p = n, n = n->next) {
1232            if (n == node) {
1233                break;
1234            }
1235        }
1236        if (!n) {
1237            return;
1238        }
1239
1240        if (!p) {
1241            file->nodes = n->next;
1242        } else {
1243            p->next = n->next;
1244        }
1245    }
1246}
1247
1248
1249static void
1250file_minmax_node_id_impl(Lib3dsFile *file, Lib3dsNode *node, uint16_t *min_id, uint16_t *max_id) {
1251    Lib3dsNode *p;
1252
1253    if (min_id && (*min_id > node->node_id))
1254        *min_id = node->node_id;
1255    if (max_id && (*max_id < node->node_id))
1256        *max_id = node->node_id;
1257
1258    p = node->childs;
1259    while (p) {
1260        file_minmax_node_id_impl(file, p, min_id, max_id);
1261        p = p->next;
1262    }
1263}
1264
1265
1266void
1267lib3ds_file_minmax_node_id(Lib3dsFile *file, uint16_t *min_id, uint16_t *max_id) {
1268    Lib3dsNode *p;
1269
1270    if (min_id)
1271        *min_id = 65535;
1272    if (max_id)
1273        *max_id = 0;
1274
1275    p = file->nodes;
1276    while (p) {
1277        file_minmax_node_id_impl(file, p, min_id, max_id);
1278        p = p->next;
1279    }
1280}
1281
1282
1283void
1284lib3ds_file_bounding_box_of_objects(Lib3dsFile *file, int
1285                                    include_meshes, int include_cameras, int include_lights,
1286                                    float bmin[3], float bmax[3]) {
1287    bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
1288    bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
1289
1290    if (include_meshes) {
1291        float lmin[3], lmax[3];
1292        int i;
1293        for (i = 0; i < file->nmeshes; ++i) {
1294            lib3ds_mesh_bounding_box(file->meshes[i], lmin, lmax);
1295            lib3ds_vector_min(bmin, lmin);
1296            lib3ds_vector_max(bmax, lmax);
1297        }
1298    }
1299    if (include_cameras) {
1300        int i;
1301        for (i = 0; i < file->ncameras; ++i) {
1302            lib3ds_vector_min(bmin, file->cameras[i]->position);
1303            lib3ds_vector_max(bmax, file->cameras[i]->position);
1304            lib3ds_vector_min(bmin, file->cameras[i]->target);
1305            lib3ds_vector_max(bmax, file->cameras[i]->target);
1306        }
1307    }
1308    if (include_lights) {
1309        int i;
1310        for (i = 0; i < file->ncameras; ++i) {
1311            lib3ds_vector_min(bmin, file->lights[i]->position);
1312            lib3ds_vector_max(bmax, file->lights[i]->position);
1313            if (file->lights[i]->spot_light) {
1314                lib3ds_vector_min(bmin, file->lights[i]->target);
1315                lib3ds_vector_max(bmax, file->lights[i]->target);
1316            }
1317        }
1318    }
1319}
1320
1321
1322static void
1323file_bounding_box_of_nodes_impl(Lib3dsNode *node, Lib3dsFile *file,
1324                                int include_meshes, int include_cameras, int include_lights,
1325                                float bmin[3], float bmax[3], float matrix[4][4]) {
1326    switch (node->type) {
1327        case LIB3DS_NODE_AMBIENT_COLOR:
1328            break;
1329           
1330        case LIB3DS_NODE_MESH_INSTANCE:
1331            if (include_meshes) {
1332                int index;
1333                Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
1334
1335                index = lib3ds_file_mesh_by_name(file, n->instance_name);
1336                if (index < 0)
1337                    index = lib3ds_file_mesh_by_name(file, node->name);
1338                if (index >= 0) {
1339                    Lib3dsMesh *mesh;
1340                    float inv_matrix[4][4], M[4][4];
1341                    float v[3];
1342                    int i;
1343
1344                    mesh = file->meshes[index];
1345                    lib3ds_matrix_copy(inv_matrix, mesh->matrix);
1346                    lib3ds_matrix_inv(inv_matrix);
1347                    lib3ds_matrix_mult(M, matrix, node->matrix);
1348                    lib3ds_matrix_translate(M, -n->pivot[0], -n->pivot[1], -n->pivot[2]);
1349                    lib3ds_matrix_mult(M, M, inv_matrix);
1350
1351                    for (i = 0; i < mesh->nvertices; ++i) {
1352                        lib3ds_vector_transform(v, M, mesh->vertices[i]);
1353                        lib3ds_vector_min(bmin, v);
1354                        lib3ds_vector_max(bmax, v);
1355                    }
1356                }
1357            }
1358            break;
1359
1360        case LIB3DS_NODE_CAMERA:
1361        case LIB3DS_NODE_CAMERA_TARGET:
1362            if (include_cameras) {
1363                float z[3], v[3];
1364                float M[4][4];
1365                lib3ds_matrix_mult(M, matrix, node->matrix);
1366                lib3ds_vector_zero(z);
1367                lib3ds_vector_transform(v, M, z);
1368                lib3ds_vector_min(bmin, v);
1369                lib3ds_vector_max(bmax, v);
1370            }
1371            break;
1372
1373        case LIB3DS_NODE_OMNILIGHT:
1374        case LIB3DS_NODE_SPOTLIGHT:
1375        case LIB3DS_NODE_SPOTLIGHT_TARGET:
1376            if (include_lights) {
1377                float z[3], v[3];
1378                float M[4][4];
1379                lib3ds_matrix_mult(M, matrix, node->matrix);
1380                lib3ds_vector_zero(z);
1381                lib3ds_vector_transform(v, M, z);
1382                lib3ds_vector_min(bmin, v);
1383                lib3ds_vector_max(bmax, v);
1384            }
1385            break;
1386    }
1387    {
1388        Lib3dsNode *p = node->childs;
1389        while (p) {
1390            file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax, matrix);
1391            p = p->next;
1392        }
1393    }
1394}
1395
1396
1397void
1398lib3ds_file_bounding_box_of_nodes(Lib3dsFile *file,
1399                                  int include_meshes, int include_cameras,int include_lights,
1400                                  float bmin[3], float bmax[3], float matrix[4][4]) {
1401    Lib3dsNode *p;
1402    float M[4][4];
1403
1404    if (matrix) {
1405        lib3ds_matrix_copy(M, matrix);
1406    } else {
1407        lib3ds_matrix_identity(M);
1408    }
1409
1410    bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
1411    bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
1412    p = file->nodes;
1413    while (p) {
1414        file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax, M);
1415        p = p->next;
1416    }
1417}
1418
1419
1420void
1421lib3ds_file_create_nodes_for_meshes(Lib3dsFile *file) {
1422    Lib3dsNode *p;
1423    int i;
1424    for (i = 0; i < file->nmeshes; ++i) {
1425        Lib3dsMesh *mesh = file->meshes[i];
1426        p = lib3ds_node_new(LIB3DS_NODE_MESH_INSTANCE);
1427        strcpy(p->name, mesh->name);
1428        lib3ds_file_insert_node(file, p, NULL);
1429    }
1430}
Note: See TracBrowser for help on using the browser.