root/OpenSceneGraph/trunk/src/osgPlugins/3ds/lib3ds/lib3ds_mesh.c @ 10853

Revision 10853, 20.5 kB (checked in by robert, 4 years ago)

From Sukender,
"Here is our freshly baked 3DS reader/writer (named 'v0.5' to differentiate from previous one). Changes are against trunk rev. 10819.
Short changelog (from rev 10819):
- Added 3DS writer
- Sync'd with latest lib3DS
- Added options, especially "flattenMatrixTransforms" to get the "old" behaviour (else the reader correctly maps to OSG the transforms from the 3DS file).

What should be done:
- Check with pivot points, with and without "flattenMatrixTransforms" option.
- We ran tests on it, but we can never be 100% sure there is no bug. Testing from the community would of course be helpful."

RevLine 
[10853]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 */
33Lib3dsMesh*
34lib3ds_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 */
56void
57lib3ds_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
65void
66lib3ds_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
85void 
86lib3ds_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 */
104void
105lib3ds_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
117void
118lib3ds_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
135typedef 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 */
162void
163lib3ds_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
237static void
238face_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
310void
311lib3ds_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
432static void
433point_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
467static void
468flag_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
487static void
488face_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        char *matf = (char*)calloc(sizeof(char), mesh->nfaces);
515                ((Lib3dsIoImpl*)io->impl)->tmp_mem = matf;
516        assert(matf);
517
518        for (i = 0; i < mesh->nfaces; ++i) {
519            if (!matf[i] && (mesh->faces[i].material >= 0) && (mesh->faces[i].material < file->nmaterials)) {
520                matf[i] = 1;
521                num = 1;
522
523                for (j = i + 1; j < mesh->nfaces; ++j) {
524                    if (mesh->faces[i].material == mesh->faces[j].material) ++num;
525                }
526
527                c.chunk = CHK_MSH_MAT_GROUP;
528                c.size = 6 + (uint32_t)strlen(file->materials[mesh->faces[i].material]->name) + 1 + 2 + 2 * num;
529                lib3ds_chunk_write(&c, io);
530                lib3ds_io_write_string(io, file->materials[mesh->faces[i].material]->name);
531                lib3ds_io_write_word(io, num);
532                lib3ds_io_write_word(io, (uint16_t) i);
533
534                for (j = i + 1; j < mesh->nfaces; ++j) {
535                    if (mesh->faces[i].material == mesh->faces[j].material) {
536                        lib3ds_io_write_word(io, (uint16_t) j);
537                        matf[j] = 1;
538                    }
539                }
540            }
541        }
542        ((Lib3dsIoImpl*)io->impl)->tmp_mem = NULL;
543        free(matf);
544    }
545
546    {
547        /*---- SMOOTH_GROUP ----*/
548        Lib3dsChunk c;
549        int i;
550
551        c.chunk = CHK_SMOOTH_GROUP;
552        c.size = 6 + 4 * mesh->nfaces;
553        lib3ds_chunk_write(&c, io);
554
555        for (i = 0; i < mesh->nfaces; ++i) {
556            lib3ds_io_write_dword(io, mesh->faces[i].smoothing_group);
557        }
558    }
559
560    {
561        /*---- MSH_BOXMAP ----*/
562        Lib3dsChunk c;
563
564        if (strlen(mesh->box_front) ||
565            strlen(mesh->box_back) ||
566            strlen(mesh->box_left) ||
567            strlen(mesh->box_right) ||
568            strlen(mesh->box_top) ||
569            strlen(mesh->box_bottom)) {
570
571            c.chunk = CHK_MSH_BOXMAP;
572            lib3ds_chunk_write_start(&c, io);
573
574            lib3ds_io_write_string(io, mesh->box_front);
575            lib3ds_io_write_string(io, mesh->box_back);
576            lib3ds_io_write_string(io, mesh->box_left);
577            lib3ds_io_write_string(io, mesh->box_right);
578            lib3ds_io_write_string(io, mesh->box_top);
579            lib3ds_io_write_string(io, mesh->box_bottom);
580
581            lib3ds_chunk_write_end(&c, io);
582        }
583    }
584
585    lib3ds_chunk_write_end(&c, io);
586}
587
588
589static void
590texco_array_write(Lib3dsMesh *mesh, Lib3dsIo *io) {
591    Lib3dsChunk c;
592    int i;
593
594    if (!mesh->texcos) {
595        return;
596    }
597     
598    c.chunk = CHK_TEX_VERTS;
599    c.size = 8 + 8 * mesh->nvertices;
600    lib3ds_chunk_write(&c, io);
601
602    lib3ds_io_write_word(io, mesh->nvertices);
603    for (i = 0; i < mesh->nvertices; ++i) {
604        lib3ds_io_write_float(io, mesh->texcos[i][0]);
605        lib3ds_io_write_float(io, mesh->texcos[i][1]);
606    }
607}
608
609
610void
611lib3ds_mesh_write(Lib3dsFile *file, Lib3dsMesh *mesh, Lib3dsIo *io) {
612    Lib3dsChunk c;
613
614    c.chunk = CHK_N_TRI_OBJECT;
615    lib3ds_chunk_write_start(&c, io);
616
617    point_array_write(mesh, io);
618    texco_array_write(mesh, io);
619
620    if (mesh->map_type != LIB3DS_MAP_NONE) {   /*---- LIB3DS_MESH_TEXTURE_INFO ----*/
621        Lib3dsChunk c;
622        int i, j;
623
624        c.chunk = CHK_MESH_TEXTURE_INFO;
625        c.size = 92;
626        lib3ds_chunk_write(&c, io);
627
628        lib3ds_io_write_word(io, (uint16_t)mesh->map_type);
629
630        for (i = 0; i < 2; ++i) {
631            lib3ds_io_write_float(io, mesh->map_tile[i]);
632        }
633        lib3ds_io_write_vector(io, mesh->map_pos);
634        lib3ds_io_write_float(io, mesh->map_scale);
635
636        for (i = 0; i < 4; i++) {
637            for (j = 0; j < 3; j++) {
638                lib3ds_io_write_float(io, mesh->map_matrix[i][j]);
639            }
640        }
641        for (i = 0; i < 2; ++i) {
642            lib3ds_io_write_float(io, mesh->map_planar_size[i]);
643        }
644        lib3ds_io_write_float(io, mesh->map_cylinder_height);
645    }
646
647    flag_array_write(mesh, io);
648
649    {
650        /*---- LIB3DS_MESH_MATRIX ----*/
651        Lib3dsChunk c;
652        int i, j;
653
654        c.chunk = CHK_MESH_MATRIX;
655        c.size = 54;
656        lib3ds_chunk_write(&c, io);
657        for (i = 0; i < 4; i++) {
658            for (j = 0; j < 3; j++) {
659                lib3ds_io_write_float(io, mesh->matrix[i][j]);
660            }
661        }
662    }
663
664    if (mesh->color) {   /*---- LIB3DS_MESH_COLOR ----*/
665        Lib3dsChunk c;
666
667        c.chunk = CHK_MESH_COLOR;
668        c.size = 7;
669        lib3ds_chunk_write(&c, io);
670        lib3ds_io_write_byte(io, (uint8_t)mesh->color);
671    }
672   
673    face_array_write(file, mesh, io);
674
675    lib3ds_chunk_write_end(&c, io);
676}
Note: See TracBrowser for help on using the browser.