C:/jkyprian/devel/lib3ds/lib3ds/file.c

00001 /*
00002  * The 3D Studio File Format Library
00003  * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
00004  * All rights reserved.
00005  *
00006  * This program is  free  software;  you can redistribute it and/or modify it
00007  * under the terms of the  GNU Lesser General Public License  as published by 
00008  * the  Free Software Foundation;  either version 2.1 of the License,  or (at 
00009  * your option) any later version.
00010  *
00011  * This  program  is  distributed in  the  hope that it will  be useful,  but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00013  * or  FITNESS FOR A  PARTICULAR PURPOSE.  See the  GNU Lesser General Public  
00014  * License for more details.
00015  *
00016  * You should  have received  a copy of the GNU Lesser General Public License
00017  * along with  this program;  if not, write to the  Free Software Foundation,
00018  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  *
00020  * $Id: file.c,v 1.34 2007/06/20 17:04:08 jeh Exp $
00021  */
00022 #include <lib3ds/file.h>
00023 #include <lib3ds/chunk.h>
00024 #include <lib3ds/io.h>
00025 #include <lib3ds/material.h>
00026 #include <lib3ds/mesh.h>
00027 #include <lib3ds/camera.h>
00028 #include <lib3ds/light.h>
00029 #include <lib3ds/node.h>
00030 #include <lib3ds/matrix.h>
00031 #include <lib3ds/vector.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <math.h>
00035 #include <float.h>
00036 
00037 
00043 static Lib3dsBool
00044 fileio_error_func(void *self)
00045 {
00046   FILE *f = (FILE*)self;
00047   return(ferror(f)!=0);
00048 }
00049 
00050 
00051 static long
00052 fileio_seek_func(void *self, long offset, Lib3dsIoSeek origin)
00053 {
00054   FILE *f = (FILE*)self;
00055   int o;
00056   switch (origin) {
00057     case LIB3DS_SEEK_SET:
00058       o = SEEK_SET;
00059       break;
00060     case LIB3DS_SEEK_CUR:
00061       o = SEEK_CUR;
00062       break;
00063     case LIB3DS_SEEK_END:
00064       o = SEEK_END;
00065       break;
00066     default:
00067       ASSERT(0);
00068       return(0);
00069   }
00070   return (fseek(f, offset, o));
00071 }
00072 
00073 
00074 static long
00075 fileio_tell_func(void *self)
00076 {
00077   FILE *f = (FILE*)self;
00078   return(ftell(f));
00079 }
00080 
00081 
00082 static size_t
00083 fileio_read_func(void *self, void *buffer, size_t size)
00084 {
00085   FILE *f = (FILE*)self;
00086   return(fread(buffer, 1, size, f));
00087 }
00088 
00089 
00090 static size_t
00091 fileio_write_func(void *self, const void *buffer, size_t size)
00092 {
00093   FILE *f = (FILE*)self;
00094   return(fwrite(buffer, 1, size, f));
00095 }
00096 
00097 
00115 Lib3dsFile*
00116 lib3ds_file_load(const char *filename)
00117 {
00118   FILE *f;
00119   Lib3dsFile *file;
00120   Lib3dsIo *io;
00121 
00122   f = fopen(filename, "rb");
00123   if (!f) {
00124     return(0);
00125   }
00126   file = lib3ds_file_new();
00127   if (!file) {
00128     fclose(f);
00129     return(0);
00130   }
00131   
00132   io = lib3ds_io_new(
00133     f, 
00134     fileio_error_func,
00135     fileio_seek_func,
00136     fileio_tell_func,
00137     fileio_read_func,
00138     fileio_write_func
00139   );
00140   if (!io) {
00141     lib3ds_file_free(file);
00142     fclose(f);
00143     return(0);
00144   }
00145 
00146   if (!lib3ds_file_read(file, io)) {
00147     free(file);
00148     lib3ds_io_free(io);
00149     fclose(f);
00150     return(0);
00151   }
00152 
00153   lib3ds_io_free(io);
00154   fclose(f);
00155   return(file);
00156 }
00157 
00158 
00172 Lib3dsBool
00173 lib3ds_file_save(Lib3dsFile *file, const char *filename)
00174 {
00175   FILE *f;
00176   Lib3dsIo *io;
00177   Lib3dsBool result;
00178 
00179   f = fopen(filename, "wb");
00180   if (!f) {
00181     return(LIB3DS_FALSE);
00182   }
00183   io = lib3ds_io_new(
00184     f, 
00185     fileio_error_func,
00186     fileio_seek_func,
00187     fileio_tell_func,
00188     fileio_read_func,
00189     fileio_write_func
00190   );
00191   if (!io) {
00192     fclose(f);
00193     return LIB3DS_FALSE;
00194   }
00195   
00196   result = lib3ds_file_write(file, io);
00197 
00198   fclose(f);
00199 
00200   lib3ds_io_free(io);
00201   return(result);
00202 }
00203 
00204 
00213 Lib3dsFile*
00214 lib3ds_file_new()
00215 {
00216   Lib3dsFile *file;
00217 
00218   file=(Lib3dsFile*)calloc(sizeof(Lib3dsFile),1);
00219   if (!file) {
00220     return(0);
00221   }
00222   file->mesh_version=3;
00223   file->master_scale=1.0f;
00224   file->keyf_revision=5;
00225   strcpy(file->name, "LIB3DS");
00226 
00227   file->frames=100;
00228   file->segment_from=0;
00229   file->segment_to=100;
00230   file->current_frame=0;
00231 
00232   return(file);
00233 }
00234 
00235 
00243 void
00244 lib3ds_file_free(Lib3dsFile* file)
00245 {
00246   ASSERT(file);
00247   lib3ds_viewport_set_views(&file->viewport,0);
00248   lib3ds_viewport_set_views(&file->viewport_keyf,0);
00249   {
00250     Lib3dsMaterial *p,*q;
00251     
00252     for (p=file->materials; p; p=q) {
00253       q=p->next;
00254       lib3ds_material_free(p);
00255     }
00256     file->materials=0;
00257   }
00258   {
00259     Lib3dsCamera *p,*q;
00260     
00261     for (p=file->cameras; p; p=q) {
00262       q=p->next;
00263       lib3ds_camera_free(p);
00264     }
00265     file->cameras=0;
00266   }
00267   {
00268     Lib3dsLight *p,*q;
00269     
00270     for (p=file->lights; p; p=q) {
00271       q=p->next;
00272       lib3ds_light_free(p);
00273     }
00274     file->lights=0;
00275   }
00276   {
00277     Lib3dsMesh *p,*q;
00278     
00279     for (p=file->meshes; p; p=q) {
00280       q=p->next;
00281       lib3ds_mesh_free(p);
00282     }
00283     file->meshes=0;
00284   }
00285   {
00286     Lib3dsNode *p,*q;
00287   
00288     for (p=file->nodes; p; p=q) {
00289       q=p->next;
00290       lib3ds_node_free(p);
00291     }
00292   }
00293   free(file);
00294 }
00295 
00296 
00307 void
00308 lib3ds_file_eval(Lib3dsFile *file, Lib3dsFloat t)
00309 {
00310   Lib3dsNode *p;
00311 
00312   for (p=file->nodes; p!=0; p=p->next) {
00313     lib3ds_node_eval(p, t);
00314   }
00315 }
00316 
00317 
00318 static Lib3dsBool
00319 named_object_read(Lib3dsFile *file, Lib3dsIo *io)
00320 {
00321   Lib3dsChunk c;
00322   char name[64];
00323   Lib3dsWord chunk;
00324   Lib3dsMesh *mesh = NULL;
00325   Lib3dsCamera *camera = NULL;
00326   Lib3dsLight *light = NULL;
00327   Lib3dsDword object_flags;
00328 
00329   if (!lib3ds_chunk_read_start(&c, LIB3DS_NAMED_OBJECT, io)) {
00330     return(LIB3DS_FALSE);
00331   }
00332   if (!lib3ds_io_read_string(io, name, 64)) {
00333     return(LIB3DS_FALSE);
00334   }
00335   lib3ds_chunk_dump_info("  NAME=%s", name);
00336   lib3ds_chunk_read_tell(&c, io);
00337 
00338   object_flags = 0;
00339   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
00340     switch (chunk) {
00341       case LIB3DS_N_TRI_OBJECT:
00342         {
00343           mesh=lib3ds_mesh_new(name);
00344           if (!mesh) {
00345             return(LIB3DS_FALSE);
00346           }
00347           lib3ds_chunk_read_reset(&c, io);
00348           if (!lib3ds_mesh_read(mesh, io)) {
00349             return(LIB3DS_FALSE);
00350           }
00351           lib3ds_file_insert_mesh(file, mesh);
00352         }
00353         break;
00354       
00355       case LIB3DS_N_CAMERA:
00356         {
00357           camera=lib3ds_camera_new(name);
00358           if (!camera) {
00359             return(LIB3DS_FALSE);
00360           }
00361           lib3ds_chunk_read_reset(&c, io);
00362           if (!lib3ds_camera_read(camera, io)) {
00363             return(LIB3DS_FALSE);
00364           }
00365           lib3ds_file_insert_camera(file, camera);
00366         }
00367         break;
00368       
00369       case LIB3DS_N_DIRECT_LIGHT:
00370         {
00371           light=lib3ds_light_new(name);
00372           if (!light) {
00373             return(LIB3DS_FALSE);
00374           }
00375           lib3ds_chunk_read_reset(&c, io);
00376           if (!lib3ds_light_read(light, io)) {
00377             return(LIB3DS_FALSE);
00378           }
00379           lib3ds_file_insert_light(file, light);
00380         }
00381         break;
00382       
00383       case LIB3DS_OBJ_HIDDEN:
00384         object_flags |= LIB3DS_OBJECT_HIDDEN;
00385         break;
00386 
00387       case LIB3DS_OBJ_DOESNT_CAST:
00388         object_flags |= LIB3DS_OBJECT_DOESNT_CAST;
00389         break;
00390 
00391       case LIB3DS_OBJ_VIS_LOFTER:
00392         object_flags |= LIB3DS_OBJECT_VIS_LOFTER;
00393         break;
00394 
00395       case LIB3DS_OBJ_MATTE:
00396         object_flags |= LIB3DS_OBJECT_MATTE;
00397         break;
00398 
00399       case LIB3DS_OBJ_DONT_RCVSHADOW:
00400         object_flags |= LIB3DS_OBJECT_DONT_RCVSHADOW;
00401         break;
00402 
00403       case LIB3DS_OBJ_FAST:
00404         object_flags |= LIB3DS_OBJECT_FAST;
00405         break;
00406 
00407       case LIB3DS_OBJ_FROZEN:
00408         object_flags |= LIB3DS_OBJECT_FROZEN;
00409         break;
00410 
00411       default:
00412         lib3ds_chunk_unknown(chunk);
00413     }
00414   }
00415 
00416   if (mesh)
00417     mesh->object_flags = object_flags;
00418   if (camera)
00419     camera->object_flags = object_flags;
00420   if (light)
00421     light->object_flags = object_flags;
00422   
00423   lib3ds_chunk_read_end(&c, io);
00424   return(LIB3DS_TRUE);
00425 }
00426 
00427 
00428 static Lib3dsBool
00429 ambient_read(Lib3dsFile *file, Lib3dsIo *io)
00430 {
00431   Lib3dsChunk c;
00432   Lib3dsWord chunk;
00433   Lib3dsBool have_lin=LIB3DS_FALSE;
00434 
00435   if (!lib3ds_chunk_read_start(&c, LIB3DS_AMBIENT_LIGHT, io)) {
00436     return(LIB3DS_FALSE);
00437   }
00438 
00439   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
00440     switch (chunk) {
00441       case LIB3DS_LIN_COLOR_F:
00442         {
00443           int i;
00444           for (i=0; i<3; ++i) {
00445             file->ambient[i]=lib3ds_io_read_float(io);
00446           }
00447         }
00448         have_lin=LIB3DS_TRUE;
00449         break;
00450       case LIB3DS_COLOR_F:
00451         {
00452           /* gamma corrected color chunk
00453              replaced in 3ds R3 by LIN_COLOR_24 */
00454           if (!have_lin) {
00455             int i;
00456             for (i=0; i<3; ++i) {
00457               file->ambient[i]=lib3ds_io_read_float(io);
00458             }
00459           }
00460         }
00461         break;
00462       default:
00463         lib3ds_chunk_unknown(chunk);
00464     }
00465   }
00466   
00467   lib3ds_chunk_read_end(&c, io);
00468   return(LIB3DS_TRUE);
00469 }
00470 
00471 
00472 static Lib3dsBool
00473 mdata_read(Lib3dsFile *file, Lib3dsIo *io)
00474 {
00475   Lib3dsChunk c;
00476   Lib3dsWord chunk;
00477 
00478   if (!lib3ds_chunk_read_start(&c, LIB3DS_MDATA, io)) {
00479     return(LIB3DS_FALSE);
00480   }
00481   
00482   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
00483     switch (chunk) {
00484       case LIB3DS_MESH_VERSION:
00485         {
00486           file->mesh_version=lib3ds_io_read_intd(io);
00487         }
00488         break;
00489       case LIB3DS_MASTER_SCALE:
00490         {
00491           file->master_scale=lib3ds_io_read_float(io);
00492         }
00493         break;
00494       case LIB3DS_SHADOW_MAP_SIZE:
00495       case LIB3DS_LO_SHADOW_BIAS:
00496       case LIB3DS_HI_SHADOW_BIAS:
00497       case LIB3DS_SHADOW_SAMPLES:
00498       case LIB3DS_SHADOW_RANGE:
00499       case LIB3DS_SHADOW_FILTER:
00500       case LIB3DS_RAY_BIAS:
00501         {
00502           lib3ds_chunk_read_reset(&c, io);
00503           if (!lib3ds_shadow_read(&file->shadow, io)) {
00504             return(LIB3DS_FALSE);
00505           }
00506         }
00507         break;
00508       case LIB3DS_VIEWPORT_LAYOUT:
00509       case LIB3DS_DEFAULT_VIEW:
00510         {
00511           lib3ds_chunk_read_reset(&c, io);
00512           if (!lib3ds_viewport_read(&file->viewport, io)) {
00513             return(LIB3DS_FALSE);
00514           }
00515         }
00516         break;
00517       case LIB3DS_O_CONSTS:
00518         {
00519           int i;
00520           for (i=0; i<3; ++i) {
00521             file->construction_plane[i]=lib3ds_io_read_float(io);
00522           }
00523         }
00524         break;
00525       case LIB3DS_AMBIENT_LIGHT:
00526         {
00527           lib3ds_chunk_read_reset(&c, io);
00528           if (!ambient_read(file, io)) {
00529             return(LIB3DS_FALSE);
00530           }
00531         }
00532         break;
00533       case LIB3DS_BIT_MAP:
00534       case LIB3DS_SOLID_BGND:
00535       case LIB3DS_V_GRADIENT:
00536       case LIB3DS_USE_BIT_MAP:
00537       case LIB3DS_USE_SOLID_BGND:
00538       case LIB3DS_USE_V_GRADIENT:
00539         {
00540           lib3ds_chunk_read_reset(&c, io);
00541           if (!lib3ds_background_read(&file->background, io)) {
00542             return(LIB3DS_FALSE);
00543           }
00544         }
00545         break;
00546       case LIB3DS_FOG:
00547       case LIB3DS_LAYER_FOG:
00548       case LIB3DS_DISTANCE_CUE:
00549       case LIB3DS_USE_FOG:
00550       case LIB3DS_USE_LAYER_FOG:
00551       case LIB3DS_USE_DISTANCE_CUE:
00552         {
00553           lib3ds_chunk_read_reset(&c, io);
00554           if (!lib3ds_atmosphere_read(&file->atmosphere, io)) {
00555             return(LIB3DS_FALSE);
00556           }
00557         }
00558         break;
00559       case LIB3DS_MAT_ENTRY:
00560         {
00561           Lib3dsMaterial *material;
00562 
00563           material=lib3ds_material_new();
00564           if (!material) {
00565             return(LIB3DS_FALSE);
00566           }
00567           lib3ds_chunk_read_reset(&c, io);
00568           if (!lib3ds_material_read(material, io)) {
00569             return(LIB3DS_FALSE);
00570           }
00571           lib3ds_file_insert_material(file, material);
00572         }
00573         break;
00574       case LIB3DS_NAMED_OBJECT:
00575         {
00576           lib3ds_chunk_read_reset(&c, io);
00577           if (!named_object_read(file, io)) {
00578             return(LIB3DS_FALSE);
00579           }
00580         }
00581         break;
00582       default:
00583         lib3ds_chunk_unknown(chunk);
00584     }
00585   }
00586 
00587   lib3ds_chunk_read_end(&c, io);
00588   return(LIB3DS_TRUE);
00589 }
00590 
00591 
00592 static Lib3dsBool
00593 kfdata_read(Lib3dsFile *file, Lib3dsIo *io)
00594 {
00595   Lib3dsChunk c;
00596   Lib3dsWord chunk;
00597   Lib3dsDword node_number = 0;
00598 
00599   if (!lib3ds_chunk_read_start(&c, LIB3DS_KFDATA, io)) {
00600     return(LIB3DS_FALSE);
00601   }
00602   
00603   while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
00604     switch (chunk) {
00605       case LIB3DS_KFHDR:
00606         {
00607           file->keyf_revision=lib3ds_io_read_word(io);
00608           if (!lib3ds_io_read_string(io, file->name, 12+1)) {
00609             return(LIB3DS_FALSE);
00610           }
00611           file->frames=lib3ds_io_read_intd(io);
00612         }
00613         break;
00614       case LIB3DS_KFSEG:
00615         {
00616           file->segment_from=lib3ds_io_read_intd(io);
00617           file->segment_to=lib3ds_io_read_intd(io);
00618         }
00619         break;
00620       case LIB3DS_KFCURTIME:
00621         {
00622           file->current_frame=lib3ds_io_read_intd(io);
00623         }
00624         break;
00625       case LIB3DS_VIEWPORT_LAYOUT:
00626       case LIB3DS_DEFAULT_VIEW:
00627         {
00628           lib3ds_chunk_read_reset(&c, io);
00629           if (!lib3ds_viewport_read(&file->viewport_keyf, io)) {
00630             return(LIB3DS_FALSE);
00631           }
00632         }
00633         break;
00634       case LIB3DS_AMBIENT_NODE_TAG:
00635         {
00636           Lib3dsNode *node;
00637 
00638           node=lib3ds_node_new_ambient();
00639           if (!node) {
00640             return(LIB3DS_FALSE);
00641           }
00642           node->node_id=node_number++;
00643           lib3ds_chunk_read_reset(&c, io);
00644           if (!lib3ds_node_read(node, file, io)) {
00645             return(LIB3DS_FALSE);
00646           }
00647           lib3ds_file_insert_node(file, node);
00648         }
00649         break;
00650       case LIB3DS_OBJECT_NODE_TAG:
00651         {
00652           Lib3dsNode *node;
00653 
00654           node=lib3ds_node_new_object();
00655           if (!node) {
00656             return(LIB3DS_FALSE);
00657           }
00658           node->node_id=node_number++;
00659           lib3ds_chunk_read_reset(&c, io);
00660           if (!lib3ds_node_read(node, file, io)) {
00661             return(LIB3DS_FALSE);
00662           }
00663           lib3ds_file_insert_node(file, node);
00664         }
00665         break;
00666       case LIB3DS_CAMERA_NODE_TAG:
00667         {
00668           Lib3dsNode *node;
00669 
00670           node=lib3ds_node_new_camera();
00671           if (!node) {
00672             return(LIB3DS_FALSE);
00673           }
00674           node->node_id=node_number++;
00675           lib3ds_chunk_read_reset(&c, io);
00676           if (!lib3ds_node_read(node, file, io)) {
00677             return(LIB3DS_FALSE);
00678           }
00679           lib3ds_file_insert_node(file, node);
00680         }
00681         break;
00682       case LIB3DS_TARGET_NODE_TAG:
00683         {
00684           Lib3dsNode *node;
00685 
00686           node=lib3ds_node_new_target();
00687           if (!node) {
00688             return(LIB3DS_FALSE);
00689           }
00690           node->node_id=node_number++;
00691           lib3ds_chunk_read_reset(&c, io);
00692           if (!lib3ds_node_read(node, file, io)) {
00693             return(LIB3DS_FALSE);
00694           }
00695           lib3ds_file_insert_node(file, node);
00696         }
00697         break;
00698       case LIB3DS_LIGHT_NODE_TAG:
00699       case LIB3DS_SPOTLIGHT_NODE_TAG:
00700         {
00701           Lib3dsNode *node;
00702 
00703           node=lib3ds_node_new_light();
00704           if (!node) {
00705             return(LIB3DS_FALSE);
00706           }
00707           node->node_id=node_number++;
00708           lib3ds_chunk_read_reset(&c, io);
00709           if (!lib3ds_node_read(node, file, io)) {
00710             return(LIB3DS_FALSE);
00711           }
00712           lib3ds_file_insert_node(file, node);
00713         }
00714         break;
00715       case LIB3DS_L_TARGET_NODE_TAG:
00716         {
00717           Lib3dsNode *node;
00718 
00719           node=lib3ds_node_new_spot();
00720           if (!node) {
00721             return(LIB3DS_FALSE);
00722           }
00723           node->node_id=node_number++;
00724           lib3ds_chunk_read_reset(&c, io);
00725           if (!lib3ds_node_read(node, file, io)) {
00726             return(LIB3DS_FALSE);
00727           }
00728           lib3ds_file_insert_node(file, node);
00729         }
00730         break;
00731       default:
00732         lib3ds_chunk_unknown(chunk);
00733     }
00734   }
00735 
00736   lib3ds_chunk_read_end(&c, io);
00737   return(LIB3DS_TRUE);
00738 }
00739 
00740 
00751 Lib3dsBool
00752 lib3ds_file_read(Lib3dsFile *file, Lib3dsIo *io)
00753 {
00754   Lib3dsChunk c;
00755   Lib3dsWord chunk;
00756 
00757   if (!lib3ds_chunk_read_start(&c, 0, io)) {
00758     return(LIB3DS_FALSE);
00759   }
00760   switch (c.chunk) {
00761     case LIB3DS_MDATA:
00762       {
00763         lib3ds_chunk_read_reset(&c, io);
00764         if (!mdata_read(file, io)) {
00765           return(LIB3DS_FALSE);
00766         }
00767       }
00768       break;
00769     case LIB3DS_M3DMAGIC:
00770     case LIB3DS_MLIBMAGIC:
00771     case LIB3DS_CMAGIC:
00772       {
00773         while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
00774           switch (chunk) {
00775             case LIB3DS_M3D_VERSION:
00776               {
00777                 file->mesh_version=lib3ds_io_read_dword(io);
00778               }
00779               break;
00780             case LIB3DS_MDATA:
00781               {
00782                 lib3ds_chunk_read_reset(&c, io);
00783                 if (!mdata_read(file, io)) {
00784                   return(LIB3DS_FALSE);
00785                 }
00786               }
00787               break;
00788             case LIB3DS_KFDATA:
00789               {
00790                 lib3ds_chunk_read_reset(&c, io);
00791                 if (!kfdata_read(file, io)) {
00792                   return(LIB3DS_FALSE);
00793                 }
00794               }
00795               break;
00796             default:
00797               lib3ds_chunk_unknown(chunk);
00798           }
00799         }
00800       }
00801       break;
00802     default:
00803       lib3ds_chunk_unknown(c.chunk);
00804       return(LIB3DS_FALSE);
00805   }
00806 
00807   lib3ds_chunk_read_end(&c, io);
00808   return(LIB3DS_TRUE);
00809 }
00810 
00811 
00812 static Lib3dsBool
00813 colorf_write(Lib3dsRgba rgb, Lib3dsIo *io)
00814 {
00815   Lib3dsChunk c;
00816 
00817   c.chunk=LIB3DS_COLOR_F;
00818   c.size=18;
00819   lib3ds_chunk_write(&c,io);
00820   lib3ds_io_write_rgb(io, rgb);
00821 
00822   c.chunk=LIB3DS_LIN_COLOR_F;
00823   c.size=18;
00824   lib3ds_chunk_write(&c,io);
00825   lib3ds_io_write_rgb(io, rgb);
00826   return(LIB3DS_TRUE);
00827 }
00828 
00829 
00830 static Lib3dsBool
00831 object_flags_write(Lib3dsDword flags, Lib3dsIo *io)
00832 {
00833   if (flags){
00834     if (flags & LIB3DS_OBJECT_HIDDEN) {
00835       if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_HIDDEN, io))
00836         return LIB3DS_FALSE;
00837     }
00838     if (flags & LIB3DS_OBJECT_VIS_LOFTER) {
00839       if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_VIS_LOFTER, io))
00840         return LIB3DS_FALSE;
00841     }
00842     if (flags & LIB3DS_OBJECT_DOESNT_CAST) {
00843       if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_DOESNT_CAST, io))
00844         return LIB3DS_FALSE;
00845     }
00846     if (flags & LIB3DS_OBJECT_MATTE) {
00847       if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_MATTE, io))
00848         return LIB3DS_FALSE;
00849     }
00850     if (flags & LIB3DS_OBJECT_DONT_RCVSHADOW) {
00851       if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_DOESNT_CAST, io))
00852         return LIB3DS_FALSE;
00853     }
00854     if (flags & LIB3DS_OBJECT_FAST) {
00855       if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_FAST, io))
00856         return LIB3DS_FALSE;
00857     }
00858     if (flags & LIB3DS_OBJECT_FROZEN) {
00859       if (!lib3ds_chunk_write_switch(LIB3DS_OBJ_FROZEN, io))
00860         return LIB3DS_FALSE;
00861     }
00862   }
00863   return LIB3DS_TRUE;
00864 }
00865 
00866 
00867 static Lib3dsBool
00868 mdata_write(Lib3dsFile *file, Lib3dsIo *io)
00869 {
00870   Lib3dsChunk c;
00871 
00872   c.chunk=LIB3DS_MDATA;
00873   if (!lib3ds_chunk_write_start(&c,io)) {
00874     return(LIB3DS_FALSE);
00875   }
00876 
00877   { /*---- LIB3DS_MESH_VERSION ----*/
00878     Lib3dsChunk c;
00879     c.chunk=LIB3DS_MESH_VERSION;
00880     c.size=10;
00881     lib3ds_chunk_write(&c,io);
00882     lib3ds_io_write_intd(io, file->mesh_version);
00883   }
00884   { /*---- LIB3DS_MASTER_SCALE ----*/
00885     Lib3dsChunk c;
00886     c.chunk=LIB3DS_MASTER_SCALE;
00887     c.size=10;
00888     lib3ds_chunk_write(&c,io);
00889     lib3ds_io_write_float(io, file->master_scale);
00890   }
00891   { /*---- LIB3DS_O_CONSTS ----*/
00892     int i;
00893     for (i=0; i<3; ++i) {
00894       if (fabs(file->construction_plane[i])>LIB3DS_EPSILON) {
00895         break;
00896       }
00897     }
00898     if (i<3) {
00899       Lib3dsChunk c;
00900       c.chunk=LIB3DS_O_CONSTS;
00901       c.size=18;
00902       lib3ds_chunk_write(&c,io);
00903       lib3ds_io_write_vector(io, file->construction_plane);
00904     }
00905   }
00906   
00907   { /*---- LIB3DS_AMBIENT_LIGHT ----*/
00908     int i;
00909     for (i=0; i<3; ++i) {
00910       if (fabs(file->ambient[i])>LIB3DS_EPSILON) {
00911         break;
00912       }
00913     }
00914     if (i<3) {
00915       Lib3dsChunk c;
00916       c.chunk=LIB3DS_AMBIENT_LIGHT;
00917       c.size=42;
00918       lib3ds_chunk_write(&c,io);
00919       colorf_write(file->ambient,io);
00920     }
00921   }
00922   lib3ds_background_write(&file->background, io);
00923   lib3ds_atmosphere_write(&file->atmosphere, io);
00924   lib3ds_shadow_write(&file->shadow, io);
00925   lib3ds_viewport_write(&file->viewport, io);
00926   {
00927     Lib3dsMaterial *p;
00928     for (p=file->materials; p!=0; p=p->next) {
00929       if (!lib3ds_material_write(p,io)) {
00930         return(LIB3DS_FALSE);
00931       }
00932     }
00933   }
00934   {
00935     Lib3dsCamera *p;
00936     Lib3dsChunk c;
00937     
00938     for (p=file->cameras; p!=0; p=p->next) {
00939       c.chunk=LIB3DS_NAMED_OBJECT;
00940       if (!lib3ds_chunk_write_start(&c,io)) {
00941         return(LIB3DS_FALSE);
00942       }
00943       lib3ds_io_write_string(io, p->name);
00944       lib3ds_camera_write(p,io);
00945       object_flags_write(p->object_flags,io);
00946       if (!lib3ds_chunk_write_end(&c,io)) {
00947         return(LIB3DS_FALSE);
00948       }
00949     }
00950   }
00951   {
00952     Lib3dsLight *p;
00953     Lib3dsChunk c;
00954     
00955     for (p=file->lights; p!=0; p=p->next) {
00956       c.chunk=LIB3DS_NAMED_OBJECT;
00957       if (!lib3ds_chunk_write_start(&c,io)) {
00958         return(LIB3DS_FALSE);
00959       }
00960       lib3ds_io_write_string(io,p->name);
00961       lib3ds_light_write(p,io);
00962       object_flags_write(p->object_flags,io);
00963       if (!lib3ds_chunk_write_end(&c,io)) {
00964         return(LIB3DS_FALSE);
00965       }
00966     }
00967   }
00968   {
00969     Lib3dsMesh *p;
00970     Lib3dsChunk c;
00971     
00972     for (p=file->meshes; p!=0; p=p->next) {
00973       c.chunk=LIB3DS_NAMED_OBJECT;
00974       if (!lib3ds_chunk_write_start(&c,io)) {
00975         return(LIB3DS_FALSE);
00976       }
00977       lib3ds_io_write_string(io, p->name);
00978       lib3ds_mesh_write(p,io);
00979       object_flags_write(p->object_flags,io);
00980       if (!lib3ds_chunk_write_end(&c,io)) {
00981         return(LIB3DS_FALSE);
00982       }
00983     }
00984   }
00985 
00986   if (!lib3ds_chunk_write_end(&c,io)) {
00987     return(LIB3DS_FALSE);
00988   }
00989   return(LIB3DS_TRUE);
00990 }
00991 
00992 
00993 
00994 static Lib3dsBool
00995 nodes_write(Lib3dsNode *node, Lib3dsFile *file, Lib3dsIo *io)
00996 {
00997   {
00998     Lib3dsNode *p;
00999     for (p=node->childs; p!=0; p=p->next) {
01000       if (!lib3ds_node_write(p, file, io)) {
01001         return(LIB3DS_FALSE);
01002       }
01003       nodes_write(p, file, io);
01004     }
01005   }
01006   return(LIB3DS_TRUE);
01007 }
01008 
01009 
01010 static Lib3dsBool
01011 kfdata_write(Lib3dsFile *file, Lib3dsIo *io)
01012 {
01013   Lib3dsChunk c;
01014 
01015   if (!file->nodes) {
01016     return(LIB3DS_TRUE);
01017   }
01018   
01019   c.chunk=LIB3DS_KFDATA;
01020   if (!lib3ds_chunk_write_start(&c,io)) {
01021     return(LIB3DS_FALSE);
01022   }
01023   
01024   { /*---- LIB3DS_KFHDR ----*/
01025     Lib3dsChunk c;
01026     c.chunk=LIB3DS_KFHDR;
01027     c.size=6 + 2 + (Lib3dsDword)strlen(file->name)+1 +4;
01028     lib3ds_chunk_write(&c,io);
01029     lib3ds_io_write_intw(io, file->keyf_revision);
01030     lib3ds_io_write_string(io, file->name);
01031     lib3ds_io_write_intd(io, file->frames);
01032   }
01033   { /*---- LIB3DS_KFSEG ----*/
01034     Lib3dsChunk c;
01035     c.chunk=LIB3DS_KFSEG;
01036     c.size=14;
01037     lib3ds_chunk_write(&c,io);
01038     lib3ds_io_write_intd(io, file->segment_from);
01039     lib3ds_io_write_intd(io, file->segment_to);
01040   }
01041   { /*---- LIB3DS_KFCURTIME ----*/
01042     Lib3dsChunk c;
01043     c.chunk=LIB3DS_KFCURTIME;
01044     c.size=10;
01045     lib3ds_chunk_write(&c,io);
01046     lib3ds_io_write_intd(io, file->current_frame);
01047   }
01048   lib3ds_viewport_write(&file->viewport_keyf, io);
01049   
01050   {
01051     Lib3dsNode *p;
01052     for (p=file->nodes; p!=0; p=p->next) {
01053       if (!lib3ds_node_write(p, file, io)) {
01054         return(LIB3DS_FALSE);
01055       }
01056       if (!nodes_write(p, file, io)) {
01057         return(LIB3DS_FALSE);
01058       }
01059     }
01060   }
01061   
01062   if (!lib3ds_chunk_write_end(&c,io)) {
01063     return(LIB3DS_FALSE);
01064   }
01065   return(LIB3DS_TRUE);
01066 }
01067 
01068 
01079 Lib3dsBool
01080 lib3ds_file_write(Lib3dsFile *file, Lib3dsIo *io)
01081 {
01082   Lib3dsChunk c;
01083 
01084   c.chunk=LIB3DS_M3DMAGIC;
01085   if (!lib3ds_chunk_write_start(&c,io)) {
01086     LIB3DS_ERROR_LOG;
01087     return(LIB3DS_FALSE);
01088   }
01089 
01090   { /*---- LIB3DS_M3D_VERSION ----*/
01091     Lib3dsChunk c;
01092 
01093     c.chunk=LIB3DS_M3D_VERSION;
01094     c.size=10;
01095     lib3ds_chunk_write(&c,io);
01096     lib3ds_io_write_dword(io, file->mesh_version);
01097   }
01098 
01099   if (!mdata_write(file, io)) {
01100     return(LIB3DS_FALSE);
01101   }
01102   if (!kfdata_write(file, io)) {
01103     return(LIB3DS_FALSE);
01104   }
01105 
01106   if (!lib3ds_chunk_write_end(&c,io)) {
01107     return(LIB3DS_FALSE);
01108   }
01109   return(LIB3DS_TRUE);
01110 }
01111 
01112 
01125 void
01126 lib3ds_file_insert_material(Lib3dsFile *file, Lib3dsMaterial *material)
01127 {
01128   Lib3dsMaterial *p,*q;
01129   
01130   ASSERT(file);
01131   ASSERT(material);
01132   ASSERT(!material->next);
01133 
01134   q=0;
01135   for (p=file->materials; p!=0; p=p->next) {
01136     if (strcmp(material->name, p->name)<0) {
01137       break;
01138     }
01139     q=p;
01140   }
01141   if (!q) {
01142     material->next=file->materials;
01143     file->materials=material;
01144   }
01145   else {
01146     material->next=q->next;
01147     q->next=material;
01148   }
01149 }
01150 
01151 
01164 void
01165 lib3ds_file_remove_material(Lib3dsFile *file, Lib3dsMaterial *material)
01166 {
01167   Lib3dsMaterial *p,*q;
01168 
01169   ASSERT(file);
01170   ASSERT(material);
01171   ASSERT(file->materials);
01172   for (p=0,q=file->materials; q; p=q,q=q->next) {
01173     if (q==material) {
01174       break;
01175     }
01176   }
01177   if (!q) {
01178     ASSERT(LIB3DS_FALSE);
01179     return;
01180   }
01181   if (!p) {
01182     file->materials=material->next;
01183   }
01184   else {
01185     p->next=q->next;
01186   }
01187   material->next=0;
01188 }
01189 
01190 
01201 Lib3dsMaterial*
01202 lib3ds_file_material_by_name(Lib3dsFile *file, const char *name)
01203 {
01204   Lib3dsMaterial *p;
01205 
01206   ASSERT(file);
01207   for (p=file->materials; p!=0; p=p->next) {
01208     if (strcmp(p->name,name)==0) {
01209       return(p);
01210     }
01211   }
01212   return(0);
01213 }
01214 
01215 
01225 void
01226 lib3ds_file_dump_materials(Lib3dsFile *file)
01227 {
01228   Lib3dsMaterial *p;
01229 
01230   ASSERT(file);
01231   for (p=file->materials; p!=0; p=p->next) {
01232     lib3ds_material_dump(p);
01233   }
01234 }
01235 
01236 
01249 void
01250 lib3ds_file_insert_mesh(Lib3dsFile *file, Lib3dsMesh *mesh)
01251 {
01252   Lib3dsMesh *p,*q;
01253   
01254   ASSERT(file);
01255   ASSERT(mesh);
01256   ASSERT(!mesh->next);
01257 
01258   q=0;
01259   for (p=file->meshes; p!=0; p=p->next) {
01260     if (strcmp(mesh->name, p->name)<0) {
01261       break;
01262     }
01263     q=p;
01264   }
01265   if (!q) {
01266     mesh->next=file->meshes;
01267     file->meshes=mesh;
01268   }
01269   else {
01270     mesh->next=q->next;
01271     q->next=mesh;
01272   }
01273 }
01274 
01275 
01288 void
01289 lib3ds_file_remove_mesh(Lib3dsFile *file, Lib3dsMesh *mesh)
01290 {
01291   Lib3dsMesh *p,*q;
01292 
01293   ASSERT(file);
01294   ASSERT(mesh);
01295   ASSERT(file->meshes);
01296   for (p=0,q=file->meshes; q; p=q,q=q->next) {
01297     if (q==mesh) {
01298       break;
01299     }
01300   }
01301   if (!q) {
01302     ASSERT(LIB3DS_FALSE);
01303     return;
01304   }
01305   if (!p) {
01306     file->meshes=mesh->next;
01307   }
01308   else {
01309     p->next=q->next;
01310   }
01311   mesh->next=0;
01312 }
01313 
01314 
01325 Lib3dsMesh*
01326 lib3ds_file_mesh_by_name(Lib3dsFile *file, const char *name)
01327 {
01328   Lib3dsMesh *p;
01329 
01330   ASSERT(file);
01331   for (p=file->meshes; p!=0; p=p->next) {
01332     if (strcmp(p->name,name)==0) {
01333       return(p);
01334     }
01335   }
01336   return(0);
01337 }
01338 
01339 
01349 void
01350 lib3ds_file_dump_meshes(Lib3dsFile *file)
01351 {
01352   Lib3dsMesh *p;
01353 
01354   ASSERT(file);
01355   for (p=file->meshes; p!=0; p=p->next) {
01356     lib3ds_mesh_dump(p);
01357   }
01358 }
01359 
01360 
01361 static void
01362 dump_instances(Lib3dsNode *node, const char* parent)
01363 {
01364   Lib3dsNode *p;
01365   char name[255];
01366 
01367   ASSERT(node);
01368   ASSERT(parent);
01369   strcpy(name, parent);
01370   strcat(name, ".");
01371   strcat(name, node->name);
01372   if (node->type==LIB3DS_OBJECT_NODE) {
01373     printf("  %s : %s\n", name, node->data.object.instance);
01374   }
01375   for (p=node->childs; p!=0; p=p->next) {
01376     dump_instances(p, parent);
01377   }
01378 }
01379 
01380 
01396 void
01397 lib3ds_file_dump_instances(Lib3dsFile *file)
01398 {
01399   Lib3dsNode *p;
01400 
01401   ASSERT(file);
01402   for (p=file->nodes; p!=0; p=p->next) {
01403     dump_instances(p,"");
01404   }
01405 }
01406 
01407 
01420 void
01421 lib3ds_file_insert_camera(Lib3dsFile *file, Lib3dsCamera *camera)
01422 {
01423   Lib3dsCamera *p,*q;
01424   
01425   ASSERT(file);
01426   ASSERT(camera);
01427   ASSERT(!camera->next);
01428 
01429   q=0;
01430   for (p=file->cameras; p!=0; p=p->next) {
01431     if (strcmp(camera->name, p->name)<0) {
01432       break;
01433     }
01434     q=p;
01435   }
01436   if (!q) {
01437     camera->next=file->cameras;
01438     file->cameras=camera;
01439   }
01440   else {
01441     camera->next=q->next;
01442     q->next=camera;
01443   }
01444 }
01445 
01446 
01459 void
01460 lib3ds_file_remove_camera(Lib3dsFile *file, Lib3dsCamera *camera)
01461 {
01462   Lib3dsCamera *p,*q;
01463 
01464   ASSERT(file);
01465   ASSERT(camera);
01466   ASSERT(file->cameras);
01467   for (p=0,q=file->cameras; q; p=q,q=q->next) {
01468     if (q==camera) {
01469       break;
01470     }
01471   }
01472   if (!q) {
01473     ASSERT(LIB3DS_FALSE);
01474     return;
01475   }
01476   if (!p) {
01477     file->cameras=camera->next;
01478   }
01479   else {
01480     p->next=q->next;
01481   }
01482   camera->next=0;
01483 }
01484 
01485 
01496 Lib3dsCamera*
01497 lib3ds_file_camera_by_name(Lib3dsFile *file, const char *name)
01498 {
01499   Lib3dsCamera *p;
01500 
01501   ASSERT(file);
01502   for (p=file->cameras; p!=0; p=p->next) {
01503     if (strcmp(p->name,name)==0) {
01504       return(p);
01505     }
01506   }
01507   return(0);
01508 }
01509 
01510 
01520 void
01521 lib3ds_file_dump_cameras(Lib3dsFile *file)
01522 {
01523   Lib3dsCamera *p;
01524 
01525   ASSERT(file);
01526   for (p=file->cameras; p!=0; p=p->next) {
01527     lib3ds_camera_dump(p);
01528   }
01529 }
01530 
01531 
01544 void
01545 lib3ds_file_insert_light(Lib3dsFile *file, Lib3dsLight *light)
01546 {
01547   Lib3dsLight *p,*q;
01548   
01549   ASSERT(file);
01550   ASSERT(light);
01551   ASSERT(!light->next);
01552 
01553   q=0;
01554   for (p=file->lights; p!=0; p=p->next) {
01555     if (strcmp(light->name, p->name)<0) {
01556       break;
01557     }
01558     q=p;
01559   }
01560   if (!q) {
01561     light->next=file->lights;
01562     file->lights=light;
01563   }
01564   else {
01565     light->next=q->next;
01566     q->next=light;
01567   }
01568 }
01569 
01570 
01583 void
01584 lib3ds_file_remove_light(Lib3dsFile *file, Lib3dsLight *light)
01585 {
01586   Lib3dsLight *p,*q;
01587 
01588   ASSERT(file);
01589   ASSERT(light);
01590   ASSERT(file->lights);
01591   for (p=0,q=file->lights; q; p=q,q=q->next) {
01592     if (q==light) {
01593       break;
01594     }
01595   }
01596   if (!q) {
01597     ASSERT(LIB3DS_FALSE);
01598     return;
01599   }
01600   if (!p) {
01601     file->lights=light->next;
01602   }
01603   else {
01604     p->next=q->next;
01605   }
01606   light->next=0;
01607 }
01608 
01609 
01620 Lib3dsLight*
01621 lib3ds_file_light_by_name(Lib3dsFile *file, const char *name)
01622 {
01623   Lib3dsLight *p;
01624 
01625   ASSERT(file);
01626   for (p=file->lights; p!=0; p=p->next) {
01627     if (strcmp(p->name,name)==0) {
01628       return(p);
01629     }
01630   }
01631   return(0);
01632 }
01633 
01634 
01644 void
01645 lib3ds_file_dump_lights(Lib3dsFile *file)
01646 {
01647   Lib3dsLight *p;
01648 
01649   ASSERT(file);
01650   for (p=file->lights; p!=0; p=p->next) {
01651     lib3ds_light_dump(p);
01652   }
01653 }
01654 
01655 
01672 Lib3dsNode*
01673 lib3ds_file_node_by_name(Lib3dsFile *file, const char* name, Lib3dsNodeTypes type)
01674 {
01675   Lib3dsNode *p,*q;
01676 
01677   ASSERT(file);
01678   for (p=file->nodes; p!=0; p=p->next) {
01679     if ((p->type==type) && (strcmp(p->name, name)==0)) {
01680       return(p);
01681     }
01682     q=lib3ds_node_by_name(p, name, type);
01683     if (q) {
01684       return(q);
01685     }
01686   }
01687   return(0);
01688 }
01689 
01690 
01705 Lib3dsNode*
01706 lib3ds_file_node_by_id(Lib3dsFile *file, Lib3dsWord node_id)
01707 {
01708   Lib3dsNode *p,*q;
01709 
01710   ASSERT(file);
01711   for (p=file->nodes; p!=0; p=p->next) {
01712     if (p->node_id==node_id) {
01713       return(p);
01714     }
01715     q=lib3ds_node_by_id(p, node_id);
01716     if (q) {
01717       return(q);
01718     }
01719   }
01720   return(0);
01721 }
01722 
01723 
01743 void
01744 lib3ds_file_insert_node(Lib3dsFile *file, Lib3dsNode *node)
01745 {
01746   Lib3dsNode *parent,*p,*n;
01747   
01748   ASSERT(node);
01749   ASSERT(!node->next);
01750   ASSERT(!node->parent);
01751 
01752   parent=0;
01753   if (node->parent_id!=LIB3DS_NO_PARENT) {
01754     parent=lib3ds_file_node_by_id(file, node->parent_id);
01755   }
01756   node->parent=parent;
01757   
01758   if (!parent) {
01759     for (p=0,n=file->nodes; n!=0; p=n,n=n->next) {
01760       if (strcmp(n->name, node->name)>0) {
01761         break;
01762       }
01763     }
01764     if (!p) {
01765       node->next=file->nodes;
01766       file->nodes=node;
01767     }