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 strcpy(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 fa = (Lib3dsFaces*)malloc(sizeof(Lib3dsFaces) * 3 * mesh->nfaces);
174
175 for (i = 0; i < mesh->nfaces; ++i) {
176 for (j = 0; j < 3; ++j) {
177 Lib3dsFaces* l = &fa[3*i+j];
178 float p[3], q[3], n[3];
179 float len, weight;
180
181 l->index = i;
182 l->next = fl[mesh->faces[i].index[j]];
183 fl[mesh->faces[i].index[j]] = l;
184
185 lib3ds_vector_sub(p, mesh->vertices[mesh->faces[i].index[j<2? j + 1 : 0]], mesh->vertices[mesh->faces[i].index[j]]);
186 lib3ds_vector_sub(q, mesh->vertices[mesh->faces[i].index[j>0? j - 1 : 2]], mesh->vertices[mesh->faces[i].index[j]]);
187 lib3ds_vector_cross(n, p, q);
188 len = lib3ds_vector_length(n);
189 if (len > 0) {
190 weight = (float)atan2(len, lib3ds_vector_dot(p, q));
191 lib3ds_vector_scalar_mul(l->normal, n, weight / len);
192 } else {
193 lib3ds_vector_zero(l->normal);
194 }
195 }
196 }
197
198 for (i = 0; i < mesh->nfaces; ++i) {
199 Lib3dsFace *f = &mesh->faces[i];
200 for (j = 0; j < 3; ++j) {
201 float n[3];
202 Lib3dsFaces *p;
203 Lib3dsFace *pf;
204
205 assert(mesh->faces[i].index[j] < mesh->nvertices);
206
207 if (f->smoothing_group) {
208 unsigned smoothing_group = f->smoothing_group;
209
210 lib3ds_vector_zero(n);
211 for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
212 pf = &mesh->faces[p->index];
213 if (pf->smoothing_group & f->smoothing_group)
214 smoothing_group |= pf->smoothing_group;
215 }
216
217 for (p = fl[mesh->faces[i].index[j]]; p; p = p->next) {
218 pf = &mesh->faces[p->index];
219 if (smoothing_group & pf->smoothing_group) {
220 lib3ds_vector_add(n, n, p->normal);
221 }
222 }
223 } else {
224 lib3ds_vector_copy(n, fa[3*i+j].normal);
225 }
226
227 lib3ds_vector_normalize(n);
228 lib3ds_vector_copy(normals[3*i+j], n);
229 }
230 }
231
232 free(fa);
233 free(fl);
234 }
235
236
237 static void
face_array_read(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)238 face_array_read(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
239 Lib3dsChunk c;
240 uint16_t chunk;
241 int i;
242 uint16_t nfaces;
243
244 lib3ds_chunk_read_start(&c, CHK_FACE_ARRAY, io);
245
246 lib3ds_mesh_resize_faces(mesh, 0);
247 nfaces = lib3ds_io_read_word(io);
248 if (nfaces) {
249 lib3ds_mesh_resize_faces(mesh, nfaces);
250 for (i = 0; i < nfaces; ++i) {
251 mesh->faces[i].index[0] = lib3ds_io_read_word(io);
252 mesh->faces[i].index[1] = lib3ds_io_read_word(io);
253 mesh->faces[i].index[2] = lib3ds_io_read_word(io);
254 mesh->faces[i].flags = lib3ds_io_read_word(io);
255 }
256 lib3ds_chunk_read_tell(&c, io);
257
258 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
259 switch (chunk) {
260 case CHK_MSH_MAT_GROUP: {
261 char name[64];
262 unsigned n;
263 unsigned i;
264 int index;
265 int material;
266
267 lib3ds_io_read_string(io, name, 64);
268 material = lib3ds_file_material_by_name(file, name);
269
270 n = lib3ds_io_read_word(io);
271 for (i = 0; i < n; ++i) {
272 index = lib3ds_io_read_word(io);
273 if (index < mesh->nfaces) {
274 mesh->faces[index].material = material;
275 } else {
276 // TODO warning
277 }
278 }
279 break;
280 }
281
282 case CHK_SMOOTH_GROUP: {
283 int i;
284 for (i = 0; i < mesh->nfaces; ++i) {
285 mesh->faces[i].smoothing_group = lib3ds_io_read_dword(io);
286 }
287 break;
288 }
289
290 case CHK_MSH_BOXMAP: {
291 lib3ds_io_read_string(io, mesh->box_front, 64);
292 lib3ds_io_read_string(io, mesh->box_back, 64);
293 lib3ds_io_read_string(io, mesh->box_left, 64);
294 lib3ds_io_read_string(io, mesh->box_right, 64);
295 lib3ds_io_read_string(io, mesh->box_top, 64);
296 lib3ds_io_read_string(io, mesh->box_bottom, 64);
297 break;
298 }
299
300 default:
301 lib3ds_chunk_unknown(chunk,io);
302 }
303 }
304
305 }
306 lib3ds_chunk_read_end(&c, io);
307 }
308
309
310 void
lib3ds_mesh_read(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)311 lib3ds_mesh_read(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
312 Lib3dsChunk c;
313 uint16_t chunk;
314
315 lib3ds_chunk_read_start(&c, CHK_N_TRI_OBJECT, io);
316
317 while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0) {
318 switch (chunk) {
319 case CHK_MESH_MATRIX: {
320 int i, j;
321
322 lib3ds_matrix_identity(mesh->matrix);
323 for (i = 0; i < 4; i++) {
324 for (j = 0; j < 3; j++) {
325 mesh->matrix[i][j] = lib3ds_io_read_float(io);
326 }
327 }
328 break;
329 }
330
331 case CHK_MESH_COLOR: {
332 mesh->color = lib3ds_io_read_byte(io);
333 break;
334 }
335
336 case CHK_POINT_ARRAY: {
337 int i;
338 uint16_t nvertices = lib3ds_io_read_word(io);
339 lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, mesh->vflags != NULL);
340 for (i = 0; i < mesh->nvertices; ++i) {
341 lib3ds_io_read_vector(io, mesh->vertices[i]);
342 }
343 break;
344 }
345
346 case CHK_POINT_FLAG_ARRAY: {
347 int i;
348 uint16_t nflags = lib3ds_io_read_word(io);
349 uint16_t nvertices = (mesh->nvertices >= nflags)? mesh->nvertices : nflags;
350 lib3ds_mesh_resize_vertices(mesh, nvertices, mesh->texcos != NULL, 1);
351 for (i = 0; i < nflags; ++i) {
352 mesh->vflags[i] = lib3ds_io_read_word(io);
353 }
354 break;
355 }
356
357 case CHK_FACE_ARRAY: {
358 lib3ds_chunk_read_reset(&c, io);
359 face_array_read(file, mesh, io);
360 break;
361 }
362
363 case CHK_MESH_TEXTURE_INFO: {
364 int i, j;
365
366 //FIXME: mesh->map_type = lib3ds_io_read_word(io);
367
368 for (i = 0; i < 2; ++i) {
369 mesh->map_tile[i] = lib3ds_io_read_float(io);
370 }
371 for (i = 0; i < 3; ++i) {
372 mesh->map_pos[i] = lib3ds_io_read_float(io);
373 }
374 mesh->map_scale = lib3ds_io_read_float(io);
375
376 lib3ds_matrix_identity(mesh->map_matrix);
377 for (i = 0; i < 4; i++) {
378 for (j = 0; j < 3; j++) {
379 mesh->map_matrix[i][j] = lib3ds_io_read_float(io);
380 }
381 }
382 for (i = 0; i < 2; ++i) {
383 mesh->map_planar_size[i] = lib3ds_io_read_float(io);
384 }
385 mesh->map_cylinder_height = lib3ds_io_read_float(io);
386 break;
387 }
388
389 case CHK_TEX_VERTS: {
390 int i;
391 uint16_t ntexcos = lib3ds_io_read_word(io);
392 uint16_t nvertices = (mesh->nvertices >= ntexcos)? mesh->nvertices : ntexcos;;
393 if (!mesh->texcos) {
394 lib3ds_mesh_resize_vertices(mesh, nvertices, 1, mesh->vflags != NULL);
395 }
396 for (i = 0; i < ntexcos; ++i) {
397 mesh->texcos[i][0] = lib3ds_io_read_float(io);
398 mesh->texcos[i][1] = lib3ds_io_read_float(io);
399 }
400 break;
401 }
402
403 default:
404 lib3ds_chunk_unknown(chunk, io);
405 }
406 }
407
408 if (lib3ds_matrix_det(mesh->matrix) < 0.0) {
409 /* Flip X coordinate of vertices if mesh matrix
410 has negative determinant */
411 float inv_matrix[4][4], M[4][4];
412 float tmp[3];
413 int i;
414
415 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
416 lib3ds_matrix_inv(inv_matrix);
417
418 lib3ds_matrix_copy(M, mesh->matrix);
419 lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f);
420 lib3ds_matrix_mult(M, M, inv_matrix);
421
422 for (i = 0; i < mesh->nvertices; ++i) {
423 lib3ds_vector_transform(tmp, M, mesh->vertices[i]);
424 lib3ds_vector_copy(mesh->vertices[i], tmp);
425 }
426 }
427
428 lib3ds_chunk_read_end(&c, io);
429 }
430
431
432 static void
point_array_write(Lib3dsMesh * mesh,Lib3dsIo * io)433 point_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
434 Lib3dsChunk c;
435 int i;
436
437 c.chunk = CHK_POINT_ARRAY;
438 c.size = 8 + 12 * mesh->nvertices;
439 lib3ds_chunk_write(&c, io);
440
441 lib3ds_io_write_word(io, (uint16_t) mesh->nvertices);
442
443 if (lib3ds_matrix_det(mesh->matrix) >= 0.0f) {
444 for (i = 0; i < mesh->nvertices; ++i) {
445 lib3ds_io_write_vector(io, mesh->vertices[i]);
446 }
447 } else {
448 /* Flip X coordinate of vertices if mesh matrix
449 has negative determinant */
450 float inv_matrix[4][4], M[4][4];
451 float tmp[3];
452
453 lib3ds_matrix_copy(inv_matrix, mesh->matrix);
454 lib3ds_matrix_inv(inv_matrix);
455 lib3ds_matrix_copy(M, mesh->matrix);
456 lib3ds_matrix_scale(M, -1.0f, 1.0f, 1.0f);
457 lib3ds_matrix_mult(M, M, inv_matrix);
458
459 for (i = 0; i < mesh->nvertices; ++i) {
460 lib3ds_vector_transform(tmp, M, mesh->vertices[i]);
461 lib3ds_io_write_vector(io, tmp);
462 }
463 }
464 }
465
466
467 static void
flag_array_write(Lib3dsMesh * mesh,Lib3dsIo * io)468 flag_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
469 Lib3dsChunk c;
470 int i;
471
472 if (!mesh->vflags) {
473 return;
474 }
475
476 c.chunk = CHK_POINT_FLAG_ARRAY;
477 c.size = 8 + 2 * mesh->nvertices;
478 lib3ds_chunk_write(&c, io);
479
480 lib3ds_io_write_word(io, (uint16_t) mesh->nvertices);
481 for (i = 0; i < mesh->nvertices; ++i) {
482 lib3ds_io_write_word(io, mesh->vflags[i]);
483 }
484 }
485
486
487 static void
face_array_write(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)488 face_array_write(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
489 Lib3dsChunk c;
490
491 if (mesh->nfaces == 0) {
492 return;
493 }
494 c.chunk = CHK_FACE_ARRAY;
495 lib3ds_chunk_write_start(&c, io);
496
497 {
498 int i;
499
500 lib3ds_io_write_word(io, (uint16_t) mesh->nfaces);
501 for (i = 0; i < mesh->nfaces; ++i) {
502 lib3ds_io_write_word(io, mesh->faces[i].index[0]);
503 lib3ds_io_write_word(io, mesh->faces[i].index[1]);
504 lib3ds_io_write_word(io, mesh->faces[i].index[2]);
505 lib3ds_io_write_word(io, mesh->faces[i].flags);
506 }
507 }
508
509 {
510 /*---- MSH_CHK_MAT_GROUP ----*/
511 Lib3dsChunk c;
512 int i, j;
513 uint16_t num;
514 Lib3dsIoImpl *impl = (Lib3dsIoImpl*)io->impl;
515
516 char *matf = (char*)calloc(sizeof(char), mesh->nfaces);
517 impl->tmp_mem = matf;
518 assert(matf);
519
520 for (i = 0; i < mesh->nfaces; ++i) {
521 if (!matf[i] && (mesh->faces[i].material >= 0) && (mesh->faces[i].material < file->nmaterials)) {
522 matf[i] = 1;
523 num = 1;
524
525 for (j = i + 1; j < mesh->nfaces; ++j) {
526 if (mesh->faces[i].material == mesh->faces[j].material) ++num;
527 }
528
529 c.chunk = CHK_MSH_MAT_GROUP;
530 c.size = 6 + (uint32_t)strlen(file->materials[mesh->faces[i].material]->name) + 1 + 2 + 2 * num;
531 lib3ds_chunk_write(&c, io);
532 lib3ds_io_write_string(io, file->materials[mesh->faces[i].material]->name);
533 lib3ds_io_write_word(io, num);
534 lib3ds_io_write_word(io, (uint16_t) i);
535
536 for (j = i + 1; j < mesh->nfaces; ++j) {
537 if (mesh->faces[i].material == mesh->faces[j].material) {
538 lib3ds_io_write_word(io, (uint16_t) j);
539 matf[j] = 1;
540 }
541 }
542 }
543 }
544 impl->tmp_mem = NULL;
545 free(matf);
546 }
547
548 {
549 /*---- SMOOTH_GROUP ----*/
550 Lib3dsChunk c;
551 int i;
552
553 c.chunk = CHK_SMOOTH_GROUP;
554 c.size = 6 + 4 * mesh->nfaces;
555 lib3ds_chunk_write(&c, io);
556
557 for (i = 0; i < mesh->nfaces; ++i) {
558 lib3ds_io_write_dword(io, mesh->faces[i].smoothing_group);
559 }
560 }
561
562 {
563 /*---- MSH_BOXMAP ----*/
564 Lib3dsChunk c;
565
566 if (strlen(mesh->box_front) ||
567 strlen(mesh->box_back) ||
568 strlen(mesh->box_left) ||
569 strlen(mesh->box_right) ||
570 strlen(mesh->box_top) ||
571 strlen(mesh->box_bottom)) {
572
573 c.chunk = CHK_MSH_BOXMAP;
574 lib3ds_chunk_write_start(&c, io);
575
576 lib3ds_io_write_string(io, mesh->box_front);
577 lib3ds_io_write_string(io, mesh->box_back);
578 lib3ds_io_write_string(io, mesh->box_left);
579 lib3ds_io_write_string(io, mesh->box_right);
580 lib3ds_io_write_string(io, mesh->box_top);
581 lib3ds_io_write_string(io, mesh->box_bottom);
582
583 lib3ds_chunk_write_end(&c, io);
584 }
585 }
586
587 lib3ds_chunk_write_end(&c, io);
588 }
589
590
591 static void
texco_array_write(Lib3dsMesh * mesh,Lib3dsIo * io)592 texco_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
593 Lib3dsChunk c;
594 int i;
595
596 if (!mesh->texcos) {
597 return;
598 }
599
600 c.chunk = CHK_TEX_VERTS;
601 c.size = 8 + 8 * mesh->nvertices;
602 lib3ds_chunk_write(&c, io);
603
604 lib3ds_io_write_word(io, mesh->nvertices);
605 for (i = 0; i < mesh->nvertices; ++i) {
606 lib3ds_io_write_float(io, mesh->texcos[i][0]);
607 lib3ds_io_write_float(io, mesh->texcos[i][1]);
608 }
609 }
610
611
612 void
lib3ds_mesh_write(Lib3dsFile * file,Lib3dsMesh * mesh,Lib3dsIo * io)613 lib3ds_mesh_write(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
614 Lib3dsChunk c;
615
616 c.chunk = CHK_N_TRI_OBJECT;
617 lib3ds_chunk_write_start(&c, io);
618
619 point_array_write(mesh, io);
620 texco_array_write(mesh, io);
621
622 if (mesh->map_type != LIB3DS_MAP_NONE) { /*---- LIB3DS_MESH_TEXTURE_INFO ----*/
623 Lib3dsChunk c;
624 int i, j;
625
626 c.chunk = CHK_MESH_TEXTURE_INFO;
627 c.size = 92;
628 lib3ds_chunk_write(&c, io);
629
630 lib3ds_io_write_word(io, (uint16_t)mesh->map_type);
631
632 for (i = 0; i < 2; ++i) {
633 lib3ds_io_write_float(io, mesh->map_tile[i]);
634 }
635 lib3ds_io_write_vector(io, mesh->map_pos);
636 lib3ds_io_write_float(io, mesh->map_scale);
637
638 for (i = 0; i < 4; i++) {
639 for (j = 0; j < 3; j++) {
640 lib3ds_io_write_float(io, mesh->map_matrix[i][j]);
641 }
642 }
643 for (i = 0; i < 2; ++i) {
644 lib3ds_io_write_float(io, mesh->map_planar_size[i]);
645 }
646 lib3ds_io_write_float(io, mesh->map_cylinder_height);
647 }
648
649 flag_array_write(mesh, io);
650
651 {
652 /*---- LIB3DS_MESH_MATRIX ----*/
653 Lib3dsChunk c;
654 int i, j;
655
656 c.chunk = CHK_MESH_MATRIX;
657 c.size = 54;
658 lib3ds_chunk_write(&c, io);
659 for (i = 0; i < 4; i++) {
660 for (j = 0; j < 3; j++) {
661 lib3ds_io_write_float(io, mesh->matrix[i][j]);
662 }
663 }
664 }
665
666 if (mesh->color) { /*---- LIB3DS_MESH_COLOR ----*/
667 Lib3dsChunk c;
668
669 c.chunk = CHK_MESH_COLOR;
670 c.size = 7;
671 lib3ds_chunk_write(&c, io);
672 lib3ds_io_write_byte(io, (uint8_t)mesh->color);
673 }
674
675 face_array_write(file, mesh, io);
676
677 lib3ds_chunk_write_end(&c, io);
678 }
679
680