1 /*
2 Copyright (C) 1996-2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
3 All rights reserved.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 2.1 of the License, or
8 (at your option) any later version.
9
10 Thisprogram is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "lib3ds_impl.h"
19
20
21 /*!
22 * Create and return a new empty mesh object.
23 *
24 * Mesh is initialized with the name and an identity matrix; all
25 * other fields are zero.
26 *
27 * See Lib3dsFaceFlag for definitions of per-face flags.
28 *
29 * \param name Mesh name. Must not be NULL. Must be < 64 characters.
30 *
31 * \return mesh object or NULL on error.
32 */
33 Lib3dsMesh*
lib3ds_mesh_new(const char * name)34 lib3ds_mesh_new(const char *name) {
35 Lib3dsMesh *mesh;
36
37 assert(name);
38 assert(strlen(name) < 64);
39
40 mesh = (Lib3dsMesh*) calloc(sizeof(Lib3dsMesh), 1);
41 if (!mesh) {
42 return (0);
43 }
44 stringcopyfixedsize(mesh->name, name);
45 lib3ds_matrix_identity(mesh->matrix);
46 mesh->map_type = LIB3DS_MAP_NONE;
47 return (mesh);
48 }
49
50
51 /*!
52 * Free a mesh object and all of its resources.
53 *
54 * \param mesh Mesh object to be freed.
55 */
56 void
lib3ds_mesh_free(Lib3dsMesh * mesh)57 lib3ds_mesh_free(Lib3dsMesh *mesh) {
58 lib3ds_mesh_resize_vertices(mesh, 0, 0, 0);
59 lib3ds_mesh_resize_faces(mesh, 0);
60 memset(mesh, 0, sizeof(Lib3dsMesh));
61 free(mesh);
62 }
63
64
65 void
lib3ds_mesh_resize_vertices(Lib3dsMesh * mesh,int nvertices,int use_texcos,int use_flags)66 lib3ds_mesh_resize_vertices(Lib3dsMesh *mesh, int nvertices, int use_texcos, int use_flags) {
67 assert(mesh);
68 mesh->vertices = (float (*)[3])lib3ds_util_realloc_array(mesh->vertices, mesh->nvertices, nvertices, 3 * sizeof(float));
69 mesh->texcos = (float (*)[2])lib3ds_util_realloc_array(
70 mesh->texcos,
71 mesh->texcos? mesh->nvertices : 0,
72 use_texcos? nvertices : 0,
73 2 * sizeof(float)
74 );
75 mesh->vflags = (unsigned short*)lib3ds_util_realloc_array(
76 mesh->vflags,
77 mesh->vflags? mesh->nvertices : 0,
78 use_flags? nvertices : 0,
79 2 * sizeof(float)
80 );
81 mesh->nvertices = (unsigned short)nvertices;
82 }
83
84
85 void
lib3ds_mesh_resize_faces(Lib3dsMesh * mesh,int nfaces)86 lib3ds_mesh_resize_faces(Lib3dsMesh *mesh, int nfaces) {
87 int i;
88 assert(mesh);
89 mesh->faces = (Lib3dsFace *)lib3ds_util_realloc_array(mesh->faces, mesh->nfaces, nfaces, sizeof(Lib3dsFace));
90 for (i = mesh->nfaces; i < nfaces; ++i) {
91 mesh->faces[i].material = -1;
92 }
93 mesh->nfaces = (unsigned short)nfaces;
94 }
95
96
97 /*!
98 * Find the bounding box of a mesh object.
99 *
100 * \param mesh The mesh object
101 * \param bmin Returned bounding box
102 * \param bmax Returned bounding box
103 */
104 void
lib3ds_mesh_bounding_box(Lib3dsMesh * mesh,float bmin[3],float bmax[3])105 lib3ds_mesh_bounding_box(Lib3dsMesh *mesh, float bmin[3], float bmax[3]) {
106 int i;
107 bmin[0] = bmin[1] = bmin[2] = FLT_MAX;
108 bmax[0] = bmax[1] = bmax[2] = -FLT_MAX;
109
110 for (i = 0; i < mesh->nvertices; ++i) {
111 lib3ds_vector_min(bmin, mesh->vertices[i]);
112 lib3ds_vector_max(bmax, mesh->vertices[i]);
113 }
114 }
115
116
117 void
lib3ds_mesh_calculate_face_normals(Lib3dsMesh * mesh,float (* face_normals)[3])118 lib3ds_mesh_calculate_face_normals(Lib3dsMesh *mesh, float (*face_normals)[3]) {
119 int i;
120
121 if (!mesh->nfaces) {
122 return;
123 }
124 for (i = 0; i < mesh->nfaces; ++i) {
125 lib3ds_vector_normal(
126 face_normals[i],
127 mesh->vertices[mesh->faces[i].index[0]],
128 mesh->vertices[mesh->faces[i].index[1]],
129 mesh->vertices[mesh->faces[i].index[2]]
130 );
131 }
132 }
133
134
135 typedef struct Lib3dsFaces {
136 struct Lib3dsFaces *next;
137 int index;
138 float normal[3];
139 } Lib3dsFaces;
140
141
142 /*!
143 * Calculates the vertex normals corresponding to the smoothing group
144 * settings for each face of a mesh.
145 *
146 * \param mesh A pointer to the mesh to calculate the normals for.
147 * \param normals A pointer to a buffer to store the calculated
148 * normals. The buffer must have the size:
149 * 3*3*sizeof(float)*mesh->nfaces.
150 *
151 * To allocate the normal buffer do for example the following:
152 * \code
153 * Lib3dsVector *normals = malloc(3*3*sizeof(float)*mesh->nfaces);
154 * \endcode
155 *
156 * To access the normal of the i-th vertex of the j-th face do the
157 * following:
158 * \code
159 * normals[3*j+i]
160 * \endcode
161 */
162 void
lib3ds_mesh_calculate_vertex_normals(Lib3dsMesh * mesh,float (* normals)[3])163 lib3ds_mesh_calculate_vertex_normals(Lib3dsMesh *mesh, float (*normals)[3]) {
164 Lib3dsFaces **fl;
165 Lib3dsFaces *fa;
166 int i, j;
167
168 if (!mesh->nfaces) {
169 return;
170 }
171
172 fl = (Lib3dsFaces**)calloc(sizeof(Lib3dsFaces*), mesh->nvertices);
173 if (!fl)
174 {
175 return;
176 }
177
178 fa = (Lib3dsFaces*)malloc(sizeof(Lib3dsFaces) * 3 * mesh->nfaces);
179 if (!fa)
180 {
181 free(fl);
182 return;
183 }
184
185 for (i = 0; i < mesh->nfaces; ++i) {
186 for (j = 0; j < 3; ++j) {
187 Lib3dsFaces* l = &fa[3*i+j];
188 float p[3], q[3], n[3];
189 float len, weight;
190
191 l->index = i;
192 l->next = fl[mesh->faces[i].index[j]];
193 fl[mesh->faces[i].index[j]] = l;
194
195 lib3ds_vector_sub(p, mesh->vertices[mesh->faces[i].index[j<2? j + 1 : 0]], mesh->vertices[mesh->faces[i].index[j]]);
196 lib3ds_vector_sub(q, mesh->vertices[mesh->faces[i].index[j>0? j - 1 : 2]], mesh->vertices[mesh->faces[i].index[j]]);
197 lib3ds_vector_cross(n, p, q);
198 len = lib3ds_vector_length(n);
199 if (len > 0) {
200 weight = (float)atan2(len, lib3ds_vector_dot(p, q));
201 lib3ds_vector_scalar_mul(l->normal, n, weight / len);
202 } else {
203 lib3ds_vector_zero(l->normal);
204 }
205 }
206 }
207
208 for (i = 0; i < mesh->nfaces; ++i) {
209 Lib3dsFace *f = &mesh->faces[i];
210 for (j = 0; j < 3; ++j) {
211 float n[3];
212 Lib3dsFaces *p;
213 Lib3dsFace *pf;
214
215 assert(mesh->faces[i].index[j] < mesh->nvertices);
216
217 if (f->smoothing_group) {
218 unsigned smoothing_group = f->smoothing_group;
219
220 lib3ds_vector_zero(n);
221 for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
222 pf = &mesh->faces[p->index];
223 if (pf->smoothing_group & f->smoothing_group)
224 smoothing_group |= pf->smoothing_group;
225 }
226
227 for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
228 pf = &mesh->faces[p->index];
229 if (smoothing_group & pf->smoothing_group) {
230 lib3ds_vector_add(n, n, p->normal);
231 }
232 }
233 } else {
234 lib3ds_vector_copy(n, fa[3*i+j].normal);
235 }
236
237 lib3ds_vector_normalize(n);
238 lib3ds_vector_copy(normals[3*i+j], n);
239 }
240 }
241
242 free(fa);
243 free(fl);
244 }
245
246
247 static void
face_array_read(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)248 face_array_read(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
249 Lib3dsChunk c;
250 uint16_t chunk;
251 int i;
252 uint16_t nfaces;
253
254 lib3ds_chunk_read_start(&c, CHK_FACE_ARRAY, io);
255
256 lib3ds_mesh_resize_faces(mesh, 0);
257 nfaces = lib3ds_io_read_word(io);
258 if (nfaces) {
259 lib3ds_mesh_resize_faces(mesh, nfaces);
260 for (i = 0; i < nfaces; ++i) {
261 mesh->faces[i].index[0] = lib3ds_io_read_word(io);
262 mesh->faces[i].index[1] = lib3ds_io_read_word(io);
263 mesh->faces[i].index[2] = lib3ds_io_read_word(io);
264 mesh->faces[i].flags = lib3ds_io_read_word(io);
265 }
266 lib3ds_chunk_read_tell(&c, io);
267
268 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
269 switch (chunk) {
270 case CHK_MSH_MAT_GROUP: {
271 char name[64];
272 unsigned n;
273 unsigned i;
274 int index;
275 int material;
276
277 lib3ds_io_read_string(io, name, 64);
278 material = lib3ds_file_material_by_name(file, name);
279
280 n = lib3ds_io_read_word(io);
281 for (i = 0; i < n; ++i) {
282 index = lib3ds_io_read_word(io);
283 if (index < mesh->nfaces) {
284 mesh->faces[index].material = material;
285 } else {
286 // TODO warning
287 }
288 }
289 break;
290 }
291
292 case CHK_SMOOTH_GROUP: {
293 int i;
294 for (i = 0; i < mesh->nfaces; ++i) {
295 mesh->faces[i].smoothing_group = lib3ds_io_read_dword(io);
296 }
297 break;
298 }
299
300 case CHK_MSH_BOXMAP: {
301 lib3ds_io_read_string(io, mesh->box_front, 64);
302 lib3ds_io_read_string(io, mesh->box_back, 64);
303 lib3ds_io_read_string(io, mesh->box_left, 64);
304 lib3ds_io_read_string(io, mesh->box_right, 64);
305 lib3ds_io_read_string(io, mesh->box_top, 64);
306 lib3ds_io_read_string(io, mesh->box_bottom, 64);
307 break;
308 }
309
310 default:
311 lib3ds_chunk_unknown(chunk,io);
312 }
313 }
314
315 }
316 lib3ds_chunk_read_end(&c, io);
317 }
318
319
320 void
lib3ds_mesh_read(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)321 lib3ds_mesh_read(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
322 Lib3dsChunk c;
323 uint16_t chunk;
324
325 lib3ds_chunk_read_start(&c, CHK_N_TRI_OBJECT, io);
326
327 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
328 switch (chunk) {
329 case CHK_MESH_MATRIX: {
330 int i, j;
331
332 lib3ds_matrix_identity(mesh->matrix);
333 for (i = 0; i < 4; i++) {
334 for (j = 0; j < 3; j++) {
335 mesh->matrix[i][j] = lib3ds_io_read_float(io);
336 }
337 }
338 break;
339 }
340
341 case CHK_MESH_COLOR: {
342 mesh->color = lib3ds_io_read_byte(io);
343 break;
344 }
345
346 case CHK_POINT_ARRAY: {
347 int i;
348 uint16_t nvertices = lib3ds_io_read_word(io);
349 lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, mesh->vflags != NULL);
350 for (i = 0; i < mesh->nvertices; ++i) {
351 lib3ds_io_read_vector(io, mesh->vertices[i]);
352 }
353 break;
354 }
355
356 case CHK_POINT_FLAG_ARRAY: {
357 int i;
358 uint16_t nflags = lib3ds_io_read_word(io);
359 uint16_t nvertices = (mesh->nvertices >= nflags)? mesh->nvertices : nflags;
360 lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, 1);
361 for (i = 0; i < nflags; ++i) {
362 mesh->vflags[i] = lib3ds_io_read_word(io);
363 }
364 break;
365 }
366
367 case CHK_FACE_ARRAY: {
368 lib3ds_chunk_read_reset(&c, io);
369 face_array_read(file, mesh, io);
370 break;
371 }
372
373 case CHK_MESH_TEXTURE_INFO: {
374 int i, j;
375
376 //FIXME: mesh->map_type = lib3ds_io_read_word(io);
377
378 for (i = 0; i < 2; ++i) {
379 mesh->map_tile[i] = lib3ds_io_read_float(io);
380 }
381 for (i = 0; i < 3; ++i) {
382 mesh->map_pos[i] = lib3ds_io_read_float(io);
383 }
384 mesh->map_scale = lib3ds_io_read_float(io);
385
386 lib3ds_matrix_identity(mesh->map_matrix);
387 for (i = 0; i < 4; i++) {
388 for (j = 0; j < 3; j++) {
389 mesh->map_matrix[i][j] = lib3ds_io_read_float(io);
390 }
391 }
392 for (i = 0; i < 2; ++i) {
393 mesh->map_planar_size[i] = lib3ds_io_read_float(io);
394 }
395 mesh->map_cylinder_height = lib3ds_io_read_float(io);
396 break;
397 }
398
399 case CHK_TEX_VERTS: {
400 int i;
401 uint16_t ntexcos = lib3ds_io_read_word(io);
402 uint16_t nvertices = (mesh->nvertices >= ntexcos)? mesh->nvertices : ntexcos;;
403 if (!mesh->texcos) {
404 lib3ds_mesh_resize_vertices(mesh, nvertices, 1, mesh->vflags != NULL);
405 }
406 for (i = 0; i < ntexcos; ++i) {
407 mesh->texcos[i][0] = lib3ds_io_read_float(io);
408 mesh->texcos[i][1] = lib3ds_io_read_float(io);
409 }
410 break;
411 }
412
413 default:
414 lib3ds_chunk_unknown(chunk, io);
415 }
416 }
417
418 if (lib3ds_matrix_det(mesh->matrix) < 0.0) {
419 /* Flip X coordinate of vertices if mesh matrix
420 has negative determinant */
421 float inv_matrix[4][4], M[4][4];
422 float tmp[3];
423 int i;
424
425 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
426 lib3ds_matrix_inv(inv_matrix);
427
428 lib3ds_matrix_copy(M, mesh->matrix);
429 lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f);
430 lib3ds_matrix_mult(M, M, inv_matrix);
431
432 for (i = 0; i < mesh->nvertices; ++i) {
433 lib3ds_vector_transform(tmp, M, mesh->vertices[i]);
434 lib3ds_vector_copy(mesh->vertices[i], tmp);
435 }
436 }
437
438 lib3ds_chunk_read_end(&c, io);
439 }
440
441
442 static void
point_array_write(Lib3dsMesh * mesh,Lib3dsIo * io)443 point_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
444 Lib3dsChunk c;
445 int i;
446
447 c.chunk = CHK_POINT_ARRAY;
448 c.size = 8 + 12 * mesh->nvertices;
449 lib3ds_chunk_write(&c, io);
450
451 lib3ds_io_write_word(io, (uint16_t) mesh->nvertices);
452
453 if (lib3ds_matrix_det(mesh->matrix) >= 0.0f) {
454 for (i = 0; i < mesh->nvertices; ++i) {
455 lib3ds_io_write_vector(io, mesh->vertices[i]);
456 }
457 } else {
458 /* Flip X coordinate of vertices if mesh matrix
459 has negative determinant */
460 float inv_matrix[4][4], M[4][4];
461 float tmp[3];
462
463 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
464 lib3ds_matrix_inv(inv_matrix);
465 lib3ds_matrix_copy(M, mesh->matrix);
466 lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f);
467 lib3ds_matrix_mult(M, M, inv_matrix);
468
469 for (i = 0; i < mesh->nvertices; ++i) {
470 lib3ds_vector_transform(tmp, M, mesh->vertices[i]);
471 lib3ds_io_write_vector(io, tmp);
472 }
473 }
474 }
475
476
477 static void
flag_array_write(Lib3dsMesh * mesh,Lib3dsIo * io)478 flag_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
479 Lib3dsChunk c;
480 int i;
481
482 if (!mesh->vflags) {
483 return;
484 }
485
486 c.chunk = CHK_POINT_FLAG_ARRAY;
487 c.size = 8 + 2 * mesh->nvertices;
488 lib3ds_chunk_write(&c, io);
489
490 lib3ds_io_write_word(io, (uint16_t) mesh->nvertices);
491 for (i = 0; i < mesh->nvertices; ++i) {
492 lib3ds_io_write_word(io, mesh->vflags[i]);
493 }
494 }
495
496
497 static void
face_array_write(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)498 face_array_write(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
499 Lib3dsChunk c;
500
501 if (mesh->nfaces == 0) {
502 return;
503 }
504 c.chunk = CHK_FACE_ARRAY;
505 lib3ds_chunk_write_start(&c, io);
506
507 {
508 int i;
509
510 lib3ds_io_write_word(io, (uint16_t) mesh->nfaces);
511 for (i = 0; i < mesh->nfaces; ++i) {
512 lib3ds_io_write_word(io, mesh->faces[i].index[0]);
513 lib3ds_io_write_word(io, mesh->faces[i].index[1]);
514 lib3ds_io_write_word(io, mesh->faces[i].index[2]);
515 lib3ds_io_write_word(io, mesh->faces[i].flags);
516 }
517 }
518
519 {
520 /*---- MSH_CHK_MAT_GROUP ----*/
521 Lib3dsChunk c;
522 int i, j;
523 uint16_t num;
524 char *matf = (char*)calloc(sizeof(char), mesh->nfaces);
525 ((Lib3dsIoImpl*)io->impl)->tmp_mem = matf;
526 assert(matf);
527
528 for (i = 0; i < mesh->nfaces; ++i) {
529 if (!matf[i] && (mesh->faces[i].material >= 0) && (mesh->faces[i].material < file->nmaterials)) {
530 matf[i] = 1;
531 num = 1;
532
533 for (j = i + 1; j < mesh->nfaces; ++j) {
534 if (mesh->faces[i].material == mesh->faces[j].material) ++num;
535 }
536
537 c.chunk = CHK_MSH_MAT_GROUP;
538 c.size = 6 + (uint32_t)strlen(file->materials[mesh->faces[i].material]->name) + 1 + 2 + 2 * num;
539 lib3ds_chunk_write(&c, io);
540 lib3ds_io_write_string(io, file->materials[mesh->faces[i].material]->name);
541 lib3ds_io_write_word(io, num);
542 lib3ds_io_write_word(io, (uint16_t) i);
543
544 for (j = i + 1; j < mesh->nfaces; ++j) {
545 if (mesh->faces[i].material == mesh->faces[j].material) {
546 lib3ds_io_write_word(io, (uint16_t) j);
547 matf[j] = 1;
548 }
549 }
550 }
551 }
552 ((Lib3dsIoImpl*)io->impl)->tmp_mem = NULL;
553 free(matf);
554 }
555
556 {
557 /*---- SMOOTH_GROUP ----*/
558 Lib3dsChunk c;
559 int i;
560
561 c.chunk = CHK_SMOOTH_GROUP;
562 c.size = 6 + 4 * mesh->nfaces;
563 lib3ds_chunk_write(&c, io);
564
565 for (i = 0; i < mesh->nfaces; ++i) {
566 lib3ds_io_write_dword(io, mesh->faces[i].smoothing_group);
567 }
568 }
569
570 {
571 /*---- MSH_BOXMAP ----*/
572 Lib3dsChunk c;
573
574 if (strlen(mesh->box_front) ||
575 strlen(mesh->box_back) ||
576 strlen(mesh->box_left) ||
577 strlen(mesh->box_right) ||
578 strlen(mesh->box_top) ||
579 strlen(mesh->box_bottom)) {
580
581 c.chunk = CHK_MSH_BOXMAP;
582 lib3ds_chunk_write_start(&c, io);
583
584 lib3ds_io_write_string(io, mesh->box_front);
585 lib3ds_io_write_string(io, mesh->box_back);
586 lib3ds_io_write_string(io, mesh->box_left);
587 lib3ds_io_write_string(io, mesh->box_right);
588 lib3ds_io_write_string(io, mesh->box_top);
589 lib3ds_io_write_string(io, mesh->box_bottom);
590
591 lib3ds_chunk_write_end(&c, io);
592 }
593 }
594
595 lib3ds_chunk_write_end(&c, io);
596 }
597
598
599 static void
texco_array_write(Lib3dsMesh * mesh,Lib3dsIo * io)600 texco_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
601 Lib3dsChunk c;
602 int i;
603
604 if (!mesh->texcos) {
605 return;
606 }
607
608 c.chunk = CHK_TEX_VERTS;
609 c.size = 8 + 8 * mesh->nvertices;
610 lib3ds_chunk_write(&c, io);
611
612 lib3ds_io_write_word(io, mesh->nvertices);
613 for (i = 0; i < mesh->nvertices; ++i) {
614 lib3ds_io_write_float(io, mesh->texcos[i][0]);
615 lib3ds_io_write_float(io, mesh->texcos[i][1]);
616 }
617 }
618
619
620 void
lib3ds_mesh_write(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)621 lib3ds_mesh_write(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
622 Lib3dsChunk c;
623
624 c.chunk = CHK_N_TRI_OBJECT;
625 lib3ds_chunk_write_start(&c, io);
626
627 point_array_write(mesh, io);
628 texco_array_write(mesh, io);
629
630 if (mesh->map_type != LIB3DS_MAP_NONE) { /*---- LIB3DS_MESH_TEXTURE_INFO ----*/
631 Lib3dsChunk c;
632 int i, j;
633
634 c.chunk = CHK_MESH_TEXTURE_INFO;
635 c.size = 92;
636 lib3ds_chunk_write(&c, io);
637
638 lib3ds_io_write_word(io, (uint16_t)mesh->map_type);
639
640 for (i = 0; i < 2; ++i) {
641 lib3ds_io_write_float(io, mesh->map_tile[i]);
642 }
643 lib3ds_io_write_vector(io, mesh->map_pos);
644 lib3ds_io_write_float(io, mesh->map_scale);
645
646 for (i = 0; i < 4; i++) {
647 for (j = 0; j < 3; j++) {
648 lib3ds_io_write_float(io, mesh->map_matrix[i][j]);
649 }
650 }
651 for (i = 0; i < 2; ++i) {
652 lib3ds_io_write_float(io, mesh->map_planar_size[i]);
653 }
654 lib3ds_io_write_float(io, mesh->map_cylinder_height);
655 }
656
657 flag_array_write(mesh, io);
658
659 {
660 /*---- LIB3DS_MESH_MATRIX ----*/
661 Lib3dsChunk c;
662 int i, j;
663
664 c.chunk = CHK_MESH_MATRIX;
665 c.size = 54;
666 lib3ds_chunk_write(&c, io);
667 for (i = 0; i < 4; i++) {
668 for (j = 0; j < 3; j++) {
669 lib3ds_io_write_float(io, mesh->matrix[i][j]);
670 }
671 }
672 }
673
674 if (mesh->color) { /*---- LIB3DS_MESH_COLOR ----*/
675 Lib3dsChunk c;
676
677 c.chunk = CHK_MESH_COLOR;
678 c.size = 7;
679 lib3ds_chunk_write(&c, io);
680 lib3ds_io_write_byte(io, (uint8_t)mesh->color);
681 }
682
683 face_array_write(file, mesh, io);
684
685 lib3ds_chunk_write_end(&c, io);
686 }
687
688