Show mesh.c syntax highlighted
/*
* The 3D Studio File Format Library
* Copyright (C) 1996-2001 by J.E. Hoffmann <je-h@gmx.net>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: mesh.c,v 1.22 2004/11/20 08:33:56 efalk Exp $
*/
#define LIB3DS_EXPORT
#include <lib3ds/mesh.h>
#include <lib3ds/io.h>
#include <lib3ds/chunk.h>
#include <lib3ds/vector.h>
#include <lib3ds/matrix.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <config.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif
/*!
* \defgroup mesh Meshes
*
* \author J.E. Hoffmann <je-h@gmx.net>
*/
static Lib3dsBool
face_array_read(Lib3dsMesh *mesh, Lib3dsIo *io)
{
Lib3dsChunk c;
Lib3dsWord chunk;
int i;
int faces;
if (!lib3ds_chunk_read_start(&c, LIB3DS_FACE_ARRAY, io)) {
return(LIB3DS_FALSE);
}
lib3ds_mesh_free_face_list(mesh);
faces=lib3ds_io_read_word(io);
if (faces) {
if (!lib3ds_mesh_new_face_list(mesh, faces)) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
for (i=0; i<faces; ++i) {
strcpy(mesh->faceL[i].material, "");
mesh->faceL[i].points[0]=lib3ds_io_read_word(io);
mesh->faceL[i].points[1]=lib3ds_io_read_word(io);
mesh->faceL[i].points[2]=lib3ds_io_read_word(io);
mesh->faceL[i].flags=lib3ds_io_read_word(io);
}
lib3ds_chunk_read_tell(&c, io);
while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
switch (chunk) {
case LIB3DS_SMOOTH_GROUP:
{
unsigned i;
for (i=0; i<mesh->faces; ++i) {
mesh->faceL[i].smoothing=lib3ds_io_read_dword(io);
}
}
break;
case LIB3DS_MSH_MAT_GROUP:
{
char name[64];
unsigned faces;
unsigned i;
unsigned index;
if (!lib3ds_io_read_string(io, name, 64)) {
return(LIB3DS_FALSE);
}
faces=lib3ds_io_read_word(io);
for (i=0; i<faces; ++i) {
index=lib3ds_io_read_word(io);
ASSERT(index<mesh->faces);
strcpy(mesh->faceL[index].material, name);
}
}
break;
case LIB3DS_MSH_BOXMAP:
{
char name[64];
if (!lib3ds_io_read_string(io, name, 64)) {
return(LIB3DS_FALSE);
}
strcpy(mesh->box_map.front, name);
if (!lib3ds_io_read_string(io, name, 64)) {
return(LIB3DS_FALSE);
}
strcpy(mesh->box_map.back, name);
if (!lib3ds_io_read_string(io, name, 64)) {
return(LIB3DS_FALSE);
}
strcpy(mesh->box_map.left, name);
if (!lib3ds_io_read_string(io, name, 64)) {
return(LIB3DS_FALSE);
}
strcpy(mesh->box_map.right, name);
if (!lib3ds_io_read_string(io, name, 64)) {
return(LIB3DS_FALSE);
}
strcpy(mesh->box_map.top, name);
if (!lib3ds_io_read_string(io, name, 64)) {
return(LIB3DS_FALSE);
}
strcpy(mesh->box_map.bottom, name);
}
break;
default:
lib3ds_chunk_unknown(chunk);
}
}
}
lib3ds_chunk_read_end(&c, io);
return(LIB3DS_TRUE);
}
/*!
* Create and return a new empty mesh object.
*
* Mesh is initialized with the name and an identity matrix; all
* other fields are zero.
*
* See Lib3dsFaceFlag for definitions of per-face flags.
*
* \param name Mesh name. Must not be NULL. Must be < 64 characters.
*
* \return mesh object or NULL on error.
*
* \ingroup mesh
*/
Lib3dsMesh*
lib3ds_mesh_new(const char *name)
{
Lib3dsMesh *mesh;
ASSERT(name);
ASSERT(strlen(name)<64);
mesh=(Lib3dsMesh*)calloc(sizeof(Lib3dsMesh), 1);
if (!mesh) {
return(0);
}
strcpy(mesh->name, name);
lib3ds_matrix_identity(mesh->matrix);
mesh->map_data.maptype=LIB3DS_MAP_NONE;
return(mesh);
}
/*!
* Free a mesh object and all of its resources.
*
* \param mesh Mesh object to be freed.
*
* \ingroup mesh
*/
void
lib3ds_mesh_free(Lib3dsMesh *mesh)
{
lib3ds_mesh_free_point_list(mesh);
lib3ds_mesh_free_flag_list(mesh);
lib3ds_mesh_free_texel_list(mesh);
lib3ds_mesh_free_face_list(mesh);
memset(mesh, 0, sizeof(Lib3dsMesh));
free(mesh);
}
/*!
* Allocate point list in mesh object.
*
* This function frees the current point list, if any, and allocates
* a new one large enough to hold the specified number of points.
*
* \param mesh Mesh object for which points are to be allocated.
* \param points Number of points in the new point list.
*
* \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
*
* \ingroup mesh
*/
Lib3dsBool
lib3ds_mesh_new_point_list(Lib3dsMesh *mesh, Lib3dsDword points)
{
ASSERT(mesh);
if (mesh->pointL) {
ASSERT(mesh->points);
lib3ds_mesh_free_point_list(mesh);
}
ASSERT(!mesh->pointL && !mesh->points);
mesh->points=0;
mesh->pointL=calloc(sizeof(Lib3dsPoint)*points,1);
if (!mesh->pointL) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
mesh->points=points;
return(LIB3DS_TRUE);
}
/*!
* Free point list in mesh object.
*
* The current point list is freed and set to NULL. mesh->points is
* set to zero.
*
* \param mesh Mesh object to be modified.
*
* \ingroup mesh
*/
void
lib3ds_mesh_free_point_list(Lib3dsMesh *mesh)
{
ASSERT(mesh);
if (mesh->pointL) {
ASSERT(mesh->points);
free(mesh->pointL);
mesh->pointL=0;
mesh->points=0;
}
else {
ASSERT(!mesh->points);
}
}
/*!
* Allocate flag list in mesh object.
*
* This function frees the current flag list, if any, and allocates
* a new one large enough to hold the specified number of flags.
* All flags are initialized to 0
*
* \param mesh Mesh object for which points are to be allocated.
* \param flags Number of flags in the new flag list.
*
* \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
*
* \ingroup mesh
*/
Lib3dsBool
lib3ds_mesh_new_flag_list(Lib3dsMesh *mesh, Lib3dsDword flags)
{
ASSERT(mesh);
if (mesh->flagL) {
ASSERT(mesh->flags);
lib3ds_mesh_free_flag_list(mesh);
}
ASSERT(!mesh->flagL && !mesh->flags);
mesh->flags=0;
mesh->flagL=calloc(sizeof(Lib3dsWord)*flags,1);
if (!mesh->flagL) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
mesh->flags=flags;
return(LIB3DS_TRUE);
}
/*!
* Free flag list in mesh object.
*
* The current flag list is freed and set to NULL. mesh->flags is
* set to zero.
*
* \param mesh Mesh object to be modified.
*
* \ingroup mesh
*/
void
lib3ds_mesh_free_flag_list(Lib3dsMesh *mesh)
{
ASSERT(mesh);
if (mesh->flagL) {
ASSERT(mesh->flags);
free(mesh->flagL);
mesh->flagL=0;
mesh->flags=0;
}
else {
ASSERT(!mesh->flags);
}
}
/*!
* Allocate texel list in mesh object.
*
* This function frees the current texel list, if any, and allocates
* a new one large enough to hold the specified number of texels.
*
* \param mesh Mesh object for which points are to be allocated.
* \param texels Number of texels in the new texel list.
*
* \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
*
* \ingroup mesh
*/
Lib3dsBool
lib3ds_mesh_new_texel_list(Lib3dsMesh *mesh, Lib3dsDword texels)
{
ASSERT(mesh);
if (mesh->texelL) {
ASSERT(mesh->texels);
lib3ds_mesh_free_texel_list(mesh);
}
ASSERT(!mesh->texelL && !mesh->texels);
mesh->texels=0;
mesh->texelL=calloc(sizeof(Lib3dsTexel)*texels,1);
if (!mesh->texelL) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
mesh->texels=texels;
return(LIB3DS_TRUE);
}
/*!
* Free texel list in mesh object.
*
* The current texel list is freed and set to NULL. mesh->texels is
* set to zero.
*
* \param mesh Mesh object to be modified.
*
* \ingroup mesh
*/
void
lib3ds_mesh_free_texel_list(Lib3dsMesh *mesh)
{
ASSERT(mesh);
if (mesh->texelL) {
ASSERT(mesh->texels);
free(mesh->texelL);
mesh->texelL=0;
mesh->texels=0;
}
else {
ASSERT(!mesh->texels);
}
}
/*!
* Allocate face list in mesh object.
*
* This function frees the current face list, if any, and allocates
* a new one large enough to hold the specified number of faces.
*
* \param mesh Mesh object for which points are to be allocated.
* \param faces Number of faces in the new face list.
*
* \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
*
* \ingroup mesh
*/
Lib3dsBool
lib3ds_mesh_new_face_list(Lib3dsMesh *mesh, Lib3dsDword faces)
{
ASSERT(mesh);
if (mesh->faceL) {
ASSERT(mesh->faces);
lib3ds_mesh_free_face_list(mesh);
}
ASSERT(!mesh->faceL && !mesh->faces);
mesh->faces=0;
mesh->faceL=calloc(sizeof(Lib3dsFace)*faces,1);
if (!mesh->faceL) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
mesh->faces=faces;
return(LIB3DS_TRUE);
}
/*!
* Free face list in mesh object.
*
* The current face list is freed and set to NULL. mesh->faces is
* set to zero.
*
* \param mesh Mesh object to be modified.
*
* \ingroup mesh
*/
void
lib3ds_mesh_free_face_list(Lib3dsMesh *mesh)
{
ASSERT(mesh);
if (mesh->faceL) {
ASSERT(mesh->faces);
free(mesh->faceL);
mesh->faceL=0;
mesh->faces=0;
}
else {
ASSERT(!mesh->faces);
}
}
typedef struct _Lib3dsFaces Lib3dsFaces;
struct _Lib3dsFaces {
Lib3dsFaces *next;
Lib3dsFace *face;
};
/*!
* Find the bounding box of a mesh object.
*
* \param mesh The mesh object
* \param min Returned bounding box
* \param max Returned bounding box
*
* \ingroup mesh
*/
void
lib3ds_mesh_bounding_box(Lib3dsMesh *mesh, Lib3dsVector min, Lib3dsVector max)
{
unsigned i,j;
Lib3dsFloat v;
if (!mesh->points) {
lib3ds_vector_zero(min);
lib3ds_vector_zero(max);
return;
}
lib3ds_vector_copy(min, mesh->pointL[0].pos);
lib3ds_vector_copy(max, mesh->pointL[0].pos);
for (i=1; i<mesh->points; ++i) {
for (j=0; j<3; ++j) {
v=mesh->pointL[i].pos[j];
if (v<min[j]) {
min[j]=v;
}
if (v>max[j]) {
max[j]=v;
}
}
};
}
/*!
* Calculates the vertex normals corresponding to the smoothing group
* settings for each face of a mesh.
*
* \param mesh A pointer to the mesh to calculate the normals for.
* \param normalL A pointer to a buffer to store the calculated
* normals. The buffer must have the size:
* 3*sizeof(Lib3dsVector)*mesh->faces.
*
* To allocate the normal buffer do for example the following:
* \code
* Lib3dsVector *normalL = malloc(3*sizeof(Lib3dsVector)*mesh->faces);
* \endcode
*
* To access the normal of the i-th vertex of the j-th face do the
* following:
* \code
* normalL[3*j+i]
* \endcode
*
* \ingroup mesh
*/
void
lib3ds_mesh_calculate_normals(Lib3dsMesh *mesh, Lib3dsVector *normalL)
{
Lib3dsFaces **fl;
Lib3dsFaces *fa;
unsigned i,j,k;
if (!mesh->faces) {
return;
}
fl=calloc(sizeof(Lib3dsFaces*),mesh->points);
ASSERT(fl);
fa=calloc(sizeof(Lib3dsFaces),3*mesh->faces);
ASSERT(fa);
k=0;
for (i=0; i<mesh->faces; ++i) {
Lib3dsFace *f=&mesh->faceL[i];
for (j=0; j<3; ++j) {
Lib3dsFaces* l=&fa[k++];
ASSERT(f->points[j]<mesh->points);
l->face=f;
l->next=fl[f->points[j]];
fl[f->points[j]]=l;
}
}
for (i=0; i<mesh->faces; ++i) {
Lib3dsFace *f=&mesh->faceL[i];
for (j=0; j<3; ++j) {
// FIXME: static array needs at least check!!
Lib3dsVector n,N[128];
Lib3dsFaces *p;
int k,l;
int found;
ASSERT(f->points[j]<mesh->points);
if (f->smoothing) {
lib3ds_vector_zero(n);
k=0;
for (p=fl[f->points[j]]; p; p=p->next) {
found=0;
for (l=0; l<k; ++l) {
if( l >= 128 )
printf("array N overflow: i=%d, j=%d, k=%d\n", i,j,k);
if (fabs(lib3ds_vector_dot(N[l], p->face->normal)-1.0)<1e-5) {
found=1;
break;
}
}
if (!found) {
if (f->smoothing & p->face->smoothing) {
lib3ds_vector_add(n,n, p->face->normal);
lib3ds_vector_copy(N[k], p->face->normal);
++k;
}
}
}
}
else {
lib3ds_vector_copy(n, f->normal);
}
lib3ds_vector_normalize(n);
lib3ds_vector_copy(normalL[3*i+j], n);
}
}
free(fa);
free(fl);
}
/*!
* This function prints data associated with the specified mesh such as
* vertex and point lists.
*
* \param mesh Points to a mesh that you wish to view the data for.
*
* \return None
*
* \warning WIN32: Should only be used in a console window not in a GUI.
*
* \ingroup mesh
*/
void
lib3ds_mesh_dump(Lib3dsMesh *mesh)
{
unsigned i;
Lib3dsVector p;
ASSERT(mesh);
printf(" %s vertices=%ld faces=%ld\n",
mesh->name,
mesh->points,
mesh->faces
);
printf(" matrix:\n");
lib3ds_matrix_dump(mesh->matrix);
printf(" point list:\n");
for (i=0; i<mesh->points; ++i) {
lib3ds_vector_copy(p, mesh->pointL[i].pos);
printf (" %8f %8f %8f\n", p[0], p[1], p[2]);
}
printf(" facelist:\n");
for (i=0; i<mesh->faces; ++i) {
printf (" %4d %4d %4d smoothing:%X flags:%X material:\"%s\"\n",
mesh->faceL[i].points[0],
mesh->faceL[i].points[1],
mesh->faceL[i].points[2],
(unsigned)mesh->faceL[i].smoothing,
mesh->faceL[i].flags,
mesh->faceL[i].material
);
}
}
/*!
* \ingroup mesh
*/
Lib3dsBool
lib3ds_mesh_read(Lib3dsMesh *mesh, Lib3dsIo *io)
{
Lib3dsChunk c;
Lib3dsWord chunk;
if (!lib3ds_chunk_read_start(&c, LIB3DS_N_TRI_OBJECT, io)) {
return(LIB3DS_FALSE);
}
while ((chunk=lib3ds_chunk_read_next(&c, io))!=0) {
switch (chunk) {
case LIB3DS_MESH_MATRIX:
{
int i,j;
lib3ds_matrix_identity(mesh->matrix);
for (i=0; i<4; i++) {
for (j=0; j<3; j++) {
mesh->matrix[i][j]=lib3ds_io_read_float(io);
}
}
}
break;
case LIB3DS_MESH_COLOR:
{
mesh->color=lib3ds_io_read_byte(io);
}
break;
case LIB3DS_POINT_ARRAY:
{
unsigned i,j;
unsigned points;
lib3ds_mesh_free_point_list(mesh);
points=lib3ds_io_read_word(io);
if (points) {
if (!lib3ds_mesh_new_point_list(mesh, points)) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
for (i=0; i<mesh->points; ++i) {
for (j=0; j<3; ++j) {
mesh->pointL[i].pos[j]=lib3ds_io_read_float(io);
}
}
ASSERT((!mesh->flags) || (mesh->points==mesh->flags));
ASSERT((!mesh->texels) || (mesh->points==mesh->texels));
}
}
break;
case LIB3DS_POINT_FLAG_ARRAY:
{
unsigned i;
unsigned flags;
lib3ds_mesh_free_flag_list(mesh);
flags=lib3ds_io_read_word(io);
if (flags) {
if (!lib3ds_mesh_new_flag_list(mesh, flags)) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
for (i=0; i<mesh->flags; ++i) {
mesh->flagL[i]=lib3ds_io_read_word(io);
}
ASSERT((!mesh->points) || (mesh->flags==mesh->points));
ASSERT((!mesh->texels) || (mesh->flags==mesh->texels));
}
}
break;
case LIB3DS_FACE_ARRAY:
{
lib3ds_chunk_read_reset(&c, io);
if (!face_array_read(mesh, io)) {
return(LIB3DS_FALSE);
}
}
break;
case LIB3DS_MESH_TEXTURE_INFO:
{
int i,j;
for (i=0; i<2; ++i) {
mesh->map_data.tile[i]=lib3ds_io_read_float(io);
}
for (i=0; i<3; ++i) {
mesh->map_data.pos[i]=lib3ds_io_read_float(io);
}
mesh->map_data.scale=lib3ds_io_read_float(io);
lib3ds_matrix_identity(mesh->map_data.matrix);
for (i=0; i<4; i++) {
for (j=0; j<3; j++) {
mesh->map_data.matrix[i][j]=lib3ds_io_read_float(io);
}
}
for (i=0; i<2; ++i) {
mesh->map_data.planar_size[i]=lib3ds_io_read_float(io);
}
mesh->map_data.cylinder_height=lib3ds_io_read_float(io);
}
break;
case LIB3DS_TEX_VERTS:
{
unsigned i;
unsigned texels;
lib3ds_mesh_free_texel_list(mesh);
texels=lib3ds_io_read_word(io);
if (texels) {
if (!lib3ds_mesh_new_texel_list(mesh, texels)) {
LIB3DS_ERROR_LOG;
return(LIB3DS_FALSE);
}
for (i=0; i<mesh->texels; ++i) {
mesh->texelL[i][0]=lib3ds_io_read_float(io);
mesh->texelL[i][1]=lib3ds_io_read_float(io);
}
ASSERT((!mesh->points) || (mesh->texels==mesh->points));
ASSERT((!mesh->flags) || (mesh->texels==mesh->flags));
}
}
break;
default:
lib3ds_chunk_unknown(chunk);
}
}
{
unsigned j;
for (j=0; j<mesh->faces; ++j) {
ASSERT(mesh->faceL[j].points[0]<mesh->points);
ASSERT(mesh->faceL[j].points[1]<mesh->points);
ASSERT(mesh->faceL[j].points[2]<mesh->points);
lib3ds_vector_normal(
mesh->faceL[j].normal,
mesh->pointL[mesh->faceL[j].points[0]].pos,
mesh->pointL[mesh->faceL[j].points[1]].pos,
mesh->pointL[mesh->faceL[j].points[2]].pos
);
}
}
lib3ds_chunk_read_end(&c, io);
return(LIB3DS_TRUE);
}
static Lib3dsBool
point_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
{
Lib3dsChunk c;
unsigned i;
if (!mesh->points || !mesh->pointL) {
return(LIB3DS_TRUE);
}
ASSERT(mesh->points<0x10000);
c.chunk=LIB3DS_POINT_ARRAY;
c.size=8+12*mesh->points;
lib3ds_chunk_write(&c, io);
lib3ds_io_write_word(io, (Lib3dsWord)mesh->points);
for (i=0; i<mesh->points; ++i) {
lib3ds_io_write_vector(io, mesh->pointL[i].pos);
}
return(LIB3DS_TRUE);
}
static Lib3dsBool
flag_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
{
Lib3dsChunk c;
unsigned i;
if (!mesh->flags || !mesh->flagL) {
return(LIB3DS_TRUE);
}
ASSERT(mesh->flags<0x10000);
c.chunk=LIB3DS_POINT_FLAG_ARRAY;
c.size=8+2*mesh->flags;
lib3ds_chunk_write(&c, io);
lib3ds_io_write_word(io, (Lib3dsWord)mesh->flags);
for (i=0; i<mesh->flags; ++i) {
lib3ds_io_write_word(io, mesh->flagL[i]);
}
return(LIB3DS_TRUE);
}
static Lib3dsBool
face_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
{
Lib3dsChunk c;
if (!mesh->faces || !mesh->faceL) {
return(LIB3DS_TRUE);
}
ASSERT(mesh->faces<0x10000);
c.chunk=LIB3DS_FACE_ARRAY;
if (!lib3ds_chunk_write_start(&c, io)) {
return(LIB3DS_FALSE);
}
{
unsigned i;
lib3ds_io_write_word(io, (Lib3dsWord)mesh->faces);
for (i=0; i<mesh->faces; ++i) {
lib3ds_io_write_word(io, mesh->faceL[i].points[0]);
lib3ds_io_write_word(io, mesh->faceL[i].points[1]);
lib3ds_io_write_word(io, mesh->faceL[i].points[2]);
lib3ds_io_write_word(io, mesh->faceL[i].flags);
}
}
{ /*---- MSH_MAT_GROUP ----*/
Lib3dsChunk c;
unsigned i,j;
Lib3dsWord num;
char *matf=calloc(sizeof(char), mesh->faces);
if (!matf) {
return(LIB3DS_FALSE);
}
for (i=0; i<mesh->faces; ++i) {
if (!matf[i] && strlen(mesh->faceL[i].material)) {
matf[i]=1;
num=1;
for (j=i+1; j<mesh->faces; ++j) {
if (strcmp(mesh->faceL[i].material, mesh->faceL[j].material)==0) ++num;
}
c.chunk=LIB3DS_MSH_MAT_GROUP;
c.size=6+ strlen(mesh->faceL[i].material)+1 +2+2*num;
lib3ds_chunk_write(&c, io);
lib3ds_io_write_string(io, mesh->faceL[i].material);
lib3ds_io_write_word(io, num);
lib3ds_io_write_word(io, (Lib3dsWord)i);
for (j=i+1; j<mesh->faces; ++j) {
if (strcmp(mesh->faceL[i].material, mesh->faceL[j].material)==0) {
lib3ds_io_write_word(io, (Lib3dsWord)j);
matf[j]=1;
}
}
}
}
free(matf);
}
{ /*---- SMOOTH_GROUP ----*/
Lib3dsChunk c;
unsigned i;
c.chunk=LIB3DS_SMOOTH_GROUP;
c.size=6+4*mesh->faces;
lib3ds_chunk_write(&c, io);
for (i=0; i<mesh->faces; ++i) {
lib3ds_io_write_dword(io, mesh->faceL[i].smoothing);
}
}
{ /*---- MSH_BOXMAP ----*/
Lib3dsChunk c;
if (strlen(mesh->box_map.front) ||
strlen(mesh->box_map.back) ||
strlen(mesh->box_map.left) ||
strlen(mesh->box_map.right) ||
strlen(mesh->box_map.top) ||
strlen(mesh->box_map.bottom)) {
c.chunk=LIB3DS_MSH_BOXMAP;
if (!lib3ds_chunk_write_start(&c, io)) {
return(LIB3DS_FALSE);
}
lib3ds_io_write_string(io, mesh->box_map.front);
lib3ds_io_write_string(io, mesh->box_map.back);
lib3ds_io_write_string(io, mesh->box_map.left);
lib3ds_io_write_string(io, mesh->box_map.right);
lib3ds_io_write_string(io, mesh->box_map.top);
lib3ds_io_write_string(io, mesh->box_map.bottom);
if (!lib3ds_chunk_write_end(&c, io)) {
return(LIB3DS_FALSE);
}
}
}
if (!lib3ds_chunk_write_end(&c, io)) {
return(LIB3DS_FALSE);
}
return(LIB3DS_TRUE);
}
static Lib3dsBool
texel_array_write(Lib3dsMesh *mesh, Lib3dsIo *io)
{
Lib3dsChunk c;
unsigned i;
if (!mesh->texels || !mesh->texelL) {
return(LIB3DS_TRUE);
}
ASSERT(mesh->texels<0x10000);
c.chunk=LIB3DS_TEX_VERTS;
c.size=8+8*mesh->texels;
lib3ds_chunk_write(&c, io);
lib3ds_io_write_word(io, (Lib3dsWord)mesh->texels);
for (i=0; i<mesh->texels; ++i) {
lib3ds_io_write_float(io, mesh->texelL[i][0]);
lib3ds_io_write_float(io, mesh->texelL[i][1]);
}
return(LIB3DS_TRUE);
}
/*!
* \ingroup mesh
*/
Lib3dsBool
lib3ds_mesh_write(Lib3dsMesh *mesh, Lib3dsIo *io)
{
Lib3dsChunk c;
c.chunk=LIB3DS_N_TRI_OBJECT;
if (!lib3ds_chunk_write_start(&c,io)) {
return(LIB3DS_FALSE);
}
if (!point_array_write(mesh, io)) {
return(LIB3DS_FALSE);
}
if (!texel_array_write(mesh, io)) {
return(LIB3DS_FALSE);
}
if (mesh->map_data.maptype!=LIB3DS_MAP_NONE) { /*---- LIB3DS_MESH_TEXTURE_INFO ----*/
Lib3dsChunk c;
int i,j;
c.chunk=LIB3DS_MESH_TEXTURE_INFO;
c.size=92;
if (!lib3ds_chunk_write(&c,io)) {
return(LIB3DS_FALSE);
}
lib3ds_io_write_word(io, mesh->map_data.maptype);
for (i=0; i<2; ++i) {
lib3ds_io_write_float(io, mesh->map_data.tile[i]);
}
for (i=0; i<3; ++i) {
lib3ds_io_write_float(io, mesh->map_data.pos[i]);
}
lib3ds_io_write_float(io, mesh->map_data.scale);
for (i=0; i<4; i++) {
for (j=0; j<3; j++) {
lib3ds_io_write_float(io, mesh->map_data.matrix[i][j]);
}
}
for (i=0; i<2; ++i) {
lib3ds_io_write_float(io, mesh->map_data.planar_size[i]);
}
lib3ds_io_write_float(io, mesh->map_data.cylinder_height);
}
if (!flag_array_write(mesh, io)) {
return(LIB3DS_FALSE);
}
{ /*---- LIB3DS_MESH_MATRIX ----*/
Lib3dsChunk c;
int i,j;
c.chunk=LIB3DS_MESH_MATRIX;
c.size=54;
if (!lib3ds_chunk_write(&c,io)) {
return(LIB3DS_FALSE);
}
for (i=0; i<4; i++) {
for (j=0; j<3; j++) {
lib3ds_io_write_float(io, mesh->matrix[i][j]);
}
}
}
if (mesh->color) { /*---- LIB3DS_MESH_COLOR ----*/
Lib3dsChunk c;
c.chunk=LIB3DS_MESH_COLOR;
c.size=7;
if (!lib3ds_chunk_write(&c,io)) {
return(LIB3DS_FALSE);
}
lib3ds_io_write_byte(io, mesh->color);
}
if (!face_array_write(mesh, io)) {
return(LIB3DS_FALSE);
}
if (!lib3ds_chunk_write_end(&c,io)) {
return(LIB3DS_FALSE);
}
return(LIB3DS_TRUE);
}
/*!
\typedef Lib3dsFace
\ingroup mesh
\sa _Lib3dsFace
*/
/*!
\typedef Lib3dsBoxMap
\ingroup mesh
\sa _Lib3dsBoxMap
*/
/*!
\typedef Lib3dsMapData
\ingroup mesh
\sa _Lib3dsMapData
*/
/*!
\typedef Lib3dsMesh
\ingroup mesh
\sa _Lib3dsMesh
*/
See more files for this project here