Code Search for Developers
 
 
  

mesh.c from Boson at Krugle


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

Boson

Boson is an OpenGL real-time strategy game. It is designed to run on Unix (Linux) computers, and is built on top of the KDE, Qt and kdegames libraries.

Project homepage: http://sourceforge.net/projects/boson
Programming language(s): C,C++
License: other

  CMakeLists.txt
  atmosphere.c
  atmosphere.h
  background.c
  background.h
  camera.c
  camera.h
  chunk.c
  chunk.h
  chunktable.h
  chunktable.sed
  ease.c
  ease.h
  file.c
  file.h
  float.c
  float.h
  io.c
  io.h
  light.c
  light.h
  material.c
  material.h
  matrix.c
  matrix.h
  mesh.c
  mesh.h
  node.c
  node.h
  quat.c
  quat.h
  shadow.c
  shadow.h
  tcb.c
  tcb.h
  tracks.c
  tracks.h
  types.h
  vector.c
  vector.h
  version.h
  viewport.c
  viewport.h