2 * The 3D Studio File Format Library
3 * Copyright (C) 1996-2001 by J.E. Hoffmann <je-h@gmx.net>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or (at
9 * your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 * License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * $Id: file.c,v 1.23 2005/01/11 10:20:36 madmac Exp $
23 #include <lib3ds/file.h>
24 #include <lib3ds/chunk.h>
25 #include <lib3ds/io.h>
26 #include <lib3ds/material.h>
27 #include <lib3ds/mesh.h>
28 #include <lib3ds/camera.h>
29 #include <lib3ds/light.h>
30 #include <lib3ds/node.h>
31 #include <lib3ds/vector.h>
42 * \defgroup file Files
44 * \author J.E. Hoffmann <je-h@gmx.net>
49 fileio_error_func(void *self)
51 FILE *f = (FILE*)self;
57 fileio_seek_func(void *self, long offset, Lib3dsIoSeek origin)
59 FILE *f = (FILE*)self;
75 return (fseek(f, offset, o));
80 fileio_tell_func(void *self)
82 FILE *f = (FILE*)self;
88 fileio_read_func(void *self, Lib3dsByte *buffer, int size)
90 FILE *f = (FILE*)self;
91 return(fread(buffer, 1, size, f));
96 fileio_write_func(void *self, const Lib3dsByte *buffer, int size)
98 FILE *f = (FILE*)self;
99 return(fwrite(buffer, 1, size, f));
104 * Loads a .3DS file from disk into memory.
106 * \param filename The filename of the .3DS file
108 * \return A pointer to the Lib3dsFile structure containing the
109 * data of the .3DS file.
110 * If the .3DS file can not be loaded NULL is returned.
112 * \note To free the returned structure use lib3ds_free.
114 * \see lib3ds_file_save
115 * \see lib3ds_file_new
116 * \see lib3ds_file_free
121 lib3ds_file_load(const char *filename)
128 f = fopen(filename, "rb");
132 file = lib3ds_file_new();
146 lib3ds_file_free(file);
151 if (!lib3ds_file_read(file, io)) {
164 * Saves a .3DS file from memory to disk.
166 * \param file A pointer to a Lib3dsFile structure containing the
167 * the data that should be stored.
168 * \param filename The filename of the .3DS file to store the data in.
170 * \return TRUE on success, FALSE otherwise.
172 * \see lib3ds_file_load
177 lib3ds_file_save(Lib3dsFile *file, const char *filename)
183 f = fopen(filename, "wb");
185 return(LIB3DS_FALSE);
200 result = lib3ds_file_write(file, io);
210 * Creates and returns a new, empty Lib3dsFile object.
212 * \return A pointer to the Lib3dsFile structure.
213 * If the structure cannot be allocated, NULL is returned.
222 file=(Lib3dsFile*)calloc(sizeof(Lib3dsFile),1);
226 file->mesh_version=3;
227 file->master_scale=1.0f;
228 file->keyf_revision=5;
229 strcpy(file->name, "LIB3DS");
232 file->segment_from=0;
233 file->segment_to=100;
234 file->current_frame=0;
241 * Free a Lib3dsFile object and all of its resources.
243 * \param file The Lib3dsFile object to be freed.
248 lib3ds_file_free(Lib3dsFile* file)
251 lib3ds_viewport_set_views(&file->viewport,0);
253 Lib3dsMaterial *p,*q;
255 for (p=file->materials; p; p=q) {
257 lib3ds_material_free(p);
264 for (p=file->cameras; p; p=q) {
266 lib3ds_camera_free(p);
273 for (p=file->lights; p; p=q) {
275 lib3ds_light_free(p);
282 for (p=file->meshes; p; p=q) {
291 for (p=file->nodes; p; p=q) {
301 * Evaluate all of the nodes in this Lib3dsFile object.
303 * \param file The Lib3dsFile object to be evaluated.
304 * \param t time value, between 0. and file->frames
306 * \see lib3ds_node_eval
311 lib3ds_file_eval(Lib3dsFile *file, Lib3dsFloat t)
315 for (p=file->nodes; p!=0; p=p->next) {
316 lib3ds_node_eval(p, t);
322 named_object_read(Lib3dsFile *file, Lib3dsIo *io)
328 if (!lib3ds_chunk_read_start(&c, LIB3DS_NAMED_OBJECT, io)) {
329 return(LIB3DS_FALSE);
331 if (!lib3ds_io_read_string(io, name, 64)) {
332 return(LIB3DS_FALSE);
334 lib3ds_chunk_dump_info(" NAME=%s", name);
335 lib3ds_chunk_read_tell(&c, io);
337 while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
339 case LIB3DS_N_TRI_OBJECT:
343 mesh=lib3ds_mesh_new(name);
345 return(LIB3DS_FALSE);
347 lib3ds_chunk_read_reset(&c, io);
348 if (!lib3ds_mesh_read(mesh, io)) {
349 return(LIB3DS_FALSE);
351 lib3ds_file_insert_mesh(file, mesh);
354 case LIB3DS_N_CAMERA:
356 Lib3dsCamera *camera;
358 camera=lib3ds_camera_new(name);
360 return(LIB3DS_FALSE);
362 lib3ds_chunk_read_reset(&c, io);
363 if (!lib3ds_camera_read(camera, io)) {
364 return(LIB3DS_FALSE);
366 lib3ds_file_insert_camera(file, camera);
369 case LIB3DS_N_DIRECT_LIGHT:
373 light=lib3ds_light_new(name);
375 return(LIB3DS_FALSE);
377 lib3ds_chunk_read_reset(&c, io);
378 if (!lib3ds_light_read(light, io)) {
379 return(LIB3DS_FALSE);
381 lib3ds_file_insert_light(file, light);
385 lib3ds_chunk_unknown(chunk);
389 lib3ds_chunk_read_end(&c, io);
395 ambient_read(Lib3dsFile *file, Lib3dsIo *io)
399 Lib3dsBool have_lin=LIB3DS_FALSE;
401 if (!lib3ds_chunk_read_start(&c, LIB3DS_AMBIENT_LIGHT, io)) {
402 return(LIB3DS_FALSE);
405 while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
407 case LIB3DS_LIN_COLOR_F:
410 for (i=0; i<3; ++i) {
411 file->ambient[i]=lib3ds_io_read_float(io);
414 have_lin=LIB3DS_TRUE;
418 /* gamma corrected color chunk
419 replaced in 3ds R3 by LIN_COLOR_24 */
422 for (i=0; i<3; ++i) {
423 file->ambient[i]=lib3ds_io_read_float(io);
429 lib3ds_chunk_unknown(chunk);
433 lib3ds_chunk_read_end(&c, io);
439 mdata_read(Lib3dsFile *file, Lib3dsIo *io)
444 if (!lib3ds_chunk_read_start(&c, LIB3DS_MDATA, io)) {
445 return(LIB3DS_FALSE);
448 while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
450 case LIB3DS_MESH_VERSION:
452 file->mesh_version=lib3ds_io_read_intd(io);
455 case LIB3DS_MASTER_SCALE:
457 file->master_scale=lib3ds_io_read_float(io);
460 case LIB3DS_SHADOW_MAP_SIZE:
461 case LIB3DS_LO_SHADOW_BIAS:
462 case LIB3DS_HI_SHADOW_BIAS:
463 case LIB3DS_SHADOW_SAMPLES:
464 case LIB3DS_SHADOW_RANGE:
465 case LIB3DS_SHADOW_FILTER:
466 case LIB3DS_RAY_BIAS:
468 lib3ds_chunk_read_reset(&c, io);
469 if (!lib3ds_shadow_read(&file->shadow, io)) {
470 return(LIB3DS_FALSE);
474 case LIB3DS_VIEWPORT_LAYOUT:
475 case LIB3DS_DEFAULT_VIEW:
477 lib3ds_chunk_read_reset(&c, io);
478 if (!lib3ds_viewport_read(&file->viewport, io)) {
479 return(LIB3DS_FALSE);
483 case LIB3DS_O_CONSTS:
486 for (i=0; i<3; ++i) {
487 file->construction_plane[i]=lib3ds_io_read_float(io);
491 case LIB3DS_AMBIENT_LIGHT:
493 lib3ds_chunk_read_reset(&c, io);
494 if (!ambient_read(file, io)) {
495 return(LIB3DS_FALSE);
500 case LIB3DS_SOLID_BGND:
501 case LIB3DS_V_GRADIENT:
502 case LIB3DS_USE_BIT_MAP:
503 case LIB3DS_USE_SOLID_BGND:
504 case LIB3DS_USE_V_GRADIENT:
506 lib3ds_chunk_read_reset(&c, io);
507 if (!lib3ds_background_read(&file->background, io)) {
508 return(LIB3DS_FALSE);
513 case LIB3DS_LAYER_FOG:
514 case LIB3DS_DISTANCE_CUE:
516 case LIB3DS_USE_LAYER_FOG:
517 case LIB3DS_USE_DISTANCE_CUE:
519 lib3ds_chunk_read_reset(&c, io);
520 if (!lib3ds_atmosphere_read(&file->atmosphere, io)) {
521 return(LIB3DS_FALSE);
525 case LIB3DS_MAT_ENTRY:
527 Lib3dsMaterial *material;
529 material=lib3ds_material_new();
531 return(LIB3DS_FALSE);
533 lib3ds_chunk_read_reset(&c, io);
534 if (!lib3ds_material_read(material, io)) {
535 return(LIB3DS_FALSE);
537 lib3ds_file_insert_material(file, material);
540 case LIB3DS_NAMED_OBJECT:
542 lib3ds_chunk_read_reset(&c, io);
543 if (!named_object_read(file, io)) {
544 return(LIB3DS_FALSE);
549 lib3ds_chunk_unknown(chunk);
553 lib3ds_chunk_read_end(&c, io);
559 kfdata_read(Lib3dsFile *file, Lib3dsIo *io)
564 if (!lib3ds_chunk_read_start(&c, LIB3DS_KFDATA, io)) {
565 return(LIB3DS_FALSE);
568 while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
572 file->keyf_revision=lib3ds_io_read_word(io);
573 if (!lib3ds_io_read_string(io, file->name, 12+1)) {
574 return(LIB3DS_FALSE);
576 file->frames=lib3ds_io_read_intd(io);
581 file->segment_from=lib3ds_io_read_intd(io);
582 file->segment_to=lib3ds_io_read_intd(io);
585 case LIB3DS_KFCURTIME:
587 file->current_frame=lib3ds_io_read_intd(io);
590 case LIB3DS_VIEWPORT_LAYOUT:
591 case LIB3DS_DEFAULT_VIEW:
593 lib3ds_chunk_read_reset(&c, io);
594 if (!lib3ds_viewport_read(&file->viewport_keyf, io)) {
595 return(LIB3DS_FALSE);
599 case LIB3DS_AMBIENT_NODE_TAG:
603 node=lib3ds_node_new_ambient();
605 return(LIB3DS_FALSE);
607 lib3ds_chunk_read_reset(&c, io);
608 if (!lib3ds_node_read(node, file, io)) {
609 return(LIB3DS_FALSE);
611 lib3ds_file_insert_node(file, node);
614 case LIB3DS_OBJECT_NODE_TAG:
618 node=lib3ds_node_new_object();
620 return(LIB3DS_FALSE);
622 lib3ds_chunk_read_reset(&c, io);
623 if (!lib3ds_node_read(node, file, io)) {
624 return(LIB3DS_FALSE);
626 lib3ds_file_insert_node(file, node);
629 case LIB3DS_CAMERA_NODE_TAG:
633 node=lib3ds_node_new_camera();
635 return(LIB3DS_FALSE);
637 lib3ds_chunk_read_reset(&c, io);
638 if (!lib3ds_node_read(node, file, io)) {
639 return(LIB3DS_FALSE);
641 lib3ds_file_insert_node(file, node);
644 case LIB3DS_TARGET_NODE_TAG:
648 node=lib3ds_node_new_target();
650 return(LIB3DS_FALSE);
652 lib3ds_chunk_read_reset(&c, io);
653 if (!lib3ds_node_read(node, file, io)) {
654 return(LIB3DS_FALSE);
656 lib3ds_file_insert_node(file, node);
659 case LIB3DS_LIGHT_NODE_TAG:
660 case LIB3DS_SPOTLIGHT_NODE_TAG:
664 node=lib3ds_node_new_light();
666 return(LIB3DS_FALSE);
668 lib3ds_chunk_read_reset(&c, io);
669 if (!lib3ds_node_read(node, file, io)) {
670 return(LIB3DS_FALSE);
672 lib3ds_file_insert_node(file, node);
675 case LIB3DS_L_TARGET_NODE_TAG:
679 node=lib3ds_node_new_spot();
681 return(LIB3DS_FALSE);
683 lib3ds_chunk_read_reset(&c, io);
684 if (!lib3ds_node_read(node, file, io)) {
685 return(LIB3DS_FALSE);
687 lib3ds_file_insert_node(file, node);
691 lib3ds_chunk_unknown(chunk);
695 lib3ds_chunk_read_end(&c, io);
701 * Read 3ds file data into a Lib3dsFile object.
703 * \param file The Lib3dsFile object to be filled.
704 * \param io A Lib3dsIo object previously set up by the caller.
706 * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
711 lib3ds_file_read(Lib3dsFile *file, Lib3dsIo *io)
716 if (!lib3ds_chunk_read_start(&c, 0, io)) {
717 return(LIB3DS_FALSE);
722 lib3ds_chunk_read_reset(&c, io);
723 if (!mdata_read(file, io)) {
724 return(LIB3DS_FALSE);
728 case LIB3DS_M3DMAGIC:
729 case LIB3DS_MLIBMAGIC:
732 while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
734 case LIB3DS_M3D_VERSION:
736 file->mesh_version=lib3ds_io_read_dword(io);
741 lib3ds_chunk_read_reset(&c, io);
742 if (!mdata_read(file, io)) {
743 return(LIB3DS_FALSE);
749 lib3ds_chunk_read_reset(&c, io);
750 if (!kfdata_read(file, io)) {
751 return(LIB3DS_FALSE);
756 lib3ds_chunk_unknown(chunk);
762 lib3ds_chunk_unknown(c.chunk);
763 return(LIB3DS_FALSE);
766 lib3ds_chunk_read_end(&c, io);
772 colorf_write(Lib3dsRgba rgb, Lib3dsIo *io)
776 c.chunk=LIB3DS_COLOR_F;
778 lib3ds_chunk_write(&c,io);
779 lib3ds_io_write_rgb(io, rgb);
781 c.chunk=LIB3DS_LIN_COLOR_F;
783 lib3ds_chunk_write(&c,io);
784 lib3ds_io_write_rgb(io, rgb);
790 mdata_write(Lib3dsFile *file, Lib3dsIo *io)
794 c.chunk=LIB3DS_MDATA;
795 if (!lib3ds_chunk_write_start(&c,io)) {
796 return(LIB3DS_FALSE);
799 { /*---- LIB3DS_MESH_VERSION ----*/
801 c.chunk=LIB3DS_MESH_VERSION;
803 lib3ds_chunk_write(&c,io);
804 lib3ds_io_write_intd(io, file->mesh_version);
806 { /*---- LIB3DS_MASTER_SCALE ----*/
808 c.chunk=LIB3DS_MASTER_SCALE;
810 lib3ds_chunk_write(&c,io);
811 lib3ds_io_write_float(io, file->master_scale);
813 { /*---- LIB3DS_O_CONSTS ----*/
815 for (i=0; i<3; ++i) {
816 if (fabs(file->construction_plane[i])>LIB3DS_EPSILON) {
822 c.chunk=LIB3DS_O_CONSTS;
824 lib3ds_chunk_write(&c,io);
825 lib3ds_io_write_vector(io, file->construction_plane);
829 { /*---- LIB3DS_AMBIENT_LIGHT ----*/
831 for (i=0; i<3; ++i) {
832 if (fabs(file->ambient[i])>LIB3DS_EPSILON) {
838 c.chunk=LIB3DS_AMBIENT_LIGHT;
840 lib3ds_chunk_write(&c,io);
841 colorf_write(file->ambient,io);
844 lib3ds_background_write(&file->background, io);
845 lib3ds_atmosphere_write(&file->atmosphere, io);
846 lib3ds_shadow_write(&file->shadow, io);
847 lib3ds_viewport_write(&file->viewport, io);
850 for (p=file->materials; p!=0; p=p->next) {
851 if (!lib3ds_material_write(p,io)) {
852 return(LIB3DS_FALSE);
860 for (p=file->cameras; p!=0; p=p->next) {
861 c.chunk=LIB3DS_NAMED_OBJECT;
862 if (!lib3ds_chunk_write_start(&c,io)) {
863 return(LIB3DS_FALSE);
865 lib3ds_io_write_string(io, p->name);
866 lib3ds_camera_write(p,io);
867 if (!lib3ds_chunk_write_end(&c,io)) {
868 return(LIB3DS_FALSE);
876 for (p=file->lights; p!=0; p=p->next) {
877 c.chunk=LIB3DS_NAMED_OBJECT;
878 if (!lib3ds_chunk_write_start(&c,io)) {
879 return(LIB3DS_FALSE);
881 lib3ds_io_write_string(io,p->name);
882 lib3ds_light_write(p,io);
883 if (!lib3ds_chunk_write_end(&c,io)) {
884 return(LIB3DS_FALSE);
892 for (p=file->meshes; p!=0; p=p->next) {
893 c.chunk=LIB3DS_NAMED_OBJECT;
894 if (!lib3ds_chunk_write_start(&c,io)) {
895 return(LIB3DS_FALSE);
897 lib3ds_io_write_string(io, p->name);
898 lib3ds_mesh_write(p,io);
899 if (!lib3ds_chunk_write_end(&c,io)) {
900 return(LIB3DS_FALSE);
905 if (!lib3ds_chunk_write_end(&c,io)) {
906 return(LIB3DS_FALSE);
914 nodes_write(Lib3dsNode *node, Lib3dsFile *file, Lib3dsIo *io)
918 for (p=node->childs; p!=0; p=p->next) {
919 if (!lib3ds_node_write(p, file, io)) {
920 return(LIB3DS_FALSE);
922 nodes_write(p, file, io);
930 kfdata_write(Lib3dsFile *file, Lib3dsIo *io)
938 c.chunk=LIB3DS_KFDATA;
939 if (!lib3ds_chunk_write_start(&c,io)) {
940 return(LIB3DS_FALSE);
943 { /*---- LIB3DS_KFHDR ----*/
945 c.chunk=LIB3DS_KFHDR;
946 c.size=6 + 2 + strlen(file->name)+1 +4;
947 lib3ds_chunk_write(&c,io);
948 lib3ds_io_write_intw(io, file->keyf_revision);
949 lib3ds_io_write_string(io, file->name);
950 lib3ds_io_write_intd(io, file->frames);
952 { /*---- LIB3DS_KFSEG ----*/
954 c.chunk=LIB3DS_KFSEG;
956 lib3ds_chunk_write(&c,io);
957 lib3ds_io_write_intd(io, file->segment_from);
958 lib3ds_io_write_intd(io, file->segment_to);
960 { /*---- LIB3DS_KFCURTIME ----*/
962 c.chunk=LIB3DS_KFCURTIME;
964 lib3ds_chunk_write(&c,io);
965 lib3ds_io_write_intd(io, file->current_frame);
967 lib3ds_viewport_write(&file->viewport_keyf, io);
971 for (p=file->nodes; p!=0; p=p->next) {
972 if (!lib3ds_node_write(p, file, io)) {
973 return(LIB3DS_FALSE);
975 if (!nodes_write(p, file, io)) {
976 return(LIB3DS_FALSE);
981 if (!lib3ds_chunk_write_end(&c,io)) {
982 return(LIB3DS_FALSE);
989 * Write 3ds file data from a Lib3dsFile object to a file.
991 * \param file The Lib3dsFile object to be written.
992 * \param io A Lib3dsIo object previously set up by the caller.
994 * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
999 lib3ds_file_write(Lib3dsFile *file, Lib3dsIo *io)
1003 c.chunk=LIB3DS_M3DMAGIC;
1004 if (!lib3ds_chunk_write_start(&c,io)) {
1006 return(LIB3DS_FALSE);
1009 { /*---- LIB3DS_M3D_VERSION ----*/
1012 c.chunk=LIB3DS_M3D_VERSION;
1014 lib3ds_chunk_write(&c,io);
1015 lib3ds_io_write_dword(io, file->mesh_version);
1018 if (!mdata_write(file, io)) {
1019 return(LIB3DS_FALSE);
1021 if (!kfdata_write(file, io)) {
1022 return(LIB3DS_FALSE);
1025 if (!lib3ds_chunk_write_end(&c,io)) {
1026 return(LIB3DS_FALSE);
1028 return(LIB3DS_TRUE);
1033 * Insert a new Lib3dsMaterial object into the materials list of
1034 * a Lib3dsFile object.
1036 * The new Lib3dsMaterial object is inserted into the materials list
1037 * in alphabetic order by name.
1039 * \param file The Lib3dsFile object to be modified.
1040 * \param material The Lib3dsMaterial object to be inserted into file->materials
1045 lib3ds_file_insert_material(Lib3dsFile *file, Lib3dsMaterial *material)
1047 Lib3dsMaterial *p,*q;
1051 ASSERT(!material->next);
1054 for (p=file->materials; p!=0; p=p->next) {
1055 if (strcmp(material->name, p->name)<0) {
1061 material->next=file->materials;
1062 file->materials=material;
1065 material->next=q->next;
1072 * Remove a Lib3dsMaterial object from the materials list of
1073 * a Lib3dsFile object.
1075 * If the Lib3dsMaterial is not found in the materials list, nothing is
1076 * done (except that an error log message may be generated.)
1078 * \param file The Lib3dsFile object to be modified.
1079 * \param material The Lib3dsMaterial object to be removed from file->materials
1084 lib3ds_file_remove_material(Lib3dsFile *file, Lib3dsMaterial *material)
1086 Lib3dsMaterial *p,*q;
1090 ASSERT(file->materials);
1091 for (p=0,q=file->materials; q; p=q,q=q->next) {
1097 ASSERT(LIB3DS_FALSE);
1101 file->materials=material->next;
1111 * Return a Lib3dsMaterial object by name.
1113 * \param file Lib3dsFile object to be searched.
1114 * \param name Name of the Lib3dsMaterial object to be searched for.
1116 * \return A pointer to the named Lib3dsMaterial, or NULL if not found.
1121 lib3ds_file_material_by_name(Lib3dsFile *file, const char *name)
1126 for (p=file->materials; p!=0; p=p->next) {
1127 if (strcmp(p->name,name)==0) {
1136 * Dump all Lib3dsMaterial objects found in a Lib3dsFile object.
1138 * \param file Lib3dsFile object to be dumped.
1140 * \see lib3ds_material_dump
1145 lib3ds_file_dump_materials(Lib3dsFile *file)
1150 for (p=file->materials; p!=0; p=p->next) {
1151 lib3ds_material_dump(p);
1157 * Insert a new Lib3dsMesh object into the meshes list of
1158 * a Lib3dsFile object.
1160 * The new Lib3dsMesh object is inserted into the meshes list
1161 * in alphabetic order by name.
1163 * \param file The Lib3dsFile object to be modified.
1164 * \param material The Lib3dsMesh object to be inserted into file->meshes
1169 lib3ds_file_insert_mesh(Lib3dsFile *file, Lib3dsMesh *mesh)
1175 ASSERT(!mesh->next);
1178 for (p=file->meshes; p!=0; p=p->next) {
1179 if (strcmp(mesh->name, p->name)<0) {
1185 mesh->next=file->meshes;
1196 * Remove a Lib3dsMesh object from the meshes list of
1197 * a Lib3dsFile object.
1199 * If the Lib3dsMesh is not found in the meshes list, nothing is done
1200 * (except that an error log message may be generated.)
1202 * \param file The Lib3dsFile object to be modified.
1203 * \param material The Lib3dsMesh object to be removed from file->meshes
1208 lib3ds_file_remove_mesh(Lib3dsFile *file, Lib3dsMesh *mesh)
1214 ASSERT(file->meshes);
1215 for (p=0,q=file->meshes; q; p=q,q=q->next) {
1221 ASSERT(LIB3DS_FALSE);
1225 file->meshes=mesh->next;
1235 * Return a Lib3dsMesh object from a Lib3dsFile by name.
1237 * \param file Lib3dsFile object to be searched.
1238 * \param name Name of the Lib3dsMesh object to be searched for.
1240 * \return A pointer to the named Lib3dsMesh, or NULL if not found.
1245 lib3ds_file_mesh_by_name(Lib3dsFile *file, const char *name)
1250 for (p=file->meshes; p!=0; p=p->next) {
1251 if (strcmp(p->name,name)==0) {
1260 * Dump all Lib3dsMesh objects found in a Lib3dsFile object.
1262 * \param file Lib3dsFile object to be dumped.
1264 * \see lib3ds_mesh_dump
1269 lib3ds_file_dump_meshes(Lib3dsFile *file)
1274 for (p=file->meshes; p!=0; p=p->next) {
1275 lib3ds_mesh_dump(p);
1281 dump_instances(Lib3dsNode *node, const char* parent)
1288 strcpy(name, parent);
1290 strcat(name, node->name);
1291 if (node->type==LIB3DS_OBJECT_NODE) {
1292 printf(" %s : %s\n", name, node->data.object.instance);
1294 for (p=node->childs; p!=0; p=p->next) {
1295 dump_instances(p, parent);
1301 * Dump all Lib3dsNode object names found in a Lib3dsFile object.
1303 * For each node of type OBJECT_NODE, its name and data.object.instance
1304 * fields are printed to stdout. Consider using lib3ds_file_dump_nodes()
1305 * instead, as that function dumps more information.
1307 * Nodes are dumped recursively.
1309 * \param file Lib3dsFile object to be dumped.
1311 * \see lib3ds_file_dump_nodes
1316 lib3ds_file_dump_instances(Lib3dsFile *file)
1321 for (p=file->nodes; p!=0; p=p->next) {
1322 dump_instances(p,"");
1328 * Insert a new Lib3dsCamera object into the cameras list of
1329 * a Lib3dsFile object.
1331 * The new Lib3dsCamera object is inserted into the cameras list
1332 * in alphabetic order by name.
1334 * \param file The Lib3dsFile object to be modified.
1335 * \param material The Lib3dsCamera object to be inserted into file->cameras
1340 lib3ds_file_insert_camera(Lib3dsFile *file, Lib3dsCamera *camera)
1346 ASSERT(!camera->next);
1349 for (p=file->cameras; p!=0; p=p->next) {
1350 if (strcmp(camera->name, p->name)<0) {
1356 camera->next=file->cameras;
1357 file->cameras=camera;
1360 camera->next=q->next;
1367 * Remove a Lib3dsCamera object from the cameras list of
1368 * a Lib3dsFile object.
1370 * If the Lib3dsCamera is not found in the cameras list, nothing is done
1371 * (except that an error log message may be generated.)
1373 * \param file The Lib3dsFile object to be modified.
1374 * \param material The Lib3dsCamera object to be removed from file->cameras
1379 lib3ds_file_remove_camera(Lib3dsFile *file, Lib3dsCamera *camera)
1385 ASSERT(file->cameras);
1386 for (p=0,q=file->cameras; q; p=q,q=q->next) {
1392 ASSERT(LIB3DS_FALSE);
1396 file->cameras=camera->next;
1406 * Return a Lib3dsCamera object from a Lib3dsFile by name.
1408 * \param file Lib3dsFile object to be searched.
1409 * \param name Name of the Lib3dsCamera object to be searched for.
1411 * \return A pointer to the named Lib3dsCamera, or NULL if not found.
1416 lib3ds_file_camera_by_name(Lib3dsFile *file, const char *name)
1421 for (p=file->cameras; p!=0; p=p->next) {
1422 if (strcmp(p->name,name)==0) {
1431 * Dump all Lib3dsCamera objects found in a Lib3dsFile object.
1433 * \param file Lib3dsFile object to be dumped.
1435 * \see lib3ds_camera_dump
1440 lib3ds_file_dump_cameras(Lib3dsFile *file)
1445 for (p=file->cameras; p!=0; p=p->next) {
1446 lib3ds_camera_dump(p);
1452 * Insert a new Lib3dsLight object into the lights list of
1453 * a Lib3dsFile object.
1455 * The new Lib3dsLight object is inserted into the lights list
1456 * in alphabetic order by name.
1458 * \param file The Lib3dsFile object to be modified.
1459 * \param material The Lib3dsLight object to be inserted into file->lights
1464 lib3ds_file_insert_light(Lib3dsFile *file, Lib3dsLight *light)
1470 ASSERT(!light->next);
1473 for (p=file->lights; p!=0; p=p->next) {
1474 if (strcmp(light->name, p->name)<0) {
1480 light->next=file->lights;
1484 light->next=q->next;
1491 * Remove a Lib3dsLight object from the lights list of
1492 * a Lib3dsFile object.
1494 * If the Lib3dsLight is not found in the lights list, nothing is done
1495 * (except that an error log message may be generated.)
1497 * \param file The Lib3dsFile object to be modified.
1498 * \param material The Lib3dsLight object to be removed from file->lights
1503 lib3ds_file_remove_light(Lib3dsFile *file, Lib3dsLight *light)
1509 ASSERT(file->lights);
1510 for (p=0,q=file->lights; q; p=q,q=q->next) {
1516 ASSERT(LIB3DS_FALSE);
1520 file->lights=light->next;
1530 * Return a Lib3dsLight object from a Lib3dsFile by name.
1532 * \param file Lib3dsFile object to be searched.
1533 * \param name Name of the Lib3dsLight object to be searched for.
1535 * \return A pointer to the named Lib3dsLight, or NULL if not found.
1540 lib3ds_file_light_by_name(Lib3dsFile *file, const char *name)
1545 for (p=file->lights; p!=0; p=p->next) {
1546 if (strcmp(p->name,name)==0) {
1555 * Dump all Lib3dsLight objects found in a Lib3dsFile object.
1557 * \param file Lib3dsFile object to be dumped.
1559 * \see lib3ds_light_dump
1564 lib3ds_file_dump_lights(Lib3dsFile *file)
1569 for (p=file->lights; p!=0; p=p->next) {
1570 lib3ds_light_dump(p);
1576 * Compute the bounding box for Lib3dsFile objects.
1578 * This function computes the bounding box for all meshes
1579 * in the Lib3dsFile object. Cameras and lights are not included.
1581 * \param file The Lib3dsFile object to be examined.
1582 * \param min Returned minimum x,y,z values.
1583 * \param max Returned maximum x,y,z values.
1588 lib3ds_object_bounding_box(Lib3dsFile *file, Lib3dsVector min, Lib3dsVector max)
1591 Lib3dsVector lmin, lmax;
1592 Lib3dsMesh *p=file->meshes;
1595 lib3ds_mesh_bounding_box(p, min, max);
1599 lib3ds_mesh_bounding_box(p, lmin, lmax);
1600 lib3ds_vector_min(min, lmin);
1601 lib3ds_vector_max(max, lmax);
1609 * Compute the bounding box for a Lib3dsFile.
1611 * This function computes the bounding box for all meshes, cameras,
1612 * and lights in the Lib3dsFile object.
1614 * \param file The Lib3dsFile object to be examined.
1615 * \param min Returned minimum x,y,z values.
1616 * \param max Returned maximum x,y,z values.
1621 lib3ds_file_bounding_box(Lib3dsFile *file, Lib3dsVector min, Lib3dsVector max)
1623 Lib3dsBool init=LIB3DS_FALSE;
1626 Lib3dsVector lmin, lmax;
1627 Lib3dsMesh *p=file->meshes;
1631 lib3ds_mesh_bounding_box(p, min, max);
1635 lib3ds_mesh_bounding_box(p, lmin, lmax);
1636 lib3ds_vector_min(min, lmin);
1637 lib3ds_vector_max(max, lmax);
1642 Lib3dsCamera *p=file->cameras;
1645 lib3ds_vector_copy(min, p->position);
1646 lib3ds_vector_copy(max, p->position);
1650 lib3ds_vector_min(min, p->position);
1651 lib3ds_vector_max(max, p->position);
1652 lib3ds_vector_min(min, p->target);
1653 lib3ds_vector_max(max, p->target);
1658 Lib3dsLight *p=file->lights;
1661 lib3ds_vector_copy(min, p->position);
1662 lib3ds_vector_copy(max, p->position);
1666 lib3ds_vector_min(min, p->position);
1667 lib3ds_vector_max(max, p->position);
1668 if (p->spot_light) {
1669 lib3ds_vector_min(min, p->spot);
1670 lib3ds_vector_max(max, p->spot);
1679 * Return a node object by name and type.
1681 * This function performs a recursive search for the specified node.
1682 * Both name and type must match.
1684 * \param file The Lib3dsFile to be searched.
1685 * \param name The target node name.
1686 * \param type The target node type
1688 * \return A pointer to the first matching node, or NULL if not found.
1690 * \see lib3ds_node_by_name
1695 lib3ds_file_node_by_name(Lib3dsFile *file, const char* name, Lib3dsNodeTypes type)
1700 for (p=file->nodes; p!=0; p=p->next) {
1701 if ((p->type==type) && (strcmp(p->name, name)==0)) {
1704 q=lib3ds_node_by_name(p, name, type);
1714 * Return a node object by id.
1716 * This function performs a recursive search for the specified node.
1718 * \param file The Lib3dsFile to be searched.
1719 * \param node_id The target node id.
1721 * \return A pointer to the first matching node, or NULL if not found.
1723 * \see lib3ds_node_by_id
1728 lib3ds_file_node_by_id(Lib3dsFile *file, Lib3dsWord node_id)
1733 for (p=file->nodes; p!=0; p=p->next) {
1734 if (p->node_id==node_id) {
1737 q=lib3ds_node_by_id(p, node_id);
1747 * Insert a new node into a Lib3dsFile object.
1749 * If the node's parent_id structure is not LIB3DS_NO_PARENT and the
1750 * specified parent is found inside the Lib3dsFile object, then the
1751 * node is inserted as a child of that parent. If the parent_id
1752 * structure is LIB3DS_NO_PARENT or the specified parent is not found,
1753 * then the node is inserted at the top level.
1755 * Node is inserted in alphabetic order by name.
1757 * Finally, if any other top-level nodes in file specify this node as
1758 * their parent, they are relocated as a child of this node.
1760 * \param file The Lib3dsFile object to be modified.
1761 * \param node The node to be inserted into file
1766 lib3ds_file_insert_node(Lib3dsFile *file, Lib3dsNode *node)
1768 Lib3dsNode *parent,*p,*n;
1771 ASSERT(!node->next);
1772 ASSERT(!node->parent);
1775 if (node->parent_id!=LIB3DS_NO_PARENT) {
1776 parent=lib3ds_file_node_by_id(file, node->parent_id);
1778 node->parent=parent;
1781 for (p=0,n=file->nodes; n!=0; p=n,n=n->next) {
1782 if (strcmp(n->name, node->name)>0) {
1787 node->next=file->nodes;
1796 for (p=0,n=parent->childs; n!=0; p=n,n=n->next) {
1797 if (strcmp(n->name, node->name)>0) {
1802 node->next=parent->childs;
1803 parent->childs=node;
1811 if (node->node_id!=LIB3DS_NO_PARENT) {
1812 for (n=file->nodes; n!=0; n=p) {
1814 if (n->parent_id==node->node_id) {
1815 lib3ds_file_remove_node(file, n);
1816 lib3ds_file_insert_node(file, n);
1824 * Remove a node from the a Lib3dsFile object.
1826 * \param file The Lib3dsFile object to be modified.
1827 * \param node The Lib3dsNode object to be removed from file
1829 * \return LIB3DS_TRUE on success, LIB3DS_FALSE if node is not found in file
1834 lib3ds_file_remove_node(Lib3dsFile *file, Lib3dsNode *node)
1839 for (p=0,n=node->parent->childs; n; p=n,n=n->next) {
1845 return(LIB3DS_FALSE);
1849 node->parent->childs=n->next;
1856 for (p=0,n=file->nodes; n; p=n,n=n->next) {
1862 return(LIB3DS_FALSE);
1866 file->nodes=n->next;
1872 return(LIB3DS_TRUE);
1877 * Dump all node objects found in a Lib3dsFile object.
1879 * Nodes are dumped recursively.
1881 * \param file Lib3dsFile object to be dumped.
1883 * \see lib3ds_node_dump
1888 lib3ds_file_dump_nodes(Lib3dsFile *file)
1893 for (p=file->nodes; p!=0; p=p->next) {
1894 lib3ds_node_dump(p,1);
1909 /* Programming trick to force users to compile their source code against the
1910 * correct headers. The symbol lib3ds_version1_3 will be defined iff the users
1911 * compile with the current version of <lib3ds/types.h>
1915 extern int lib3ds_version1_3;
1916 static const int *lib3ds_version = &lib3ds_version1_3;