root/OpenSceneGraph/trunk/src/osgPlugins/3ds/lib3ds/lib3ds_file.c @ 10853

Revision 10853, 38.8 kB (checked in by robert, 5 years ago)

From Sukender,
"Here is our freshly baked 3DS reader/writer (named 'v0.5' to differentiate from previous one). Changes are against trunk rev. 10819.
Short changelog (from rev 10819):
- Added 3DS writer
- Sync'd with latest lib3DS
- Added options, especially "flattenMatrixTransforms" to get the "old" behaviour (else the reader correctly maps to OSG the transforms from the 3DS file).

What should be done:
- Check with pivot points, with and without "flattenMatrixTransforms" option.
- We ran tests on it, but we can never be 100% sure there is no bug. Testing from the community would of course be helpful."

RevLine 
[10853]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 (*((Lib3dsNode**)a))->node_id - (*((Lib3dsNode**)b))->node_id;
450}
451
452
453static int 
454compare_node_id2( const void *a, const void *b ) {
455   return *((unsigned short*)a) - (*((Lib3dsNode**)b))->node_id;
456}
457
458
459static void
460kfdata_read(Lib3dsFile *file, Lib3dsIo *io) {
461    Lib3dsChunk c;
462    uint16_t chunk;
463    unsigned num_nodes = 0;
464    //Lib3dsIoImpl *impl = (Lib3dsIoImpl*)io->impl;
465    Lib3dsNode *last = NULL;
466
467    lib3ds_chunk_read_start(&c, CHK_KFDATA, io);
468
469    while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
470        switch (chunk) {
471            case CHK_KFHDR: {
472                file->keyf_revision = lib3ds_io_read_word(io);
473                lib3ds_io_read_string(io, file->name, 12 + 1);
474                file->frames = lib3ds_io_read_intd(io);
475                break;
476            }
477
478            case CHK_KFSEG: {
479                file->segment_from = lib3ds_io_read_intd(io);
480                file->segment_to = lib3ds_io_read_intd(io);
481                break;
482            }
483
484            case CHK_KFCURTIME: {
485                file->current_frame = lib3ds_io_read_intd(io);
486                break;
487            }
488
489            case CHK_VIEWPORT_LAYOUT:
490            case CHK_DEFAULT_VIEW: {
491                lib3ds_chunk_read_reset(&c, io);
492                lib3ds_viewport_read(&file->viewport_keyf, io);
493                break;
494            }
495
496            case CHK_AMBIENT_NODE_TAG:
497            case CHK_OBJECT_NODE_TAG:
498            case CHK_CAMERA_NODE_TAG:
499            case CHK_TARGET_NODE_TAG:
500            case CHK_LIGHT_NODE_TAG:
501            case CHK_SPOTLIGHT_NODE_TAG:
502            case CHK_L_TARGET_NODE_TAG: {
503                Lib3dsNodeType type = 0;
504                Lib3dsNode *node;
505
506                switch (chunk) {
507                    case CHK_AMBIENT_NODE_TAG:
508                        type = LIB3DS_NODE_AMBIENT_COLOR;
509                        break;
510                    case CHK_OBJECT_NODE_TAG:
511                        type = LIB3DS_NODE_MESH_INSTANCE;
512                        break;
513                    case CHK_CAMERA_NODE_TAG:
514                        type = LIB3DS_NODE_CAMERA;
515                        break;
516                    case CHK_TARGET_NODE_TAG:
517                        type = LIB3DS_NODE_CAMERA_TARGET;
518                        break;
519                    case CHK_LIGHT_NODE_TAG:
520                        type = LIB3DS_NODE_OMNILIGHT;
521                        break;
522                    case CHK_SPOTLIGHT_NODE_TAG:
523                        type = LIB3DS_NODE_SPOTLIGHT;
524                        break;
525                    case CHK_L_TARGET_NODE_TAG:
526                        type = LIB3DS_NODE_SPOTLIGHT_TARGET;
527                        break;
528                }
529
530                node = lib3ds_node_new(type);
531                node->node_id = (unsigned short)(num_nodes++);
532                if (last) {
533                    last->next = node;
534                } else {
535                    file->nodes = node;
536                }
537                node->user_ptr = last;
538                last = node;
539                lib3ds_chunk_read_reset(&c, io);
540                lib3ds_node_read(node, io);
541                break;
542            }
543
544            default:
545                lib3ds_chunk_unknown(chunk, io);
546        }
547    }
548
549    {
550        Lib3dsNode **nodes = (Lib3dsNode **)malloc(num_nodes * sizeof(Lib3dsNode*));
551        unsigned i;
552        Lib3dsNode *p, *q, *parent;
553
554        p = file->nodes;
555        for (i = 0; i < num_nodes; ++i) {
556            nodes[i] = p;
557            p = p->next;
558        }
559        qsort(nodes, num_nodes, sizeof(Lib3dsNode*), compare_node_id);
560
561        p = last;
562        while (p) {
563            q = (Lib3dsNode *)p->user_ptr;
564            if (p->user_id != 65535) {
565                parent = *(Lib3dsNode**)bsearch(&p->user_id, nodes, num_nodes, sizeof(Lib3dsNode*), compare_node_id2);
566                if (parent) {
567                    q->next = p->next;   
568                    p->next = parent->childs;
569                    p->parent = parent;
570                    parent->childs = p;
571                } else {
572                    /* TODO: warning */
573                }
574            }
575            p->user_id = 0;
576            p->user_ptr = NULL;
577            p = q;
578        }
579        free(nodes);
580    }
581
582    lib3ds_chunk_read_end(&c, io);
583}
584
585
586/*!
587 * Read 3ds file data into a Lib3dsFile object.
588 *
589 * \param file The Lib3dsFile object to be filled.
590 * \param io A Lib3dsIo object previously set up by the caller.
591 *
592 * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
593 */
594int
595lib3ds_file_read(Lib3dsFile *file, Lib3dsIo *io) {
596    Lib3dsChunk c;
597    uint16_t chunk;
598    Lib3dsIoImpl *impl;
599
600    lib3ds_io_setup(io);
601    impl = (Lib3dsIoImpl*)io->impl;
602
603    if (setjmp(impl->jmpbuf) != 0) {
604        lib3ds_io_cleanup(io);
605        return FALSE;
606    }
607
608    lib3ds_chunk_read_start(&c, 0, io);
609    switch (c.chunk) {
610        case CHK_MDATA: {
611            lib3ds_chunk_read_reset(&c, io);
612            mdata_read(file, io);
613            break;
614        }
615
616        case CHK_M3DMAGIC:
617        case CHK_MLIBMAGIC:
618        case CHK_CMAGIC: {
619            while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
620                switch (chunk) {
621                    case CHK_M3D_VERSION: {
622                        file->mesh_version = lib3ds_io_read_dword(io);
623                        break;
624                    }
625
626                    case CHK_MDATA: {
627                        lib3ds_chunk_read_reset(&c, io);
628                        mdata_read(file, io);
629                        break;
630                    }
631
632                    case CHK_KFDATA: {
633                        lib3ds_chunk_read_reset(&c, io);
634                        kfdata_read(file, io);
635                        break;
636                    }
637
638                    default:
639                        lib3ds_chunk_unknown(chunk, io);
640                }
641            }
642            break;
643        }
644
645        default:
646            lib3ds_chunk_unknown(c.chunk, io);
647            return FALSE;
648    }
649
650    lib3ds_chunk_read_end(&c, io);
651
652    memset(impl->jmpbuf, 0, sizeof(impl->jmpbuf));
653    lib3ds_io_cleanup(io);
654    return TRUE;
655}
656
657
658static void
659colorf_write(float rgb[3], Lib3dsIo *io) {
660    Lib3dsChunk c;
661
662    c.chunk = CHK_COLOR_F;
663    c.size = 18;
664    lib3ds_chunk_write(&c, io);
665    lib3ds_io_write_rgb(io, rgb);
666
667    c.chunk = CHK_LIN_COLOR_F;
668    c.size = 18;
669    lib3ds_chunk_write(&c, io);
670    lib3ds_io_write_rgb(io, rgb);
671}
672
673
674static void
675object_flags_write(uint32_t flags, Lib3dsIo *io) {
676    if (flags) {
677        Lib3dsChunk c;
678        c.size = 6;
679
680        if (flags & LIB3DS_OBJECT_HIDDEN) {
681            c.chunk = CHK_OBJ_HIDDEN;
682            lib3ds_chunk_write(&c, io);
683        }
684        if (flags & LIB3DS_OBJECT_VIS_LOFTER) {
685            c.chunk = CHK_OBJ_VIS_LOFTER;
686            lib3ds_chunk_write(&c, io);
687        }
688        if (flags & LIB3DS_OBJECT_DOESNT_CAST) {
689            c.chunk = CHK_OBJ_DOESNT_CAST;
690            lib3ds_chunk_write(&c, io);
691        }
692        if (flags & LIB3DS_OBJECT_MATTE) {
693            c.chunk = CHK_OBJ_MATTE;
694            lib3ds_chunk_write(&c, io);
695        }
696        if (flags & LIB3DS_OBJECT_DONT_RCVSHADOW) {
697            c.chunk = CHK_OBJ_DOESNT_CAST;
698            lib3ds_chunk_write(&c, io);
699        }
700        if (flags & LIB3DS_OBJECT_FAST) {
701            c.chunk = CHK_OBJ_FAST;
702            lib3ds_chunk_write(&c, io);
703        }
704        if (flags & LIB3DS_OBJECT_FROZEN) {
705            c.chunk = CHK_OBJ_FROZEN;
706            lib3ds_chunk_write(&c, io);
707        }
708    }
709}
710
711
712static void
713mdata_write(Lib3dsFile *file, Lib3dsIo *io) {
714    Lib3dsChunk c;
715
716    c.chunk = CHK_MDATA;
717    lib3ds_chunk_write_start(&c, io);
718
719    { /*---- LIB3DS_MESH_VERSION ----*/
720        Lib3dsChunk c;
721        c.chunk = CHK_MESH_VERSION;
722        c.size = 10;
723        lib3ds_chunk_write(&c, io);
724        lib3ds_io_write_intd(io, file->mesh_version);
725    }
726    { /*---- LIB3DS_MASTER_SCALE ----*/
727        Lib3dsChunk c;
728        c.chunk = CHK_MASTER_SCALE;
729        c.size = 10;
730        lib3ds_chunk_write(&c, io);
731        lib3ds_io_write_float(io, file->master_scale);
732    }
733    { /*---- LIB3DS_O_CONSTS ----*/
734        int i;
735        for (i = 0; i < 3; ++i) {
736            if (fabs(file->construction_plane[i]) > LIB3DS_EPSILON) {
737                break;
738            }
739        }
740        if (i < 3) {
741            Lib3dsChunk c;
742            c.chunk = CHK_O_CONSTS;
743            c.size = 18;
744            lib3ds_chunk_write(&c, io);
745            lib3ds_io_write_vector(io, file->construction_plane);
746        }
747    }
748
749    { /*---- LIB3DS_AMBIENT_LIGHT ----*/
750        int i;
751        for (i = 0; i < 3; ++i) {
752            if (fabs(file->ambient[i]) > LIB3DS_EPSILON) {
753                break;
754            }
755        }
756        if (i < 3) {
757            Lib3dsChunk c;
758            c.chunk = CHK_AMBIENT_LIGHT;
759            c.size = 42;
760            lib3ds_chunk_write(&c, io);
761            colorf_write(file->ambient, io);
762        }
763    }
764    lib3ds_background_write(&file->background, io);
765    lib3ds_atmosphere_write(&file->atmosphere, io);
766    lib3ds_shadow_write(&file->shadow, io);
767    lib3ds_viewport_write(&file->viewport, io);
768    {
769        int i;
770        for (i = 0; i < file->nmaterials; ++i) {
771            lib3ds_material_write(file->materials[i], io);
772        }
773    }
774    {
775        Lib3dsChunk c;
776        int i;
777
778        for (i = 0; i < file->ncameras; ++i) {
779            c.chunk = CHK_NAMED_OBJECT;
780            lib3ds_chunk_write_start(&c, io);
781            lib3ds_io_write_string(io, file->cameras[i]->name);
782            lib3ds_camera_write(file->cameras[i], io);
783            object_flags_write(file->cameras[i]->object_flags, io);
784            lib3ds_chunk_write_end(&c, io);
785        }
786    }
787    {
788        Lib3dsChunk c;
789        int i;
790
791        for (i = 0; i < file->nlights; ++i) {
792            c.chunk = CHK_NAMED_OBJECT;
793            lib3ds_chunk_write_start(&c, io);
794            lib3ds_io_write_string(io, file->lights[i]->name);
795            lib3ds_light_write(file->lights[i], io);
796            object_flags_write(file->lights[i]->object_flags, io);
797            lib3ds_chunk_write_end(&c, io);
798        }
799    }
800    {
801        Lib3dsChunk c;
802        int i;
803
804        for (i = 0; i < file->nmeshes; ++i) {
805            c.chunk = CHK_NAMED_OBJECT;
806            lib3ds_chunk_write_start(&c, io);
807            lib3ds_io_write_string(io, file->meshes[i]->name);
808            lib3ds_mesh_write(file, file->meshes[i], io);
809            object_flags_write(file->meshes[i]->object_flags, io);
810            lib3ds_chunk_write_end(&c, io);
811        }
812    }
813
814    lib3ds_chunk_write_end(&c, io);
815}
816
817
818
819static void
820nodes_write(Lib3dsNode *first_node, uint16_t *default_id, uint16_t parent_id, Lib3dsIo *io) {
821    Lib3dsNode *p;
822    for (p = first_node; p != NULL; p = p->next) {
823        uint16_t node_id;
824        if ((p->type == LIB3DS_NODE_AMBIENT_COLOR) || (p->node_id != 65535)) {
825            node_id = p->node_id;
826        } else {
827            node_id = *default_id;
828        }
829        ++(*default_id);
830        lib3ds_node_write(p, node_id, parent_id, io);
831
832        nodes_write(p->childs, default_id, node_id, io);
833    }
834}
835
836
837static void
838kfdata_write(Lib3dsFile *file, Lib3dsIo *io) {
839    Lib3dsChunk c;
840
841    if (!file->nodes) {
842        return;
843    }
844
845    c.chunk = CHK_KFDATA;
846    lib3ds_chunk_write_start(&c, io);
847
848    { /*---- LIB3DS_KFHDR ----*/
849        Lib3dsChunk c;
850        c.chunk = CHK_KFHDR;
851        c.size = 6 + 2 + (uint32_t)strlen(file->name) + 1 + 4;
852        lib3ds_chunk_write(&c, io);
853        lib3ds_io_write_intw(io, (int16_t)file->keyf_revision);
854        lib3ds_io_write_string(io, file->name);
855        lib3ds_io_write_intd(io, file->frames);
856    }
857    { /*---- LIB3DS_KFSEG ----*/
858        Lib3dsChunk c;
859        c.chunk = CHK_KFSEG;
860        c.size = 14;
861        lib3ds_chunk_write(&c, io);
862        lib3ds_io_write_intd(io, file->segment_from);
863        lib3ds_io_write_intd(io, file->segment_to);
864    }
865    { /*---- LIB3DS_KFCURTIME ----*/
866        Lib3dsChunk c;
867        c.chunk = CHK_KFCURTIME;
868        c.size = 10;
869        lib3ds_chunk_write(&c, io);
870        lib3ds_io_write_intd(io, file->current_frame);
871    }
872    lib3ds_viewport_write(&file->viewport_keyf, io);
873
874    {
875        uint16_t default_id = 0;
876        nodes_write(file->nodes, &default_id, 65535, io);
877    }
878
879    lib3ds_chunk_write_end(&c, io);
880}
881
882
883/*!
884 * Write 3ds file data from a Lib3dsFile object to a file.
885 *
886 * \param file The Lib3dsFile object to be written.
887 * \param io A Lib3dsIo object previously set up by the caller.
888 *
889 * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
890 */
891int
892lib3ds_file_write(Lib3dsFile *file, Lib3dsIo *io) {
893    Lib3dsChunk c;
894    Lib3dsIoImpl *impl;
895
896    lib3ds_io_setup(io);
897    impl = (Lib3dsIoImpl*)io->impl;
898
899    if (setjmp(impl->jmpbuf) != 0) {
900        lib3ds_io_cleanup(io);
901        return FALSE;
902    }
903
904    c.chunk = CHK_M3DMAGIC;
905    lib3ds_chunk_write_start(&c, io);
906
907    { /*---- LIB3DS_M3D_VERSION ----*/
908        Lib3dsChunk c;
909
910        c.chunk = CHK_M3D_VERSION;
911        c.size = 10;
912        lib3ds_chunk_write(&c, io);
913        lib3ds_io_write_dword(io, file->mesh_version);
914    }
915
916    mdata_write(file, io);
917    kfdata_write(file, io);
918
919    lib3ds_chunk_write_end(&c, io);
920
921    memset(impl->jmpbuf, 0, sizeof(impl->jmpbuf));
922    lib3ds_io_cleanup(io);
923    return TRUE;
924}
925
926
927void lib3ds_file_reserve_materials(Lib3dsFile *file, int size, int force) {
928    assert(file);
929    lib3ds_util_reserve_array((void***)&file->materials, &file->nmaterials, &file->materials_size,
930                              size, force, (Lib3dsFreeFunc)lib3ds_material_free);
931}
932
933
934void
935lib3ds_file_insert_material(Lib3dsFile *file, Lib3dsMaterial *material, int index) {
936    assert(file);
937    lib3ds_util_insert_array((void***)&file->materials, &file->nmaterials, &file->materials_size, material, index);
938}
939
940
941void
942lib3ds_file_remove_material(Lib3dsFile *file, int index) {
943    assert(file);
944    lib3ds_util_remove_array((void***)&file->materials, &file->nmaterials, index, (Lib3dsFreeFunc)lib3ds_material_free);
945}
946
947
948int
949lib3ds_file_material_by_name(Lib3dsFile *file, const char *name) {
950    int i;
951
952    assert(file);
953    for (i = 0; i < file->nmaterials; ++i) {
954        if (strcmp(file->materials[i]->name, name) == 0) {
955            return(i);
956        }
957    }
958    return -1;
959}
960
961
962void 
963lib3ds_file_reserve_cameras(Lib3dsFile *file, int size, int force) {
964    assert(file);
965    lib3ds_util_reserve_array((void***)&file->cameras, &file->ncameras, &file->cameras_size,
966                              size, force, (Lib3dsFreeFunc)lib3ds_camera_free);
967}
968
969
970void
971lib3ds_file_insert_camera(Lib3dsFile *file, Lib3dsCamera *camera, int index) {
972    assert(file);
973    lib3ds_util_insert_array((void***)&file->cameras, &file->ncameras, &file->cameras_size, camera, index);
974}
975
976
977void
978lib3ds_file_remove_camera(Lib3dsFile *file, int index) {
979    assert(file);
980    lib3ds_util_remove_array((void***)&file->cameras, &file->ncameras, index, (Lib3dsFreeFunc)lib3ds_camera_free);
981}
982
983
984int
985lib3ds_file_camera_by_name(Lib3dsFile *file, const char *name) {
986    int i;
987
988    assert(file);
989    for (i = 0; i < file->ncameras; ++i) {
990        if (strcmp(file->cameras[i]->name, name) == 0) {
991            return(i);
992        }
993    }
994    return -1;
995}
996
997
998void 
999lib3ds_file_reserve_lights(Lib3dsFile *file, int size, int force) {
1000    assert(file);
1001    lib3ds_util_reserve_array((void***)&file->lights, &file->nlights, &file->lights_size,
1002                              size, force, (Lib3dsFreeFunc)lib3ds_light_free);
1003}
1004
1005
1006void
1007lib3ds_file_insert_light(Lib3dsFile *file, Lib3dsLight *light, int index) {
1008    assert(file);
1009    lib3ds_util_insert_array((void***)&file->lights, &file->nlights, &file->lights_size, light, index);
1010}
1011
1012
1013void
1014lib3ds_file_remove_light(Lib3dsFile *file, int index) {
1015    assert(file);
1016    lib3ds_util_remove_array((void***)&file->lights, &file->nlights, index, (Lib3dsFreeFunc)lib3ds_light_free);
1017}
1018
1019
1020int
1021lib3ds_file_light_by_name(Lib3dsFile *file, const char *name) {
1022    int i;
1023
1024    assert(file);
1025    for (i = 0; i < file->nlights; ++i) {
1026        if (strcmp(file->lights[i]->name, name) == 0) {
1027            return(i);
1028        }
1029    }
1030    return -1;
1031}
1032
1033
1034void 
1035lib3ds_file_reserve_meshes(Lib3dsFile *file, int size, int force) {
1036    assert(file);
1037    lib3ds_util_reserve_array((void***)&file->meshes, &file->nmeshes, &file->meshes_size,
1038                               size, force, (Lib3dsFreeFunc)lib3ds_mesh_free);
1039}
1040
1041
1042void
1043lib3ds_file_insert_mesh(Lib3dsFile *file, Lib3dsMesh *mesh, int index) {
1044    assert(file);
1045    lib3ds_util_insert_array((void***)&file->meshes, &file->nmeshes, &file->meshes_size, mesh, index);
1046}
1047
1048
1049void
1050lib3ds_file_remove_mesh(Lib3dsFile *file, int index) {
1051    assert(file);
1052    lib3ds_util_remove_array((void***)&file->meshes, &file->nmeshes, index, (Lib3dsFreeFunc)lib3ds_mesh_free);
1053}
1054
1055
1056int
1057lib3ds_file_mesh_by_name(Lib3dsFile *file, const char *name) {
1058    int i;
1059
1060    assert(file);
1061    for (i = 0; i < file->nmeshes; ++i) {
1062        if (strcmp(file->meshes[i]->name, name) == 0) {
1063            return(i);
1064        }
1065    }
1066    return -1;
1067}
1068
1069
1070Lib3dsMesh*
1071lib3ds_file_mesh_for_node(Lib3dsFile *file, Lib3dsNode *node) {
1072    int index;
1073    Lib3dsMeshInstanceNode *n;
1074
1075    if (node->type != LIB3DS_NODE_MESH_INSTANCE)
1076        return NULL;
1077    n = (Lib3dsMeshInstanceNode*)node;
1078
1079    index = lib3ds_file_mesh_by_name(file, node->name);
1080
1081    return (index >= 0)? file->meshes[index] : NULL;
1082}
1083
1084
1085/*!
1086 * Return a node object by name and type.
1087 *
1088 * This function performs a recursive search for the specified node.
1089 * Both name and type must match.
1090 *
1091 * \param file The Lib3dsFile to be searched.
1092 * \param name The target node name.
1093 * \param type The target node type
1094 *
1095 * \return A pointer to the first matching node, or NULL if not found.
1096 *
1097 * \see lib3ds_node_by_name
1098 */
1099Lib3dsNode*
1100lib3ds_file_node_by_name(Lib3dsFile *file, const char* name, Lib3dsNodeType type) {
1101    Lib3dsNode *p, *q;
1102
1103    assert(file);
1104    for (p = file->nodes; p != 0; p = p->next) {
1105        if ((p->type == type) && (strcmp(p->name, name) == 0)) {
1106            return(p);
1107        }
1108        q = lib3ds_node_by_name(p, name, type);
1109        if (q) {
1110            return(q);
1111        }
1112    }
1113    return(0);
1114}
1115
1116
1117/*!
1118 * Return a node object by id.
1119 *
1120 * This function performs a recursive search for the specified node.
1121 *
1122 * \param file The Lib3dsFile to be searched.
1123 * \param node_id The target node id.
1124 *
1125 * \return A pointer to the first matching node, or NULL if not found.
1126 *
1127 * \see lib3ds_node_by_id
1128 */
1129Lib3dsNode*
1130lib3ds_file_node_by_id(Lib3dsFile *file, uint16_t node_id) {
1131    Lib3dsNode *p, *q;
1132
1133    assert(file);
1134    for (p = file->nodes; p != 0; p = p->next) {
1135        if (p->node_id == node_id) {
1136            return(p);
1137        }
1138        q = lib3ds_node_by_id(p, node_id);
1139        if (q) {
1140            return(q);
1141        }
1142    }
1143    return(0);
1144}
1145
1146
1147void
1148lib3ds_file_append_node(Lib3dsFile *file, Lib3dsNode *node, Lib3dsNode *parent) {
1149    Lib3dsNode *p;
1150
1151    assert(file);
1152    assert(node);
1153    p = parent? parent->childs : file->nodes;
1154    if (p) {
1155        while (p->next) {
1156            p = p->next;
1157        }
1158        p->next = node;
1159    } else {
1160        if (parent) {
1161            parent->childs = node;
1162        } else {
1163            file->nodes = node;
1164        }
1165    }
1166    node->parent = parent;
1167    node->next = NULL;
1168}
1169
1170
1171void
1172lib3ds_file_insert_node(Lib3dsFile *file, Lib3dsNode *node, Lib3dsNode *before) {
1173    Lib3dsNode *p, *q;
1174
1175    assert(node);
1176    assert(file);
1177
1178    if (before) {
1179        p = before->parent? before->parent->childs : file->nodes;
1180        assert(p);
1181        q = NULL;
1182        while (p != before) {
1183            q = p;
1184            p = p->next;
1185        }
1186        if (q) {
1187            node->next = q->next;
1188            q->next = node;
1189        } else {
1190            node->next = file->nodes;
1191            file->nodes = node;
1192        }
1193        node->parent = before->parent;
1194    } else {
1195        node->next = file->nodes;
1196        node->parent = NULL;
1197        file->nodes = node;
1198    }
1199}
1200
1201
1202/*!
1203 * Remove a node from the a Lib3dsFile object.
1204 *
1205 * \param file The Lib3dsFile object to be modified.
1206 * \param node The Lib3dsNode object to be removed from file
1207 *
1208 * \return LIB3DS_TRUE on success, LIB3DS_FALSE if node is not found in file
1209 */
1210void
1211lib3ds_file_remove_node(Lib3dsFile *file, Lib3dsNode *node) {
1212    Lib3dsNode *p, *n;
1213
1214    if (node->parent) {
1215        for (p = 0, n = node->parent->childs; n; p = n, n = n->next) {
1216            if (n == node) {
1217                break;
1218            }
1219        }
1220        if (!n) {
1221            return;
1222        }
1223
1224        if (!p) {
1225            node->parent->childs = n->next;
1226        } else {
1227            p->next = n->next;
1228        }
1229    } else {
1230        for (p = 0, n = file->nodes; n; p = n, n = n->next) {
1231            if (n == node) {
1232                break;
1233            }
1234        }
1235        if (!n) {
1236            return;
1237        }
1238
1239        if (!p) {
1240            file->nodes = n->next;
1241        } else {
1242            p->next = n->next;
1243        }
1244    }
1245}
1246
1247
1248static void
1249file_minmax_node_id_impl(Lib3dsFile *file, Lib3dsNode *node, uint16_t *min_id, uint16_t *max_id) {
1250    Lib3dsNode *p;
1251   
1252    if (min_id && (*min_id > node->node_id))
1253        *min_id = node->node_id;
1254    if (max_id && (*max_id < node->node_id))
1255        *max_id = node->node_id;
1256   
1257    p = node->childs;
1258    while (p) {
1259        file_minmax_node_id_impl(file, p, min_id, max_id);
1260        p = p->next;
1261    }
1262}
1263
1264
1265void 
1266lib3ds_file_minmax_node_id(Lib3dsFile *file, uint16_t *min_id, uint16_t *max_id) {
1267    Lib3dsNode *p;
1268   
1269    if (min_id)
1270        *min_id = 65535;
1271    if (max_id)
1272        *max_id = 0;
1273
1274    p = file->nodes;
1275    while (p) {
1276        file_minmax_node_id_impl(file, p, min_id, max_id);
1277        p = p->next;
1278    }
1279}
1280
1281
1282void
1283lib3ds_file_bounding_box_of_objects(Lib3dsFile *file, int 
1284                                    include_meshes, int include_cameras, int include_lights,
1285                                    float bmin[3], float bmax[3]) {
1286    bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
1287    bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
1288
1289    if (include_meshes) {
1290        float lmin[3], lmax[3];
1291        int i;
1292        for (i = 0; i < file->nmeshes; ++i) {
1293            lib3ds_mesh_bounding_box(file->meshes[i], lmin, lmax);
1294            lib3ds_vector_min(bmin, lmin);
1295            lib3ds_vector_max(bmax, lmax);
1296        }
1297    }
1298    if (include_cameras) {
1299        int i;
1300        for (i = 0; i < file->ncameras; ++i) {
1301            lib3ds_vector_min(bmin, file->cameras[i]->position);
1302            lib3ds_vector_max(bmax, file->cameras[i]->position);
1303            lib3ds_vector_min(bmin, file->cameras[i]->target);
1304            lib3ds_vector_max(bmax, file->cameras[i]->target);
1305        }
1306    }
1307    if (include_lights) {
1308        int i;
1309        for (i = 0; i < file->ncameras; ++i) {
1310            lib3ds_vector_min(bmin, file->lights[i]->position);
1311            lib3ds_vector_max(bmax, file->lights[i]->position);
1312            if (file->lights[i]->spot_light) {
1313                lib3ds_vector_min(bmin, file->lights[i]->target);
1314                lib3ds_vector_max(bmax, file->lights[i]->target);
1315            }
1316        }
1317    }
1318}
1319
1320
1321static void
1322file_bounding_box_of_nodes_impl(Lib3dsNode *node, Lib3dsFile *file,
1323                                int include_meshes, int include_cameras, int include_lights,
1324                                float bmin[3], float bmax[3], float matrix[4][4]) {
1325    switch (node->type) {
1326        case LIB3DS_NODE_MESH_INSTANCE:
1327            if (include_meshes) {
1328                int index;
1329                Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
1330
1331                index = lib3ds_file_mesh_by_name(file, n->instance_name);
1332                if (index < 0)
1333                    index = lib3ds_file_mesh_by_name(file, node->name);
1334                if (index >= 0) {
1335                    Lib3dsMesh *mesh;
1336                    float inv_matrix[4][4], M[4][4];
1337                    float v[3];
1338                    int i;
1339
1340                    mesh = file->meshes[index];
1341                    lib3ds_matrix_copy(inv_matrix, mesh->matrix);
1342                    lib3ds_matrix_inv(inv_matrix);
1343                    lib3ds_matrix_mult(M, matrix, node->matrix);
1344                    lib3ds_matrix_translate(M, -n->pivot[0], -n->pivot[1], -n->pivot[2]);
1345                    lib3ds_matrix_mult(M, M, inv_matrix);
1346
1347                    for (i = 0; i < mesh->nvertices; ++i) {
1348                        lib3ds_vector_transform(v, M, mesh->vertices[i]);
1349                        lib3ds_vector_min(bmin, v);
1350                        lib3ds_vector_max(bmax, v);
1351                    }
1352                }
1353            }
1354            break;
1355
1356        case LIB3DS_NODE_CAMERA:
1357        case LIB3DS_NODE_CAMERA_TARGET:
1358            if (include_cameras) {
1359                float z[3], v[3];
1360                float M[4][4];
1361                lib3ds_matrix_mult(M, matrix, node->matrix);
1362                lib3ds_vector_zero(z);
1363                lib3ds_vector_transform(v, M, z);
1364                lib3ds_vector_min(bmin, v);
1365                lib3ds_vector_max(bmax, v);
1366            }
1367            break;
1368
1369        case LIB3DS_NODE_OMNILIGHT:
1370        case LIB3DS_NODE_SPOTLIGHT:
1371        case LIB3DS_NODE_SPOTLIGHT_TARGET:
1372            if (include_lights) {
1373                float z[3], v[3];
1374                float M[4][4];
1375                lib3ds_matrix_mult(M, matrix, node->matrix);
1376                lib3ds_vector_zero(z);
1377                lib3ds_vector_transform(v, M, z);
1378                lib3ds_vector_min(bmin, v);
1379                lib3ds_vector_max(bmax, v);
1380            }
1381            break;
1382    }
1383    {
1384        Lib3dsNode *p = node->childs;
1385        while (p) {
1386            file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax, matrix);
1387            p = p->next;
1388        }
1389    }
1390}
1391
1392
1393void
1394lib3ds_file_bounding_box_of_nodes(Lib3dsFile *file,
1395                                  int include_meshes, int include_cameras,int include_lights,
1396                                  float bmin[3], float bmax[3], float matrix[4][4]) {
1397    Lib3dsNode *p;
1398    float M[4][4];
1399
1400    if (matrix) {
1401        lib3ds_matrix_copy(M, matrix);
1402    } else {
1403        lib3ds_matrix_identity(M);
1404    }
1405
1406    bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
1407    bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
1408    p = file->nodes;
1409    while (p) {
1410        file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax, M);
1411        p = p->next;
1412    }
1413}
1414
1415
1416void
1417lib3ds_file_create_nodes_for_meshes(Lib3dsFile *file) {
1418    Lib3dsNode *p;
1419    int i;
1420    for (i = 0; i < file->nmeshes; ++i) {
1421        Lib3dsMesh *mesh = file->meshes[i];
1422        p = lib3ds_node_new(LIB3DS_NODE_MESH_INSTANCE);
1423        strcpy(p->name, mesh->name);
1424        lib3ds_file_insert_node(file, p, NULL);
1425    }
1426}
Note: See TracBrowser for help on using the browser.