00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "lib3ds_impl.h"
00019
00020
00033 Lib3dsMesh*
00034 lib3ds_mesh_new(const char *name) {
00035 Lib3dsMesh *mesh;
00036
00037 assert(name);
00038 assert(strlen(name) < 64);
00039
00040 mesh = (Lib3dsMesh*) calloc(sizeof(Lib3dsMesh), 1);
00041 if (!mesh) {
00042 return (0);
00043 }
00044 strcpy(mesh->name, name);
00045 lib3ds_matrix_identity(mesh->matrix);
00046 mesh->map_type = LIB3DS_MAP_NONE;
00047 return (mesh);
00048 }
00049
00050
00056 void
00057 lib3ds_mesh_free(Lib3dsMesh *mesh) {
00058 lib3ds_mesh_resize_vertices(mesh, 0, 0, 0);
00059 lib3ds_mesh_resize_faces(mesh, 0);
00060 memset(mesh, 0, sizeof(Lib3dsMesh));
00061 free(mesh);
00062 }
00063
00064
00065 void
00066 lib3ds_mesh_resize_vertices(Lib3dsMesh *mesh, int nvertices, int use_texcos, int use_flags) {
00067 assert(mesh);
00068 mesh->vertices = lib3ds_util_realloc_array(mesh->vertices, mesh->nvertices, nvertices, 3 * sizeof(float));
00069 mesh->texcos = lib3ds_util_realloc_array(
00070 mesh->texcos,
00071 mesh->texcos? mesh->nvertices : 0,
00072 use_texcos? nvertices : 0,
00073 2 * sizeof(float)
00074 );
00075 mesh->vflags = lib3ds_util_realloc_array(
00076 mesh->vflags,
00077 mesh->vflags? mesh->nvertices : 0,
00078 use_flags? nvertices : 0,
00079 2 * sizeof(float)
00080 );
00081 mesh->nvertices = nvertices;
00082 }
00083
00084
00085 void
00086 lib3ds_mesh_resize_faces(Lib3dsMesh *mesh, int nfaces) {
00087 int i;
00088 assert(mesh);
00089 mesh->faces = lib3ds_util_realloc_array(mesh->faces, mesh->nfaces, nfaces, sizeof(Lib3dsFace));
00090 for (i = mesh->nfaces; i < nfaces; ++i) {
00091 mesh->faces[i].material = -1;
00092 }
00093 mesh->nfaces = nfaces;
00094 }
00095
00096
00104 void
00105 lib3ds_mesh_bounding_box(Lib3dsMesh *mesh, float bmin[3], float bmax[3]) {
00106 int i;
00107 bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
00108 bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
00109
00110 for (i = 0; i < mesh->nvertices; ++i) {
00111 lib3ds_vector_min(bmin, mesh->vertices[i]);
00112 lib3ds_vector_max(bmax, mesh->vertices[i]);
00113 }
00114 }
00115
00116
00117 void
00118 lib3ds_mesh_calculate_face_normals(Lib3dsMesh *mesh, float (*face_normals)[3]) {
00119 int i;
00120
00121 if (!mesh->nfaces) {
00122 return;
00123 }
00124 for (i = 0; i < mesh->nfaces; ++i) {
00125 lib3ds_vector_normal(
00126 face_normals[i],
00127 mesh->vertices[mesh->faces[i].index[0]],
00128 mesh->vertices[mesh->faces[i].index[1]],
00129 mesh->vertices[mesh->faces[i].index[2]]
00130 );
00131 }
00132 }
00133
00134
00135 typedef struct Lib3dsFaces {
00136 struct Lib3dsFaces *next;
00137 int index;
00138 float normal[3];
00139 } Lib3dsFaces;
00140
00141
00162 void
00163 lib3ds_mesh_calculate_vertex_normals(Lib3dsMesh *mesh, float (*normals)[3]) {
00164 Lib3dsFaces **fl;
00165 Lib3dsFaces *fa;
00166 int i, j;
00167
00168 if (!mesh->nfaces) {
00169 return;
00170 }
00171
00172 fl = calloc(sizeof(Lib3dsFaces*), mesh->nvertices);
00173 fa = malloc(sizeof(Lib3dsFaces) * 3 * mesh->nfaces);
00174
00175 for (i = 0; i < mesh->nfaces; ++i) {
00176 for (j = 0; j < 3; ++j) {
00177 Lib3dsFaces* l = &fa[3*i+j];
00178 float p[3], q[3], n[3];
00179 float len, weight;
00180
00181 l->index = i;
00182 l->next = fl[mesh->faces[i].index[j]];
00183 fl[mesh->faces[i].index[j]] = l;
00184
00185 lib3ds_vector_sub(p, mesh->vertices[mesh->faces[i].index[j<2? j + 1 : 0]], mesh->vertices[mesh->faces[i].index[j]]);
00186 lib3ds_vector_sub(q, mesh->vertices[mesh->faces[i].index[j>0? j - 1 : 2]], mesh->vertices[mesh->faces[i].index[j]]);
00187 lib3ds_vector_cross(n, p, q);
00188 len = lib3ds_vector_length(n);
00189 if (len > 0) {
00190 weight = (float)atan2(len, lib3ds_vector_dot(p, q));
00191 lib3ds_vector_scalar_mul(l->normal, n, weight / len);
00192 } else {
00193 lib3ds_vector_zero(l->normal);
00194 }
00195 }
00196 }
00197
00198 for (i = 0; i < mesh->nfaces; ++i) {
00199 Lib3dsFace *f = &mesh->faces[i];
00200 for (j = 0; j < 3; ++j) {
00201 float n[3];
00202 Lib3dsFaces *p;
00203 Lib3dsFace *pf;
00204
00205 assert(mesh->faces[i].index[j] < mesh->nvertices);
00206
00207 if (f->smoothing_group) {
00208 unsigned smoothing_group = f->smoothing_group;
00209
00210 lib3ds_vector_zero(n);
00211 for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
00212 pf = &mesh->faces[p->index];
00213 if (pf->smoothing_group & f->smoothing_group)
00214 smoothing_group |= pf->smoothing_group;
00215 }
00216
00217 for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
00218 pf = &mesh->faces[p->index];
00219 if (smoothing_group & pf->smoothing_group) {
00220 lib3ds_vector_add(n, n, p->normal);
00221 }
00222 }
00223 } else {
00224 lib3ds_vector_copy(n, fa[3*i+j].normal);
00225 }
00226
00227 lib3ds_vector_normalize(n);
00228 lib3ds_vector_copy(normals[3*i+j], n);
00229 }
00230 }
00231
00232 free(fa);
00233 free(fl);
00234 }
00235
00236
00237 static void
00238 face_array_read(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
00239 Lib3dsChunk c;
00240 uint16_t chunk;
00241 int i;
00242 uint16_t nfaces;
00243
00244 lib3ds_chunk_read_start(&c, CHK_FACE_ARRAY, io);
00245
00246 lib3ds_mesh_resize_faces(mesh, 0);
00247 nfaces = lib3ds_io_read_word(io);
00248 if (nfaces) {
00249 lib3ds_mesh_resize_faces(mesh, nfaces);
00250 for (i = 0; i < nfaces; ++i) {
00251 mesh->faces[i].index[0] = lib3ds_io_read_word(io);
00252 mesh->faces[i].index[1] = lib3ds_io_read_word(io);
00253 mesh->faces[i].index[2] = lib3ds_io_read_word(io);
00254 mesh->faces[i].flags = lib3ds_io_read_word(io);
00255 }
00256 lib3ds_chunk_read_tell(&c, io);
00257
00258 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
00259 switch (chunk) {
00260 case CHK_MSH_MAT_GROUP: {
00261 char name[64];
00262 unsigned n;
00263 unsigned i;
00264 int index;
00265 int material;
00266
00267 lib3ds_io_read_string(io, name, 64);
00268 material = lib3ds_file_material_by_name(file, name);
00269
00270 n = lib3ds_io_read_word(io);
00271 for (i = 0; i < n; ++i) {
00272 index = lib3ds_io_read_word(io);
00273 if (index < mesh->nfaces) {
00274 mesh->faces[index].material = material;
00275 } else {
00276
00277 }
00278 }
00279 break;
00280 }
00281
00282 case CHK_SMOOTH_GROUP: {
00283 int i;
00284 for (i = 0; i < mesh->nfaces; ++i) {
00285 mesh->faces[i].smoothing_group = lib3ds_io_read_dword(io);
00286 }
00287 break;
00288 }
00289
00290 case CHK_MSH_BOXMAP: {
00291 lib3ds_io_read_string(io, mesh->box_front, 64);
00292 lib3ds_io_read_string(io, mesh->box_back, 64);
00293 lib3ds_io_read_string(io, mesh->box_left, 64);
00294 lib3ds_io_read_string(io, mesh->box_right, 64);
00295 lib3ds_io_read_string(io, mesh->box_top, 64);
00296 lib3ds_io_read_string(io, mesh->box_bottom, 64);
00297 break;
00298 }
00299
00300 default:
00301 lib3ds_chunk_unknown(chunk,io);
00302 }
00303 }
00304
00305 }
00306 lib3ds_chunk_read_end(&c, io);
00307 }
00308
00309
00310 void
00311 lib3ds_mesh_read(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
00312 Lib3dsChunk c;
00313 uint16_t chunk;
00314
00315 lib3ds_chunk_read_start(&c, CHK_N_TRI_OBJECT, io);
00316
00317 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
00318 switch (chunk) {
00319 case CHK_MESH_MATRIX: {
00320 int i, j;
00321
00322 lib3ds_matrix_identity(mesh->matrix);
00323 for (i = 0; i < 4; i++) {
00324 for (j = 0; j < 3; j++) {
00325 mesh->matrix[i][j] = lib3ds_io_read_float(io);
00326 }
00327 }
00328 break;
00329 }
00330
00331 case CHK_MESH_COLOR: {
00332 mesh->color = lib3ds_io_read_byte(io);
00333 break;
00334 }
00335
00336 case CHK_POINT_ARRAY: {
00337 int i;
00338 uint16_t nvertices = lib3ds_io_read_word(io);
00339 lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, mesh->vflags != NULL);
00340 for (i = 0; i < mesh->nvertices; ++i) {
00341 lib3ds_io_read_vector(io, mesh->vertices[i]);
00342 }
00343 break;
00344 }
00345
00346 case CHK_POINT_FLAG_ARRAY: {
00347 int i;
00348 uint16_t nflags = lib3ds_io_read_word(io);
00349 uint16_t nvertices = (mesh->nvertices >= nflags)? mesh->nvertices : nflags;
00350 lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, 1);
00351 for (i = 0; i < nflags; ++i) {
00352 mesh->vflags[i] = lib3ds_io_read_word(io);
00353 }
00354 break;
00355 }
00356
00357 case CHK_FACE_ARRAY: {
00358 lib3ds_chunk_read_reset(&c, io);
00359 face_array_read(file, mesh, io);
00360 break;
00361 }
00362
00363 case CHK_MESH_TEXTURE_INFO: {
00364 int i, j;
00365
00366
00367
00368 for (i = 0; i < 2; ++i) {
00369 mesh->map_tile[i] = lib3ds_io_read_float(io);
00370 }
00371 for (i = 0; i < 3; ++i) {
00372 mesh->map_pos[i] = lib3ds_io_read_float(io);
00373 }
00374 mesh->map_scale = lib3ds_io_read_float(io);
00375
00376 lib3ds_matrix_identity(mesh->map_matrix);
00377 for (i = 0; i < 4; i++) {
00378 for (j = 0; j < 3; j++) {
00379 mesh->map_matrix[i][j] = lib3ds_io_read_float(io);
00380 }
00381 }
00382 for (i = 0; i < 2; ++i) {
00383 mesh->map_planar_size[i] = lib3ds_io_read_float(io);
00384 }
00385 mesh->map_cylinder_height = lib3ds_io_read_float(io);
00386 break;
00387 }
00388
00389 case CHK_TEX_VERTS: {
00390 int i;
00391 uint16_t ntexcos = lib3ds_io_read_word(io);
00392 uint16_t nvertices = (mesh->nvertices >= ntexcos)? mesh->nvertices : ntexcos;;
00393 if (!mesh->texcos) {
00394 lib3ds_mesh_resize_vertices(mesh, nvertices, 1, mesh->vflags != NULL);
00395 }
00396 for (i = 0; i < ntexcos; ++i) {
00397 mesh->texcos[i][0] = lib3ds_io_read_float(io);
00398 mesh->texcos[i][1] = lib3ds_io_read_float(io);
00399 }
00400 break;
00401 }
00402
00403 default:
00404 lib3ds_chunk_unknown(chunk, io);
00405 }
00406 }
00407
00408 if (lib3ds_matrix_det(mesh->matrix) < 0.0) {
00409
00410
00411 float inv_matrix[4][4], M[4][4];
00412 float tmp[3];
00413 int i;
00414
00415 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
00416 lib3ds_matrix_inv(inv_matrix);
00417
00418 lib3ds_matrix_copy(M, mesh->matrix);
00419 lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f);
00420 lib3ds_matrix_mult(M, M, inv_matrix);
00421
00422 for (i = 0; i < mesh->nvertices; ++i) {
00423 lib3ds_vector_transform(tmp, M, mesh->vertices[i]);
00424 lib3ds_vector_copy(mesh->vertices[i], tmp);
00425 }
00426 }
00427
00428 lib3ds_chunk_read_end(&c, io);
00429 }
00430
00431
00432 static void
00433 point_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
00434 Lib3dsChunk c;
00435 int i;
00436
00437 c.chunk = CHK_POINT_ARRAY;
00438 c.size = 8 + 12 * mesh->nvertices;
00439 lib3ds_chunk_write(&c, io);
00440
00441 lib3ds_io_write_word(io, (uint16_t) mesh->nvertices);
00442
00443 if (lib3ds_matrix_det(mesh->matrix) >= 0.0f) {
00444 for (i = 0; i < mesh->nvertices; ++i) {
00445 lib3ds_io_write_vector(io, mesh->vertices[i]);
00446 }
00447 } else {
00448
00449
00450 float inv_matrix[4][4], M[4][4];
00451 float tmp[3];
00452
00453 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
00454 lib3ds_matrix_inv(inv_matrix);
00455 lib3ds_matrix_copy(M, mesh->matrix);
00456 lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f);
00457 lib3ds_matrix_mult(M, M, inv_matrix);
00458
00459 for (i = 0; i < mesh->nvertices; ++i) {
00460 lib3ds_vector_transform(tmp, M, mesh->vertices[i]);
00461 lib3ds_io_write_vector(io, tmp);
00462 }
00463 }
00464 }
00465
00466
00467 static void
00468 flag_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
00469 Lib3dsChunk c;
00470 int i;
00471
00472 if (!mesh->vflags) {
00473 return;
00474 }
00475
00476 c.chunk = CHK_POINT_FLAG_ARRAY;
00477 c.size = 8 + 2 * mesh->nvertices;
00478 lib3ds_chunk_write(&c, io);
00479
00480 lib3ds_io_write_word(io, (uint16_t) mesh->nvertices);
00481 for (i = 0; i < mesh->nvertices; ++i) {
00482 lib3ds_io_write_word(io, mesh->vflags[i]);
00483 }
00484 }
00485
00486
00487 static void
00488 face_array_write(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
00489 Lib3dsChunk c;
00490
00491 if (mesh->nfaces == 0) {
00492 return;
00493 }
00494 c.chunk = CHK_FACE_ARRAY;
00495 lib3ds_chunk_write_start(&c, io);
00496
00497 {
00498 int i;
00499
00500 lib3ds_io_write_word(io, (uint16_t) mesh->nfaces);
00501 for (i = 0; i < mesh->nfaces; ++i) {
00502 lib3ds_io_write_word(io, mesh->faces[i].index[0]);
00503 lib3ds_io_write_word(io, mesh->faces[i].index[1]);
00504 lib3ds_io_write_word(io, mesh->faces[i].index[2]);
00505 lib3ds_io_write_word(io, mesh->faces[i].flags);
00506 }
00507 }
00508
00509 {
00510
00511 Lib3dsChunk c;
00512 int i, j;
00513 uint16_t num;
00514 char *matf = ((Lib3dsIoImpl*)io->impl)->tmp_mem = calloc(sizeof(char), mesh->nfaces);
00515 assert(matf);
00516
00517 for (i = 0; i < mesh->nfaces; ++i) {
00518 if (!matf[i] && (mesh->faces[i].material >= 0) && (mesh->faces[i].material < file->nmaterials)) {
00519 matf[i] = 1;
00520 num = 1;
00521
00522 for (j = i + 1; j < mesh->nfaces; ++j) {
00523 if (mesh->faces[i].material == mesh->faces[j].material) ++num;
00524 }
00525
00526 c.chunk = CHK_MSH_MAT_GROUP;
00527 c.size = 6 + (uint32_t)strlen(file->materials[mesh->faces[i].material]->name) + 1 + 2 + 2 * num;
00528 lib3ds_chunk_write(&c, io);
00529 lib3ds_io_write_string(io, file->materials[mesh->faces[i].material]->name);
00530 lib3ds_io_write_word(io, num);
00531 lib3ds_io_write_word(io, (uint16_t) i);
00532
00533 for (j = i + 1; j < mesh->nfaces; ++j) {
00534 if (mesh->faces[i].material == mesh->faces[j].material) {
00535 lib3ds_io_write_word(io, (uint16_t) j);
00536 matf[j] = 1;
00537 }
00538 }
00539 }
00540 }
00541 ((Lib3dsIoImpl*)io->impl)->tmp_mem = NULL;
00542 free(matf);
00543 }
00544
00545 {
00546
00547 Lib3dsChunk c;
00548 int i;
00549
00550 c.chunk = CHK_SMOOTH_GROUP;
00551 c.size = 6 + 4 * mesh->nfaces;
00552 lib3ds_chunk_write(&c, io);
00553
00554 for (i = 0; i < mesh->nfaces; ++i) {
00555 lib3ds_io_write_dword(io, mesh->faces[i].smoothing_group);
00556 }
00557 }
00558
00559 {
00560
00561 Lib3dsChunk c;
00562
00563 if (strlen(mesh->box_front) ||
00564 strlen(mesh->box_back) ||
00565 strlen(mesh->box_left) ||
00566 strlen(mesh->box_right) ||
00567 strlen(mesh->box_top) ||
00568 strlen(mesh->box_bottom)) {
00569
00570 c.chunk = CHK_MSH_BOXMAP;
00571 lib3ds_chunk_write_start(&c, io);
00572
00573 lib3ds_io_write_string(io, mesh->box_front);
00574 lib3ds_io_write_string(io, mesh->box_back);
00575 lib3ds_io_write_string(io, mesh->box_left);
00576 lib3ds_io_write_string(io, mesh->box_right);
00577 lib3ds_io_write_string(io, mesh->box_top);
00578 lib3ds_io_write_string(io, mesh->box_bottom);
00579
00580 lib3ds_chunk_write_end(&c, io);
00581 }
00582 }
00583
00584 lib3ds_chunk_write_end(&c, io);
00585 }
00586
00587
00588 static void
00589 texco_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
00590 Lib3dsChunk c;
00591 int i;
00592
00593 if (!mesh->texcos) {
00594 return;
00595 }
00596
00597 c.chunk = CHK_TEX_VERTS;
00598 c.size = 8 + 8 * mesh->nvertices;
00599 lib3ds_chunk_write(&c, io);
00600
00601 lib3ds_io_write_word(io, mesh->nvertices);
00602 for (i = 0; i < mesh->nvertices; ++i) {
00603 lib3ds_io_write_float(io, mesh->texcos[i][0]);
00604 lib3ds_io_write_float(io, mesh->texcos[i][1]);
00605 }
00606 }
00607
00608
00609 void
00610 lib3ds_mesh_write(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
00611 Lib3dsChunk c;
00612
00613 c.chunk = CHK_N_TRI_OBJECT;
00614 lib3ds_chunk_write_start(&c, io);
00615
00616 point_array_write(mesh, io);
00617 texco_array_write(mesh, io);
00618
00619 if (mesh->map_type != LIB3DS_MAP_NONE) {
00620 Lib3dsChunk c;
00621 int i, j;
00622
00623 c.chunk = CHK_MESH_TEXTURE_INFO;
00624 c.size = 92;
00625 lib3ds_chunk_write(&c, io);
00626
00627 lib3ds_io_write_word(io, mesh->map_type);
00628
00629 for (i = 0; i < 2; ++i) {
00630 lib3ds_io_write_float(io, mesh->map_tile[i]);
00631 }
00632 lib3ds_io_write_vector(io, mesh->map_pos);
00633 lib3ds_io_write_float(io, mesh->map_scale);
00634
00635 for (i = 0; i < 4; i++) {
00636 for (j = 0; j < 3; j++) {
00637 lib3ds_io_write_float(io, mesh->map_matrix[i][j]);
00638 }
00639 }
00640 for (i = 0; i < 2; ++i) {
00641 lib3ds_io_write_float(io, mesh->map_planar_size[i]);
00642 }
00643 lib3ds_io_write_float(io, mesh->map_cylinder_height);
00644 }
00645
00646 flag_array_write(mesh, io);
00647
00648 {
00649
00650 Lib3dsChunk c;
00651 int i, j;
00652
00653 c.chunk = CHK_MESH_MATRIX;
00654 c.size = 54;
00655 lib3ds_chunk_write(&c, io);
00656 for (i = 0; i < 4; i++) {
00657 for (j = 0; j < 3; j++) {
00658 lib3ds_io_write_float(io, mesh->matrix[i][j]);
00659 }
00660 }
00661 }
00662
00663 if (mesh->color) {
00664 Lib3dsChunk c;
00665
00666 c.chunk = CHK_MESH_COLOR;
00667 c.size = 7;
00668 lib3ds_chunk_write(&c, io);
00669 lib3ds_io_write_byte(io, mesh->color);
00670 }
00671
00672 face_array_write(file, mesh, io);
00673
00674 lib3ds_chunk_write_end(&c, io);
00675 }
00676