00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "lib3ds_impl.h"
00019
00020
00021 static long
00022 fileio_seek_func(void *self, long offset, Lib3dsIoSeek origin) {
00023 FILE *f = (FILE*)self;
00024 int o;
00025 switch (origin) {
00026 case LIB3DS_SEEK_SET:
00027 o = SEEK_SET;
00028 break;
00029
00030 case LIB3DS_SEEK_CUR:
00031 o = SEEK_CUR;
00032 break;
00033
00034 case LIB3DS_SEEK_END:
00035 o = SEEK_END;
00036 break;
00037
00038 default:
00039 assert(0);
00040 return(0);
00041 }
00042 return (fseek(f, offset, o));
00043 }
00044
00045
00046 static long
00047 fileio_tell_func(void *self) {
00048 FILE *f = (FILE*)self;
00049 return(ftell(f));
00050 }
00051
00052
00053 static size_t
00054 fileio_read_func(void *self, void *buffer, size_t size) {
00055 FILE *f = (FILE*)self;
00056 return(fread(buffer, 1, size, f));
00057 }
00058
00059
00060 static size_t
00061 fileio_write_func(void *self, const void *buffer, size_t size) {
00062 FILE *f = (FILE*)self;
00063 return(fwrite(buffer, 1, size, f));
00064 }
00065
00066
00082 Lib3dsFile*
00083 lib3ds_file_open(const char *filename) {
00084 FILE *f;
00085 Lib3dsFile *file;
00086 Lib3dsIo io;
00087
00088 f = fopen(filename, "rb");
00089 if (!f) {
00090 return NULL;
00091 }
00092 file = lib3ds_file_new();
00093 if (!file) {
00094 fclose(f);
00095 return NULL;
00096 }
00097
00098 memset(&io, 0, sizeof(io));
00099 io.self = f;
00100 io.seek_func = fileio_seek_func;
00101 io.tell_func = fileio_tell_func;
00102 io.read_func = fileio_read_func;
00103 io.write_func = fileio_write_func;
00104 io.log_func = NULL;
00105
00106 if (!lib3ds_file_read(file, &io)) {
00107 fclose(f);
00108 free(file);
00109 return NULL;
00110 }
00111
00112 fclose(f);
00113 return file;
00114 }
00115
00116
00128 int
00129 lib3ds_file_save(Lib3dsFile *file, const char *filename) {
00130 FILE *f;
00131 Lib3dsIo io;
00132 int result;
00133
00134 f = fopen(filename, "wb");
00135 if (!f) {
00136 return FALSE;
00137 }
00138
00139 memset(&io, 0, sizeof(io));
00140 io.self = f;
00141 io.seek_func = fileio_seek_func;
00142 io.tell_func = fileio_tell_func;
00143 io.read_func = fileio_read_func;
00144 io.write_func = fileio_write_func;
00145 io.log_func = NULL;
00146
00147 result = lib3ds_file_write(file, &io);
00148 fclose(f);
00149 return result;
00150 }
00151
00152
00159 Lib3dsFile*
00160 lib3ds_file_new() {
00161 Lib3dsFile *file;
00162
00163 file = (Lib3dsFile*)calloc(sizeof(Lib3dsFile), 1);
00164 if (!file) {
00165 return(0);
00166 }
00167 file->mesh_version = 3;
00168 file->master_scale = 1.0f;
00169 file->keyf_revision = 5;
00170 strcpy(file->name, "LIB3DS");
00171
00172 file->frames = 100;
00173 file->segment_from = 0;
00174 file->segment_to = 100;
00175 file->current_frame = 0;
00176
00177 return(file);
00178 }
00179
00180
00186 void
00187 lib3ds_file_free(Lib3dsFile* file) {
00188 assert(file);
00189 lib3ds_file_reserve_materials(file, 0, TRUE);
00190 lib3ds_file_reserve_cameras(file, 0, TRUE);
00191 lib3ds_file_reserve_lights(file, 0, TRUE);
00192 lib3ds_file_reserve_meshes(file, 0, TRUE);
00193 {
00194 Lib3dsNode *p, *q;
00195
00196 for (p = file->nodes; p; p = q) {
00197 q = p->next;
00198 lib3ds_node_free(p);
00199 }
00200 }
00201 free(file);
00202 }
00203
00204
00213 void
00214 lib3ds_file_eval(Lib3dsFile *file, float t) {
00215 Lib3dsNode *p;
00216
00217 for (p = file->nodes; p != 0; p = p->next) {
00218 lib3ds_node_eval(p, t);
00219 }
00220 }
00221
00222
00223 static void
00224 named_object_read(Lib3dsFile *file, Lib3dsIo *io) {
00225 Lib3dsChunk c;
00226 char name[64];
00227 uint16_t chunk;
00228 Lib3dsMesh *mesh = NULL;
00229 Lib3dsCamera *camera = NULL;
00230 Lib3dsLight *light = NULL;
00231 uint32_t object_flags;
00232
00233 lib3ds_chunk_read_start(&c, CHK_NAMED_OBJECT, io);
00234
00235 lib3ds_io_read_string(io, name, 64);
00236 lib3ds_io_log(io, LIB3DS_LOG_INFO, " NAME=%s", name);
00237 lib3ds_chunk_read_tell(&c, io);
00238
00239 object_flags = 0;
00240 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
00241 switch (chunk) {
00242 case CHK_N_TRI_OBJECT: {
00243 mesh = lib3ds_mesh_new(name);
00244 lib3ds_file_insert_mesh(file, mesh, -1);
00245 lib3ds_chunk_read_reset(&c, io);
00246 lib3ds_mesh_read(file, mesh, io);
00247 break;
00248 }
00249
00250 case CHK_N_CAMERA: {
00251 camera = lib3ds_camera_new(name);
00252 lib3ds_file_insert_camera(file, camera, -1);
00253 lib3ds_chunk_read_reset(&c, io);
00254 lib3ds_camera_read(camera, io);
00255 break;
00256 }
00257
00258 case CHK_N_DIRECT_LIGHT: {
00259 light = lib3ds_light_new(name);
00260 lib3ds_file_insert_light(file, light, -1);
00261 lib3ds_chunk_read_reset(&c, io);
00262 lib3ds_light_read(light, io);
00263 break;
00264 }
00265
00266 case CHK_OBJ_HIDDEN:
00267 object_flags |= LIB3DS_OBJECT_HIDDEN;
00268 break;
00269
00270 case CHK_OBJ_DOESNT_CAST:
00271 object_flags |= LIB3DS_OBJECT_DOESNT_CAST;
00272 break;
00273
00274 case CHK_OBJ_VIS_LOFTER:
00275 object_flags |= LIB3DS_OBJECT_VIS_LOFTER;
00276 break;
00277
00278 case CHK_OBJ_MATTE:
00279 object_flags |= LIB3DS_OBJECT_MATTE;
00280 break;
00281
00282 case CHK_OBJ_DONT_RCVSHADOW:
00283 object_flags |= LIB3DS_OBJECT_DONT_RCVSHADOW;
00284 break;
00285
00286 case CHK_OBJ_FAST:
00287 object_flags |= LIB3DS_OBJECT_FAST;
00288 break;
00289
00290 case CHK_OBJ_FROZEN:
00291 object_flags |= LIB3DS_OBJECT_FROZEN;
00292 break;
00293
00294 default:
00295 lib3ds_chunk_unknown(chunk, io);
00296 }
00297 }
00298
00299 if (mesh)
00300 mesh->object_flags = object_flags;
00301 if (camera)
00302 camera->object_flags = object_flags;
00303 if (light)
00304 light->object_flags = object_flags;
00305
00306 lib3ds_chunk_read_end(&c, io);
00307 }
00308
00309
00310 static void
00311 ambient_read(Lib3dsFile *file, Lib3dsIo *io) {
00312 Lib3dsChunk c;
00313 uint16_t chunk;
00314 int have_lin = FALSE;
00315
00316 lib3ds_chunk_read_start(&c, CHK_AMBIENT_LIGHT, io);
00317
00318 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
00319 switch (chunk) {
00320 case CHK_LIN_COLOR_F: {
00321 int i;
00322 for (i = 0; i < 3; ++i) {
00323 file->ambient[i] = lib3ds_io_read_float(io);
00324 }
00325 have_lin = TRUE;
00326 break;
00327 }
00328
00329 case CHK_COLOR_F: {
00330
00331
00332 if (!have_lin) {
00333 int i;
00334 for (i = 0; i < 3; ++i) {
00335 file->ambient[i] = lib3ds_io_read_float(io);
00336 }
00337 }
00338 break;
00339 }
00340
00341 default:
00342 lib3ds_chunk_unknown(chunk, io);
00343 }
00344 }
00345
00346 lib3ds_chunk_read_end(&c, io);
00347 }
00348
00349
00350 static void
00351 mdata_read(Lib3dsFile *file, Lib3dsIo *io) {
00352 Lib3dsChunk c;
00353 uint16_t chunk;
00354
00355 lib3ds_chunk_read_start(&c, CHK_MDATA, io);
00356
00357 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
00358 switch (chunk) {
00359 case CHK_MESH_VERSION: {
00360 file->mesh_version = lib3ds_io_read_intd(io);
00361 break;
00362 }
00363
00364 case CHK_MASTER_SCALE: {
00365 file->master_scale = lib3ds_io_read_float(io);
00366 break;
00367 }
00368
00369 case CHK_SHADOW_MAP_SIZE:
00370 case CHK_LO_SHADOW_BIAS:
00371 case CHK_HI_SHADOW_BIAS:
00372 case CHK_SHADOW_SAMPLES:
00373 case CHK_SHADOW_RANGE:
00374 case CHK_SHADOW_FILTER:
00375 case CHK_RAY_BIAS: {
00376 lib3ds_chunk_read_reset(&c, io);
00377 lib3ds_shadow_read(&file->shadow, io);
00378 break;
00379 }
00380
00381 case CHK_VIEWPORT_LAYOUT:
00382 case CHK_DEFAULT_VIEW: {
00383 lib3ds_chunk_read_reset(&c, io);
00384 lib3ds_viewport_read(&file->viewport, io);
00385 break;
00386 }
00387
00388 case CHK_O_CONSTS: {
00389 int i;
00390 for (i = 0; i < 3; ++i) {
00391 file->construction_plane[i] = lib3ds_io_read_float(io);
00392 }
00393 break;
00394 }
00395
00396 case CHK_AMBIENT_LIGHT: {
00397 lib3ds_chunk_read_reset(&c, io);
00398 ambient_read(file, io);
00399 break;
00400 }
00401
00402 case CHK_BIT_MAP:
00403 case CHK_SOLID_BGND:
00404 case CHK_V_GRADIENT:
00405 case CHK_USE_BIT_MAP:
00406 case CHK_USE_SOLID_BGND:
00407 case CHK_USE_V_GRADIENT: {
00408 lib3ds_chunk_read_reset(&c, io);
00409 lib3ds_background_read(&file->background, io);
00410 break;
00411 }
00412
00413 case CHK_FOG:
00414 case CHK_LAYER_FOG:
00415 case CHK_DISTANCE_CUE:
00416 case CHK_USE_FOG:
00417 case CHK_USE_LAYER_FOG:
00418 case CHK_USE_DISTANCE_CUE: {
00419 lib3ds_chunk_read_reset(&c, io);
00420 lib3ds_atmosphere_read(&file->atmosphere, io);
00421 break;
00422 }
00423
00424 case CHK_MAT_ENTRY: {
00425 Lib3dsMaterial *material = lib3ds_material_new(NULL);
00426 lib3ds_file_insert_material(file, material, -1);
00427 lib3ds_chunk_read_reset(&c, io);
00428 lib3ds_material_read(material, io);
00429 break;
00430 }
00431
00432 case CHK_NAMED_OBJECT: {
00433 lib3ds_chunk_read_reset(&c, io);
00434 named_object_read(file, io);
00435 break;
00436 }
00437
00438 default:
00439 lib3ds_chunk_unknown(chunk, io);
00440 }
00441 }
00442
00443 lib3ds_chunk_read_end(&c, io);
00444 }
00445
00446
00447 static int
00448 compare_node_id( const void *a, const void *b ) {
00449 return (*((Lib3dsNode**)a))->node_id - (*((Lib3dsNode**)b))->node_id;
00450 }
00451
00452
00453 static int
00454 compare_node_id2( const void *a, const void *b ) {
00455 return *((unsigned short*)a) - (*((Lib3dsNode**)b))->node_id;
00456 }
00457
00458
00459 static void
00460 kfdata_read(Lib3dsFile *file, Lib3dsIo *io) {
00461 Lib3dsChunk c;
00462 uint16_t chunk;
00463 unsigned num_nodes = 0;
00464 Lib3dsIoImpl *impl = (Lib3dsIoImpl*)io->impl;
00465 Lib3dsNode *last = NULL;
00466
00467 lib3ds_chunk_read_start(&c, CHK_KFDATA, io);
00468
00469 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
00470 switch (chunk) {
00471 case CHK_KFHDR: {
00472 file->keyf_revision = lib3ds_io_read_word(io);
00473 lib3ds_io_read_string(io, file->name, 12 + 1);
00474 file->frames = lib3ds_io_read_intd(io);
00475 break;
00476 }
00477
00478 case CHK_KFSEG: {
00479 file->segment_from = lib3ds_io_read_intd(io);
00480 file->segment_to = lib3ds_io_read_intd(io);
00481 break;
00482 }
00483
00484 case CHK_KFCURTIME: {
00485 file->current_frame = lib3ds_io_read_intd(io);
00486 break;
00487 }
00488
00489 case CHK_VIEWPORT_LAYOUT:
00490 case CHK_DEFAULT_VIEW: {
00491 lib3ds_chunk_read_reset(&c, io);
00492 lib3ds_viewport_read(&file->viewport_keyf, io);
00493 break;
00494 }
00495
00496 case CHK_AMBIENT_NODE_TAG:
00497 case CHK_OBJECT_NODE_TAG:
00498 case CHK_CAMERA_NODE_TAG:
00499 case CHK_TARGET_NODE_TAG:
00500 case CHK_LIGHT_NODE_TAG:
00501 case CHK_SPOTLIGHT_NODE_TAG:
00502 case CHK_L_TARGET_NODE_TAG: {
00503 Lib3dsNodeType type;
00504 Lib3dsNode *node;
00505
00506 switch (chunk) {
00507 case CHK_AMBIENT_NODE_TAG:
00508 type = LIB3DS_NODE_AMBIENT_COLOR;
00509 break;
00510 case CHK_OBJECT_NODE_TAG:
00511 type = LIB3DS_NODE_MESH_INSTANCE;
00512 break;
00513 case CHK_CAMERA_NODE_TAG:
00514 type = LIB3DS_NODE_CAMERA;
00515 break;
00516 case CHK_TARGET_NODE_TAG:
00517 type = LIB3DS_NODE_CAMERA_TARGET;
00518 break;
00519 case CHK_LIGHT_NODE_TAG:
00520 type = LIB3DS_NODE_OMNILIGHT;
00521 break;
00522 case CHK_SPOTLIGHT_NODE_TAG:
00523 type = LIB3DS_NODE_SPOTLIGHT;
00524 break;
00525 case CHK_L_TARGET_NODE_TAG:
00526 type = LIB3DS_NODE_SPOTLIGHT_TARGET;
00527 break;
00528 }
00529
00530 node = lib3ds_node_new(type);
00531 node->node_id = num_nodes++;
00532 if (last) {
00533 last->next = node;
00534 } else {
00535 file->nodes = node;
00536 }
00537 node->user_ptr = last;
00538 last = node;
00539 lib3ds_chunk_read_reset(&c, io);
00540 lib3ds_node_read(node, io);
00541 break;
00542 }
00543
00544 default:
00545 lib3ds_chunk_unknown(chunk, io);
00546 }
00547 }
00548
00549 {
00550 Lib3dsNode **nodes = malloc(num_nodes * sizeof(Lib3dsNode*));
00551 unsigned i;
00552 Lib3dsNode *p, *q, *parent;
00553
00554 p = file->nodes;
00555 for (i = 0; i < num_nodes; ++i) {
00556 nodes[i] = p;
00557 p = p->next;
00558 }
00559 qsort(nodes, num_nodes, sizeof(Lib3dsNode*), compare_node_id);
00560
00561 p = last;
00562 while (p) {
00563 q = p->user_ptr;
00564 if (p->user_id != 65535) {
00565 parent = *(Lib3dsNode**)bsearch(&p->user_id, nodes, num_nodes, sizeof(Lib3dsNode*), compare_node_id2);
00566 if (parent) {
00567 q->next = p->next;
00568 p->next = parent->childs;
00569 p->parent = parent;
00570 parent->childs = p;
00571 } else {
00572
00573 }
00574 }
00575 p->user_id = 0;
00576 p->user_ptr = NULL;
00577 p = q;
00578 }
00579 free(nodes);
00580 }
00581
00582 lib3ds_chunk_read_end(&c, io);
00583 }
00584
00585
00594 int
00595 lib3ds_file_read(Lib3dsFile *file, Lib3dsIo *io) {
00596 Lib3dsChunk c;
00597 uint16_t chunk;
00598 Lib3dsIoImpl *impl;
00599
00600 lib3ds_io_setup(io);
00601 impl = (Lib3dsIoImpl*)io->impl;
00602
00603 if (setjmp(impl->jmpbuf) != 0) {
00604 lib3ds_io_cleanup(io);
00605 return FALSE;
00606 }
00607
00608 lib3ds_chunk_read_start(&c, 0, io);
00609 switch (c.chunk) {
00610 case CHK_MDATA: {
00611 lib3ds_chunk_read_reset(&c, io);
00612 mdata_read(file, io);
00613 break;
00614 }
00615
00616 case CHK_M3DMAGIC:
00617 case CHK_MLIBMAGIC:
00618 case CHK_CMAGIC: {
00619 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
00620 switch (chunk) {
00621 case CHK_M3D_VERSION: {
00622 file->mesh_version = lib3ds_io_read_dword(io);
00623 break;
00624 }
00625
00626 case CHK_MDATA: {
00627 lib3ds_chunk_read_reset(&c, io);
00628 mdata_read(file, io);
00629 break;
00630 }
00631
00632 case CHK_KFDATA: {
00633 lib3ds_chunk_read_reset(&c, io);
00634 kfdata_read(file, io);
00635 break;
00636 }
00637
00638 default:
00639 lib3ds_chunk_unknown(chunk, io);
00640 }
00641 }
00642 break;
00643 }
00644
00645 default:
00646 lib3ds_chunk_unknown(c.chunk, io);
00647 return FALSE;
00648 }
00649
00650 lib3ds_chunk_read_end(&c, io);
00651
00652 memset(impl->jmpbuf, 0, sizeof(impl->jmpbuf));
00653 lib3ds_io_cleanup(io);
00654 return TRUE;
00655 }
00656
00657
00658 static void
00659 colorf_write(float rgb[3], Lib3dsIo *io) {
00660 Lib3dsChunk c;
00661
00662 c.chunk = CHK_COLOR_F;
00663 c.size = 18;
00664 lib3ds_chunk_write(&c, io);
00665 lib3ds_io_write_rgb(io, rgb);
00666
00667 c.chunk = CHK_LIN_COLOR_F;
00668 c.size = 18;
00669 lib3ds_chunk_write(&c, io);
00670 lib3ds_io_write_rgb(io, rgb);
00671 }
00672
00673
00674 static void
00675 object_flags_write(uint32_t flags, Lib3dsIo *io) {
00676 if (flags) {
00677 Lib3dsChunk c;
00678 c.size = 6;
00679
00680 if (flags & LIB3DS_OBJECT_HIDDEN) {
00681 c.chunk = CHK_OBJ_HIDDEN;
00682 lib3ds_chunk_write(&c, io);
00683 }
00684 if (flags & LIB3DS_OBJECT_VIS_LOFTER) {
00685 c.chunk = CHK_OBJ_VIS_LOFTER;
00686 lib3ds_chunk_write(&c, io);
00687 }
00688 if (flags & LIB3DS_OBJECT_DOESNT_CAST) {
00689 c.chunk = CHK_OBJ_DOESNT_CAST;
00690 lib3ds_chunk_write(&c, io);
00691 }
00692 if (flags & LIB3DS_OBJECT_MATTE) {
00693 c.chunk = CHK_OBJ_MATTE;
00694 lib3ds_chunk_write(&c, io);
00695 }
00696 if (flags & LIB3DS_OBJECT_DONT_RCVSHADOW) {
00697 c.chunk = CHK_OBJ_DOESNT_CAST;
00698 lib3ds_chunk_write(&c, io);
00699 }
00700 if (flags & LIB3DS_OBJECT_FAST) {
00701 c.chunk = CHK_OBJ_FAST;
00702 lib3ds_chunk_write(&c, io);
00703 }
00704 if (flags & LIB3DS_OBJECT_FROZEN) {
00705 c.chunk = CHK_OBJ_FROZEN;
00706 lib3ds_chunk_write(&c, io);
00707 }
00708 }
00709 }
00710
00711
00712 static void
00713 mdata_write(Lib3dsFile *file, Lib3dsIo *io) {
00714 Lib3dsChunk c;
00715
00716 c.chunk = CHK_MDATA;
00717 lib3ds_chunk_write_start(&c, io);
00718
00719 {
00720 Lib3dsChunk c;
00721 c.chunk = CHK_MESH_VERSION;
00722 c.size = 10;
00723 lib3ds_chunk_write(&c, io);
00724 lib3ds_io_write_intd(io, file->mesh_version);
00725 }
00726 {
00727 Lib3dsChunk c;
00728 c.chunk = CHK_MASTER_SCALE;
00729 c.size = 10;
00730 lib3ds_chunk_write(&c, io);
00731 lib3ds_io_write_float(io, file->master_scale);
00732 }
00733 {
00734 int i;
00735 for (i = 0; i < 3; ++i) {
00736 if (fabs(file->construction_plane[i]) > LIB3DS_EPSILON) {
00737 break;
00738 }
00739 }
00740 if (i < 3) {
00741 Lib3dsChunk c;
00742 c.chunk = CHK_O_CONSTS;
00743 c.size = 18;
00744 lib3ds_chunk_write(&c, io);
00745 lib3ds_io_write_vector(io, file->construction_plane);
00746 }
00747 }
00748
00749 {
00750 int i;
00751 for (i = 0; i < 3; ++i) {
00752 if (fabs(file->ambient[i]) > LIB3DS_EPSILON) {
00753 break;
00754 }
00755 }
00756 if (i < 3) {
00757 Lib3dsChunk c;
00758 c.chunk = CHK_AMBIENT_LIGHT;
00759 c.size = 42;
00760 lib3ds_chunk_write(&c, io);
00761 colorf_write(file->ambient, io);
00762 }
00763 }
00764 lib3ds_background_write(&file->background, io);
00765 lib3ds_atmosphere_write(&file->atmosphere, io);
00766 lib3ds_shadow_write(&file->shadow, io);
00767 lib3ds_viewport_write(&file->viewport, io);
00768 {
00769 int i;
00770 for (i = 0; i < file->nmaterials; ++i) {
00771 lib3ds_material_write(file->materials[i], io);
00772 }
00773 }
00774 {
00775 Lib3dsChunk c;
00776 int i;
00777
00778 for (i = 0; i < file->ncameras; ++i) {
00779 c.chunk = CHK_NAMED_OBJECT;
00780 lib3ds_chunk_write_start(&c, io);
00781 lib3ds_io_write_string(io, file->cameras[i]->name);
00782 lib3ds_camera_write(file->cameras[i], io);
00783 object_flags_write(file->cameras[i]->object_flags, io);
00784 lib3ds_chunk_write_end(&c, io);
00785 }
00786 }
00787 {
00788 Lib3dsChunk c;
00789 int i;
00790
00791 for (i = 0; i < file->nlights; ++i) {
00792 c.chunk = CHK_NAMED_OBJECT;
00793 lib3ds_chunk_write_start(&c, io);
00794 lib3ds_io_write_string(io, file->lights[i]->name);
00795 lib3ds_light_write(file->lights[i], io);
00796 object_flags_write(file->lights[i]->object_flags, io);
00797 lib3ds_chunk_write_end(&c, io);
00798 }
00799 }
00800 {
00801 Lib3dsChunk c;
00802 int i;
00803
00804 for (i = 0; i < file->nmeshes; ++i) {
00805 c.chunk = CHK_NAMED_OBJECT;
00806 lib3ds_chunk_write_start(&c, io);
00807 lib3ds_io_write_string(io, file->meshes[i]->name);
00808 lib3ds_mesh_write(file, file->meshes[i], io);
00809 object_flags_write(file->meshes[i]->object_flags, io);
00810 lib3ds_chunk_write_end(&c, io);
00811 }
00812 }
00813
00814 lib3ds_chunk_write_end(&c, io);
00815 }
00816
00817
00818
00819 static void
00820 nodes_write(Lib3dsNode *first_node, uint16_t *default_id, uint16_t parent_id, Lib3dsIo *io) {
00821 Lib3dsNode *p;
00822 for (p = first_node; p != NULL; p = p->next) {
00823 uint16_t node_id;
00824 if ((p->type == LIB3DS_NODE_AMBIENT_COLOR) || (p->node_id != 65535)) {
00825 node_id = p->node_id;
00826 } else {
00827 node_id = *default_id;
00828 }
00829 ++(*default_id);
00830 lib3ds_node_write(p, node_id, parent_id, io);
00831
00832 nodes_write(p->childs, default_id, node_id, io);
00833 }
00834 }
00835
00836
00837 static void
00838 kfdata_write(Lib3dsFile *file, Lib3dsIo *io) {
00839 Lib3dsChunk c;
00840
00841 if (!file->nodes) {
00842 return;
00843 }
00844
00845 c.chunk = CHK_KFDATA;
00846 lib3ds_chunk_write_start(&c, io);
00847
00848 {
00849 Lib3dsChunk c;
00850 c.chunk = CHK_KFHDR;
00851 c.size = 6 + 2 + (uint32_t)strlen(file->name) + 1 + 4;
00852 lib3ds_chunk_write(&c, io);
00853 lib3ds_io_write_intw(io, file->keyf_revision);
00854 lib3ds_io_write_string(io, file->name);
00855 lib3ds_io_write_intd(io, file->frames);
00856 }
00857 {
00858 Lib3dsChunk c;
00859 c.chunk = CHK_KFSEG;
00860 c.size = 14;
00861 lib3ds_chunk_write(&c, io);
00862 lib3ds_io_write_intd(io, file->segment_from);
00863 lib3ds_io_write_intd(io, file->segment_to);
00864 }
00865 {
00866 Lib3dsChunk c;
00867 c.chunk = CHK_KFCURTIME;
00868 c.size = 10;
00869 lib3ds_chunk_write(&c, io);
00870 lib3ds_io_write_intd(io, file->current_frame);
00871 }
00872 lib3ds_viewport_write(&file->viewport_keyf, io);
00873
00874 {
00875 uint16_t default_id = 0;
00876 nodes_write(file->nodes, &default_id, 65535, io);
00877 }
00878
00879 lib3ds_chunk_write_end(&c, io);
00880 }
00881
00882
00891 int
00892 lib3ds_file_write(Lib3dsFile *file, Lib3dsIo *io) {
00893 Lib3dsChunk c;
00894 Lib3dsIoImpl *impl;
00895
00896 lib3ds_io_setup(io);
00897 impl = (Lib3dsIoImpl*)io->impl;
00898
00899 if (setjmp(impl->jmpbuf) != 0) {
00900 lib3ds_io_cleanup(io);
00901 return FALSE;
00902 }
00903
00904 c.chunk = CHK_M3DMAGIC;
00905 lib3ds_chunk_write_start(&c, io);
00906
00907 {
00908 Lib3dsChunk c;
00909
00910 c.chunk = CHK_M3D_VERSION;
00911 c.size = 10;
00912 lib3ds_chunk_write(&c, io);
00913 lib3ds_io_write_dword(io, file->mesh_version);
00914 }
00915
00916 mdata_write(file, io);
00917 kfdata_write(file, io);
00918
00919 lib3ds_chunk_write_end(&c, io);
00920
00921 memset(impl->jmpbuf, 0, sizeof(impl->jmpbuf));
00922 lib3ds_io_cleanup(io);
00923 return TRUE;
00924 }
00925
00926
00927 void lib3ds_file_reserve_materials(Lib3dsFile *file, int size, int force) {
00928 assert(file);
00929 lib3ds_util_reserve_array((void***)&file->materials, &file->nmaterials, &file->materials_size,
00930 size, force, (Lib3dsFreeFunc)lib3ds_material_free);
00931 }
00932
00933
00934 void
00935 lib3ds_file_insert_material(Lib3dsFile *file, Lib3dsMaterial *material, int index) {
00936 assert(file);
00937 lib3ds_util_insert_array((void***)&file->materials, &file->nmaterials, &file->materials_size, material, index);
00938 }
00939
00940
00941 void
00942 lib3ds_file_remove_material(Lib3dsFile *file, int index) {
00943 assert(file);
00944 lib3ds_util_remove_array((void***)&file->materials, &file->nmaterials, index, (Lib3dsFreeFunc)lib3ds_material_free);
00945 }
00946
00947
00948 int
00949 lib3ds_file_material_by_name(Lib3dsFile *file, const char *name) {
00950 int i;
00951
00952 assert(file);
00953 for (i = 0; i < file->nmaterials; ++i) {
00954 if (strcmp(file->materials[i]->name, name) == 0) {
00955 return(i);
00956 }
00957 }
00958 return -1;
00959 }
00960
00961
00962 void
00963 lib3ds_file_reserve_cameras(Lib3dsFile *file, int size, int force) {
00964 assert(file);
00965 lib3ds_util_reserve_array((void***)&file->cameras, &file->ncameras, &file->cameras_size,
00966 size, force, (Lib3dsFreeFunc)lib3ds_camera_free);
00967 }
00968
00969
00970 void
00971 lib3ds_file_insert_camera(Lib3dsFile *file, Lib3dsCamera *camera, int index) {
00972 assert(file);
00973 lib3ds_util_insert_array((void***)&file->cameras, &file->ncameras, &file->cameras_size, camera, index);
00974 }
00975
00976
00977 void
00978 lib3ds_file_remove_camera(Lib3dsFile *file, int index) {
00979 assert(file);
00980 lib3ds_util_remove_array((void***)&file->cameras, &file->ncameras, index, (Lib3dsFreeFunc)lib3ds_camera_free);
00981 }
00982
00983
00984 int
00985 lib3ds_file_camera_by_name(Lib3dsFile *file, const char *name) {
00986 int i;
00987
00988 assert(file);
00989 for (i = 0; i < file->ncameras; ++i) {
00990 if (strcmp(file->cameras[i]->name, name) == 0) {
00991 return(i);
00992 }
00993 }
00994 return -1;
00995 }
00996
00997
00998 void
00999 lib3ds_file_reserve_lights(Lib3dsFile *file, int size, int force) {
01000 assert(file);
01001 lib3ds_util_reserve_array((void***)&file->lights, &file->nlights, &file->lights_size,
01002 size, force, (Lib3dsFreeFunc)lib3ds_light_free);
01003 }
01004
01005
01006 void
01007 lib3ds_file_insert_light(Lib3dsFile *file, Lib3dsLight *light, int index) {
01008 assert(file);
01009 lib3ds_util_insert_array((void***)&file->lights, &file->nlights, &file->lights_size, light, index);
01010 }
01011
01012
01013 void
01014 lib3ds_file_remove_light(Lib3dsFile *file, int index) {
01015 assert(file);
01016 lib3ds_util_remove_array((void***)&file->lights, &file->nlights, index, (Lib3dsFreeFunc)lib3ds_light_free);
01017 }
01018
01019
01020 int
01021 lib3ds_file_light_by_name(Lib3dsFile *file, const char *name) {
01022 int i;
01023
01024 assert(file);
01025 for (i = 0; i < file->nlights; ++i) {
01026 if (strcmp(file->lights[i]->name, name) == 0) {
01027 return(i);
01028 }
01029 }
01030 return -1;
01031 }
01032
01033
01034 void
01035 lib3ds_file_reserve_meshes(Lib3dsFile *file, int size, int force) {
01036 assert(file);
01037 lib3ds_util_reserve_array((void***)&file->meshes, &file->nmeshes, &file->meshes_size,
01038 size, force, (Lib3dsFreeFunc)lib3ds_mesh_free);
01039 }
01040
01041
01042 void
01043 lib3ds_file_insert_mesh(Lib3dsFile *file, Lib3dsMesh *mesh, int index) {
01044 assert(file);
01045 lib3ds_util_insert_array((void***)&file->meshes, &file->nmeshes, &file->meshes_size, mesh, index);
01046 }
01047
01048
01049 void
01050 lib3ds_file_remove_mesh(Lib3dsFile *file, int index) {
01051 assert(file);
01052 lib3ds_util_remove_array((void***)&file->meshes, &file->nmeshes, index, (Lib3dsFreeFunc)lib3ds_mesh_free);
01053 }
01054
01055
01056 int
01057 lib3ds_file_mesh_by_name(Lib3dsFile *file, const char *name) {
01058 int i;
01059
01060 assert(file);
01061 for (i = 0; i < file->nmeshes; ++i) {
01062 if (strcmp(file->meshes[i]->name, name) == 0) {
01063 return(i);
01064 }
01065 }
01066 return -1;
01067 }
01068
01069
01070 Lib3dsMesh*
01071 lib3ds_file_mesh_for_node(Lib3dsFile *file, Lib3dsNode *node) {
01072 int index;
01073 Lib3dsMeshInstanceNode *n;
01074
01075 if (node->type != LIB3DS_NODE_MESH_INSTANCE)
01076 return NULL;
01077 n = (Lib3dsMeshInstanceNode*)node;
01078
01079 index = lib3ds_file_mesh_by_name(file, node->name);
01080
01081 return (index >= 0)? file->meshes[index] : NULL;
01082 }
01083
01084
01099 Lib3dsNode*
01100 lib3ds_file_node_by_name(Lib3dsFile *file, const char* name, Lib3dsNodeType type) {
01101 Lib3dsNode *p, *q;
01102
01103 assert(file);
01104 for (p = file->nodes; p != 0; p = p->next) {
01105 if ((p->type == type) && (strcmp(p->name, name) == 0)) {
01106 return(p);
01107 }
01108 q = lib3ds_node_by_name(p, name, type);
01109 if (q) {
01110 return(q);
01111 }
01112 }
01113 return(0);
01114 }
01115
01116
01129 Lib3dsNode*
01130 lib3ds_file_node_by_id(Lib3dsFile *file, uint16_t node_id) {
01131 Lib3dsNode *p, *q;
01132
01133 assert(file);
01134 for (p = file->nodes; p != 0; p = p->next) {
01135 if (p->node_id == node_id) {
01136 return(p);
01137 }
01138 q = lib3ds_node_by_id(p, node_id);
01139 if (q) {
01140 return(q);
01141 }
01142 }
01143 return(0);
01144 }
01145
01146
01147 void
01148 lib3ds_file_append_node(Lib3dsFile *file, Lib3dsNode *node, Lib3dsNode *parent) {
01149 Lib3dsNode *p;
01150
01151 assert(file);
01152 assert(node);
01153 p = parent? parent->childs : file->nodes;
01154 if (p) {
01155 while (p->next) {
01156 p = p->next;
01157 }
01158 p->next = node;
01159 } else {
01160 if (parent) {
01161 parent->childs = node;
01162 } else {
01163 file->nodes = node;
01164 }
01165 }
01166 node->parent = parent;
01167 node->next = NULL;
01168 }
01169
01170
01171 void
01172 lib3ds_file_insert_node(Lib3dsFile *file, Lib3dsNode *node, Lib3dsNode *before) {
01173 Lib3dsNode *p, *q;
01174
01175 assert(node);
01176 assert(file);
01177
01178 if (before) {
01179 p = before->parent? before->parent->childs : file->nodes;
01180 assert(p);
01181 q = NULL;
01182 while (p != before) {
01183 q = p;
01184 p = p->next;
01185 }
01186 if (q) {
01187 node->next = q->next;
01188 q->next = node;
01189 } else {
01190 node->next = file->nodes;
01191 file->nodes = node;
01192 }
01193 node->parent = before->parent;
01194 } else {
01195 node->next = file->nodes;
01196 node->parent = NULL;
01197 file->nodes = node;
01198 }
01199 }
01200
01201
01210 void
01211 lib3ds_file_remove_node(Lib3dsFile *file, Lib3dsNode *node) {
01212 Lib3dsNode *p, *n;
01213
01214 if (node->parent) {
01215 for (p = 0, n = node->parent->childs; n; p = n, n = n->next) {
01216 if (n == node) {
01217 break;
01218 }
01219 }
01220 if (!n) {
01221 return;
01222 }
01223
01224 if (!p) {
01225 node->parent->childs = n->next;
01226 } else {
01227 p->next = n->next;
01228 }
01229 } else {
01230 for (p = 0, n = file->nodes; n; p = n, n = n->next) {
01231 if (n == node) {
01232 break;
01233 }
01234 }
01235 if (!n) {
01236 return;
01237 }
01238
01239 if (!p) {
01240 file->nodes = n->next;
01241 } else {
01242 p->next = n->next;
01243 }
01244 }
01245 }
01246
01247
01248 static void
01249 file_minmax_node_id_impl(Lib3dsFile *file, Lib3dsNode *node, uint16_t *min_id, uint16_t *max_id) {
01250 Lib3dsNode *p;
01251
01252 if (min_id && (*min_id > node->node_id))
01253 *min_id = node->node_id;
01254 if (max_id && (*max_id < node->node_id))
01255 *max_id = node->node_id;
01256
01257 p = node->childs;
01258 while (p) {
01259 file_minmax_node_id_impl(file, p, min_id, max_id);
01260 p = p->next;
01261 }
01262 }
01263
01264
01265 void
01266 lib3ds_file_minmax_node_id(Lib3dsFile *file, uint16_t *min_id, uint16_t *max_id) {
01267 Lib3dsNode *p;
01268
01269 if (min_id)
01270 *min_id = 65535;
01271 if (max_id)
01272 *max_id = 0;
01273
01274 p = file->nodes;
01275 while (p) {
01276 file_minmax_node_id_impl(file, p, min_id, max_id);
01277 p = p->next;
01278 }
01279 }
01280
01281
01282 void
01283 lib3ds_file_bounding_box_of_objects(Lib3dsFile *file, int
01284 include_meshes, int include_cameras, int include_lights,
01285 float bmin[3], float bmax[3]) {
01286 bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
01287 bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
01288
01289 if (include_meshes) {
01290 float lmin[3], lmax[3];
01291 int i;
01292 for (i = 0; i < file->nmeshes; ++i) {
01293 lib3ds_mesh_bounding_box(file->meshes[i], lmin, lmax);
01294 lib3ds_vector_min(bmin, lmin);
01295 lib3ds_vector_max(bmax, lmax);
01296 }
01297 }
01298 if (include_cameras) {
01299 int i;
01300 for (i = 0; i < file->ncameras; ++i) {
01301 lib3ds_vector_min(bmin, file->cameras[i]->position);
01302 lib3ds_vector_max(bmax, file->cameras[i]->position);
01303 lib3ds_vector_min(bmin, file->cameras[i]->target);
01304 lib3ds_vector_max(bmax, file->cameras[i]->target);
01305 }
01306 }
01307 if (include_lights) {
01308 int i;
01309 for (i = 0; i < file->ncameras; ++i) {
01310 lib3ds_vector_min(bmin, file->lights[i]->position);
01311 lib3ds_vector_max(bmax, file->lights[i]->position);
01312 if (file->lights[i]->spot_light) {
01313 lib3ds_vector_min(bmin, file->lights[i]->target);
01314 lib3ds_vector_max(bmax, file->lights[i]->target);
01315 }
01316 }
01317 }
01318 }
01319
01320
01321 static void
01322 file_bounding_box_of_nodes_impl(Lib3dsNode *node, Lib3dsFile *file,
01323 int include_meshes, int include_cameras, int include_lights,
01324 float bmin[3], float bmax[3], float matrix[4][4]) {
01325 switch (node->type) {
01326 case LIB3DS_NODE_MESH_INSTANCE:
01327 if (include_meshes) {
01328 int index;
01329 Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
01330
01331 index = lib3ds_file_mesh_by_name(file, n->instance_name);
01332 if (index < 0)
01333 index = lib3ds_file_mesh_by_name(file, node->name);
01334 if (index >= 0) {
01335 Lib3dsMesh *mesh;
01336 float inv_matrix[4][4], M[4][4];
01337 float v[3];
01338 int i;
01339
01340 mesh = file->meshes[index];
01341 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
01342 lib3ds_matrix_inv(inv_matrix);
01343 lib3ds_matrix_mult(M, matrix, node->matrix);
01344 lib3ds_matrix_translate(M, -n->pivot[0], -n->pivot[1], -n->pivot[2]);
01345 lib3ds_matrix_mult(M, M, inv_matrix);
01346
01347 for (i = 0; i < mesh->nvertices; ++i) {
01348 lib3ds_vector_transform(v, M, mesh->vertices[i]);
01349 lib3ds_vector_min(bmin, v);
01350 lib3ds_vector_max(bmax, v);
01351 }
01352 }
01353 }
01354 break;
01355
01356 case LIB3DS_NODE_CAMERA:
01357 case LIB3DS_NODE_CAMERA_TARGET:
01358 if (include_cameras) {
01359 float z[3], v[3];
01360 float M[4][4];
01361 lib3ds_matrix_mult(M, matrix, node->matrix);
01362 lib3ds_vector_zero(z);
01363 lib3ds_vector_transform(v, M, z);
01364 lib3ds_vector_min(bmin, v);
01365 lib3ds_vector_max(bmax, v);
01366 }
01367 break;
01368
01369 case LIB3DS_NODE_OMNILIGHT:
01370 case LIB3DS_NODE_SPOTLIGHT:
01371 case LIB3DS_NODE_SPOTLIGHT_TARGET:
01372 if (include_lights) {
01373 float z[3], v[3];
01374 float M[4][4];
01375 lib3ds_matrix_mult(M, matrix, node->matrix);
01376 lib3ds_vector_zero(z);
01377 lib3ds_vector_transform(v, M, z);
01378 lib3ds_vector_min(bmin, v);
01379 lib3ds_vector_max(bmax, v);
01380 }
01381 break;
01382 }
01383 {
01384 Lib3dsNode *p = node->childs;
01385 while (p) {
01386 file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax, matrix);
01387 p = p->next;
01388 }
01389 }
01390 }
01391
01392
01393 void
01394 lib3ds_file_bounding_box_of_nodes(Lib3dsFile *file,
01395 int include_meshes, int include_cameras,int include_lights,
01396 float bmin[3], float bmax[3], float matrix[4][4]) {
01397 Lib3dsNode *p;
01398 float M[4][4];
01399
01400 if (matrix) {
01401 lib3ds_matrix_copy(M, matrix);
01402 } else {
01403 lib3ds_matrix_identity(M);
01404 }
01405
01406 bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
01407 bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
01408 p = file->nodes;
01409 while (p) {
01410 file_bounding_box_of_nodes_impl(p, file, include_meshes, include_cameras, include_lights, bmin, bmax, M);
01411 p = p->next;
01412 }
01413 }
01414
01415
01416 void
01417 lib3ds_file_create_nodes_for_meshes(Lib3dsFile *file) {
01418 Lib3dsNode *p;
01419 int i;
01420 for (i = 0; i < file->nmeshes; ++i) {
01421 Lib3dsMesh *mesh = file->meshes[i];
01422 p = lib3ds_node_new(LIB3DS_NODE_MESH_INSTANCE);
01423 strcpy(p->name, mesh->name);
01424 lib3ds_file_insert_node(file, p, NULL);
01425 }
01426 }