Browse Source

boundary faces, matrix to list, fix tga, and now compiles (debug) with no warnings

Former-commit-id: df9a4422bace239d46870fb30b7e7f911db1dca5
jalec 13 years ago
parent
commit
f30e1c69c9
17 changed files with 873 additions and 623 deletions
  1. 5 5
      Makefile
  2. 109 0
      boundary_faces.cpp
  3. 54 0
      boundary_faces.h
  4. 15 0
      faces_first.cpp
  5. 8 2
      faces_first.h
  6. 26 0
      matrix_to_list.cpp
  7. 30 0
      matrix_to_list.h
  8. 2 2
      per_corner_normals.cpp
  9. 3 3
      read.h
  10. 7 7
      readOBJ.cpp
  11. 15 11
      readOBJ.h
  12. 11 14
      sort.cpp
  13. 6 5
      sort.h
  14. 550 0
      tga.cpp
  15. 13 561
      tga.h
  16. 9 3
      write.cpp
  17. 10 10
      writeOBJ.h

+ 5 - 5
Makefile

@@ -1,8 +1,8 @@
+all: lib examples
+
 .PHONY: all
 .PHONY: examples
 
-all: lib examples
-
 debug: lib
 
 lib: obj libigl.a
@@ -15,8 +15,8 @@ OBJ_FILES=$(addprefix obj/,$(notdir $(CPP_FILES:.cpp=.o)))
 
 # optimized default settings
 all: LFLAGS +=
-all: CFLAGS += -O3 -DNDEBUG
-debug: CFLAGS += -g
+all: CFLAGS += -O3 -DNDEBUG -Wall
+debug: CFLAGS += -g -Wall -Werror
 
 # Eigen dependency
 EIGEN3_INC=-I/usr/local/include/eigen3 -I/usr/local/include/eigen3/unsupported
@@ -34,7 +34,7 @@ libigl.a: $(OBJ_FILES)
 	rm -f $@
 	ar cqs $@ $(OBJ_FILES)
 
-obj/%.o: %.cpp
+obj/%.o: %.cpp %.h
 	g++ $(CFLAGS) -c -o $@ $< $(INC)
 
 clean:

+ 109 - 0
boundary_faces.cpp

@@ -0,0 +1,109 @@
+#include "boundary_faces.h"
+
+// IGL includes
+#include "sort.h"
+
+// STL includes
+#include <map>
+
+template <typename IntegerT, typename IntegerF>
+IGL_INLINE void igl::boundary_faces(
+  const std::vector<std::vector<IntegerT> > & T,
+  std::vector<std::vector<IntegerF> > & F)
+{
+  using namespace std;
+  using namespace Eigen;
+  using namespace igl;
+
+  // Get a list of all faces
+  vector<vector<IntegerF> > allF(T.size()*4,vector<IntegerF>(3));
+  // Gather faces, loop over tets
+  for(int i = 0; i< (int)T.size();i++)
+  {
+    assert(T[i].size() == 4);
+    // get face in correct order
+    allF[i*4+0][0] = T[i][0];
+    allF[i*4+0][1] = T[i][1];
+    allF[i*4+0][2] = T[i][2];
+    // get face in correct order
+    allF[i*4+1][0] = T[i][0];
+    allF[i*4+1][1] = T[i][2];
+    allF[i*4+1][2] = T[i][3];
+    // get face in correct order
+    allF[i*4+2][0] = T[i][0];
+    allF[i*4+2][1] = T[i][3];
+    allF[i*4+2][2] = T[i][1];
+    // get face in correct order
+    allF[i*4+3][0] = T[i][1];
+    allF[i*4+3][1] = T[i][3];
+    allF[i*4+3][2] = T[i][2];
+  }
+  // Get a list of sorted faces
+  vector<vector<IntegerF> > sortedF = allF;
+  for(int i = 0; i < (int)allF.size();i++)
+  {
+    sort(sortedF[i].begin(),sortedF[i].end());
+  }
+  // Count how many times each sorted face occurs
+  map<vector<IntegerF>,int> counts;
+  int twos = 0;
+  for(int i = 0; i < (int)sortedF.size();i++)
+  {
+    if(counts.find(sortedF[i]) == counts.end())
+    {
+      // initialize to count of 1
+      counts[sortedF[i]] = 1;
+    }else
+    {
+      // increment count
+      counts[sortedF[i]]++;
+      assert(counts[sortedF[i]] == 2);
+      // increment number of twos
+      twos++;
+    }
+  }
+
+  // Resize output to fit number of ones
+  F.resize(allF.size() - twos*2);
+  int j = 0;
+  for(int i = 0;i< (int)allF.size();i++)
+  {
+    // sorted face should definitely be in counts map
+    assert(counts.find(sortedF[i]) != counts.end());
+    if(counts[sortedF[i]] == 1)
+    {
+      assert(j<(int)F.size());
+      F[j] = allF[i];
+      j++;
+    }
+  }
+}
+
+#ifndef IGL_NO_EIGEN
+#include "list_to_matrix.h"
+#include "matrix_to_list.h"
+
+template <typename DerivedT, typename DerivedF>
+IGL_INLINE void igl::boundary_faces(
+  const Eigen::PlainObjectBase<DerivedT>& T,
+  Eigen::PlainObjectBase<DerivedF>& F)
+{
+  assert(T.cols() == 0 || T.cols() == 4);
+  using namespace std;
+  using namespace Eigen;
+  using namespace igl;
+  // Cop out: use vector of vectors version
+  vector<vector<typename Eigen::PlainObjectBase<DerivedT>::Scalar> > vT;
+  matrix_to_list(T,vT);
+  vector<vector<typename Eigen::PlainObjectBase<DerivedF>::Scalar> > vF;
+  boundary_faces(vT,vF);
+  list_to_matrix(vF,F);
+}
+#endif
+
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+template void igl::boundary_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
+

+ 54 - 0
boundary_faces.h

@@ -0,0 +1,54 @@
+#ifndef IGL_BOUNDARY_FACES_H
+#define IGL_BOUNDARY_FACES_H
+#include "igl_inline.h"
+
+#ifndef IGL_NO_EIGEN
+#  include <Eigen/Dense>
+#endif
+
+#include <vector>
+
+namespace igl
+{
+  // BOUNDARY_FACES Determine boundary faces of tetrahedra stored in T
+  //
+  // Templates:
+  //   IntegerT  integer-value: i.e. int
+  //   IntegerF  integer-value: i.e. int
+  // Input:
+  //  T  tetrahedron index list, m by 4, where m is the number of tetrahedra
+  // Output:
+  //  F  list of boundary faces, n by 3, where n is the number of boundary faces
+  //
+  // Input:
+  //  V  # vertices by 3 vertex positions
+  //  F  # faces by 3 list of face indices
+  // Output: 
+  //  RV  # vertices by 3 vertex positions, order such that if the jth vertex is
+  //    some face in F, and the kth vertex is not then j comes before k
+  //  RF  # faces by 3 list of face indices, reindexed to use RV
+  //  IM  # faces by 1 list of indices such that: RF = IM(F) and RT = IM(T)
+  //    and RV(IM,:) = V
+  //
+  template <typename IntegerT, typename IntegerF>
+  IGL_INLINE void boundary_faces(
+    const std::vector<std::vector<IntegerT> > & T,
+    std::vector<std::vector<IntegerF> > & F);
+
+#ifndef IGL_NO_EIGEN
+  // Templates:
+  //   DerivedT  integer-value: i.e. from MatrixXi
+  //   DerivedF  integer-value: i.e. from MatrixXi
+  template <typename DerivedT, typename DerivedF>
+  IGL_INLINE void boundary_faces(
+    const Eigen::PlainObjectBase<DerivedT>& T,
+    Eigen::PlainObjectBase<DerivedF>& F);
+#endif
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "boundary_faces.cpp"
+#endif
+
+#endif
+

+ 15 - 0
faces_first.cpp

@@ -74,6 +74,21 @@ IGL_INLINE void igl::faces_first(
   }
 }
 
+template <typename MatV, typename MatF, typename VecI>
+IGL_INLINE void igl::faces_first(
+  MatV & V, 
+  MatF & F, 
+  VecI & IM)
+{
+  MatV RV;
+  // Copying F may not be needed, seems RF = F is safe (whereas RV = V is not)
+  MatF RF;
+  igl::faces_first(V,F,RV,RF,IM);
+  V = RV;
+  F = RF;
+}
+
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
+template void igl::faces_first<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
 #endif

+ 8 - 2
faces_first.h

@@ -12,8 +12,8 @@ namespace igl
   //
   // Templates:
   //   MatV  matrix for vertex positions, e.g. MatrixXd
-  //   MatF  matrix for vertex positions, e.g. MatrixXi
-  //   VecI  matrix for vertex positions, e.g. VectorXi
+  //   MatF  matrix for face indices, e.g. MatrixXi
+  //   VecI  vector for index map, e.g. VectorXi
   // Input:
   //  V  # vertices by 3 vertex positions
   //  F  # faces by 3 list of face indices
@@ -31,6 +31,12 @@ namespace igl
     MatV & RV, 
     MatF & RF, 
     VecI & IM);
+  // Virtual "in place" wrapper
+  template <typename MatV, typename MatF, typename VecI>
+  IGL_INLINE void faces_first(
+    MatV & V, 
+    MatF & F, 
+    VecI & IM);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 26 - 0
matrix_to_list.cpp

@@ -0,0 +1,26 @@
+#include "matrix_to_list.h"
+
+#include <Eigen/Dense>
+
+template <typename Mat, typename T>
+IGL_INLINE void igl::matrix_to_list(
+  const Mat & M, 
+  std::vector<std::vector<T > > & V)
+{
+  using namespace std;
+  V.resize(M.rows(),vector<T >(M.cols()));
+  // loop over rows
+  for(int i = 0;i<M.rows();i++)
+  {
+    // loop over cols
+    for(int j = 0;j<M.cols();j++)
+    {
+      V[i][j] = M(i,j);
+    }
+  }
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+template void igl::matrix_to_list<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+#endif

+ 30 - 0
matrix_to_list.h

@@ -0,0 +1,30 @@
+#ifndef IGL_MATRIX_TO_LIST_H
+#define IGL_MATRIX_TO_LIST_H
+#include "igl_inline.h"
+#include <vector>
+namespace igl
+{
+  // Convert a matrix to a list (std::vector) of row vectors of the same size
+  // Template: 
+  //   Mat  Matrix type, must implement:
+  //     .resize(m,n)
+  //     .row(i) = Row
+  //   T  type that can be safely cast to type in Mat via '='
+  // Inputs:
+  //   V  a m-long list of vectors of size n
+  // Outputs:
+  //   M  an m by n matrix
+  //
+  // See also: list_to_matrix
+  template <typename Mat, typename T>
+  IGL_INLINE void matrix_to_list(
+    const Mat & M, 
+    std::vector<std::vector<T > > & V);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "matrix_to_list.cpp"
+#endif
+
+#endif
+

+ 2 - 2
per_corner_normals.cpp

@@ -43,12 +43,12 @@ IGL_INLINE void igl::per_corner_normals(
   CN.resize(m*n,3);
 
   // loop over faces
-  for(size_t i = 0;i<m;i++)
+  for(size_t i = 0;int(i)<m;i++)
   {
     // Normal of this face
     Eigen::Matrix<typename DerivedV::Scalar,3,1> fn = FN.row(i);
     // loop over corners
-    for(size_t j = 0;j<n;j++)
+    for(size_t j = 0;int(j)<n;j++)
     {
       const std::vector<IndexType> &incident_faces = VF[F(i,j)];
       // loop over faces sharing vertex of this corner

+ 3 - 3
read.h

@@ -24,9 +24,9 @@ namespace igl
   //   F  eigen int matrix #F by 3
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE bool read(
-                       const std::string str,
-                       Eigen::PlainObjectBase<DerivedV>& V,
-                       Eigen::PlainObjectBase<DerivedF>& F);
+    const std::string str,
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedF>& F);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 7 - 7
readOBJ.cpp

@@ -199,13 +199,13 @@ IGL_INLINE bool igl::readOBJ(
 
 template <typename DerivedV, typename DerivedF, typename DerivedT>
 IGL_INLINE bool igl::readOBJ(
-                             const std::string str,
-                             Eigen::PlainObjectBase<DerivedV>& V,
-                             Eigen::PlainObjectBase<DerivedF>& F,
-                             Eigen::PlainObjectBase<DerivedV>& CN,
-                             Eigen::PlainObjectBase<DerivedF>& FN,
-                             Eigen::PlainObjectBase<DerivedT>& TC,
-                             Eigen::PlainObjectBase<DerivedF>& FTC)
+  const std::string str,
+  Eigen::PlainObjectBase<DerivedV>& V,
+  Eigen::PlainObjectBase<DerivedF>& F,
+  Eigen::PlainObjectBase<DerivedV>& CN,
+  Eigen::PlainObjectBase<DerivedF>& FN,
+  Eigen::PlainObjectBase<DerivedT>& TC,
+  Eigen::PlainObjectBase<DerivedF>& FTC)
 {
   std::vector<std::vector<double> > vV,vTC,vN;
   std::vector<std::vector<int> > vF,vFTC,vFN;

+ 15 - 11
readOBJ.h

@@ -12,7 +12,9 @@
 #define IGL_READOBJ_H
 #include "igl_inline.h"
 
-#include <Eigen/Core>
+#ifndef IGL_NO_EIGEN
+#  include <Eigen/Core>
+#endif
 #include <string>
 #include <vector>
 
@@ -45,6 +47,7 @@ namespace igl
     std::vector<std::vector<Index > > & FTC,
     std::vector<std::vector<Index > > & FN);
 
+#ifndef IGL_NO_EIGEN
   //! Read a mesh from an ascii obj file
   // Inputs:
   //   str  path to .obj file
@@ -59,13 +62,13 @@ namespace igl
   // indices. It will probably crash or give garbage on anything else.
   template <typename DerivedV, typename DerivedF, typename DerivedT>
   IGL_INLINE bool readOBJ(
-                          const std::string str,
-                          Eigen::PlainObjectBase<DerivedV>& V,
-                          Eigen::PlainObjectBase<DerivedF>& F,
-                          Eigen::PlainObjectBase<DerivedV>& CN,
-                          Eigen::PlainObjectBase<DerivedF>& FN,
-                          Eigen::PlainObjectBase<DerivedT>& TC,
-                          Eigen::PlainObjectBase<DerivedF>& FTC);
+    const std::string str,
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedF>& F,
+    Eigen::PlainObjectBase<DerivedV>& CN,
+    Eigen::PlainObjectBase<DerivedF>& FN,
+    Eigen::PlainObjectBase<DerivedT>& TC,
+    Eigen::PlainObjectBase<DerivedF>& FTC);
 
   //! Read a mesh from an ascii obj file
   // Inputs:
@@ -81,9 +84,10 @@ namespace igl
   // indices. It will probably crash or give garbage on anything else.
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE bool readOBJ(
-                          const std::string str,
-                          Eigen::PlainObjectBase<DerivedV>& V,
-                          Eigen::PlainObjectBase<DerivedF>& F);
+    const std::string str,
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedF>& F);
+#endif
 
 }
 

+ 11 - 14
sort.cpp

@@ -3,14 +3,15 @@
 #include <algorithm>
 #include "reorder.h"
 
-template <typename T>
+template <typename DerivedX, typename DerivedIX>
 IGL_INLINE void igl::sort(
-  const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
+  const Eigen::PlainObjectBase<DerivedX>& X,
   const int dim,
   const bool ascending,
-  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Y,
-  Eigen::MatrixXi & IX)
+  Eigen::PlainObjectBase<DerivedX>& Y,
+  Eigen::PlainObjectBase<DerivedIX>& IX)
 {
+  using namespace Eigen;
   // dim must be 2 or 1
   assert(dim == 1 || dim == 2);
   // Resize output
@@ -26,23 +27,19 @@ IGL_INLINE void igl::sort(
   {
     // Unsorted index map for this column (or row)
     std::vector<size_t> index_map(num_inner);
-    std::vector<T> data(num_inner);
+    std::vector<double> data(num_inner);
     for(int j = 0;j<num_inner;j++)
     {
       if(dim == 1)
       {
-        data[j] = X(j,i);
+        data[j] = (double) X(j,i);
       }else
       {
-        data[j] = X(i,j);
+        data[j] = (double) X(i,j);
       }
     }
     // sort this column (or row)
-    sort<T>(
-      data,
-      ascending,
-      data,
-      index_map);
+    igl::sort( data, ascending, data, index_map);
     // Copy into Y and IX
     for(int j = 0;j<num_inner;j++)
     {
@@ -87,7 +84,7 @@ IGL_INLINE void igl::sort(
     index_map[i] = i;
   }
   // Sort the index map, using unsorted for comparison
-  sort(
+  std::sort(
     index_map.begin(),
     index_map.end(),
     igl::index_cmp<const std::vector<T>& >(unsorted));
@@ -106,5 +103,5 @@ IGL_INLINE void igl::sort(
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
 // generated by autoexplicit.sh
-template void igl::sort<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, bool, Eigen::Matrix<double, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
+template void igl::sort<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 6 - 5
sort.h

@@ -11,7 +11,8 @@ namespace igl
   // function
   //
   // Templates:
-  //   T  should be a eigen matrix primitive type like int or double
+  //   DerivedX derived scalar type, e.g. MatrixXi or MatrixXd
+  //   DerivedIX derived integer type, e.g. MatrixXi
   // Inputs:
   //   X  m by n matrix whose entries are to be sorted
   //   dim  dimensional along which to sort:
@@ -22,13 +23,13 @@ namespace igl
   //   Y  m by n matrix whose entries are sorted
   //   IX  m by n matrix of indices so that if dim = 1, then in matlab notation
   //     for j = 1:n, Y(:,j) = X(I(:,j),j); end
-  template <typename T>
+  template <typename DerivedX, typename DerivedIX>
   IGL_INLINE void sort(
-    const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
+    const Eigen::PlainObjectBase<DerivedX>& X,
     const int dim,
     const bool ascending,
-    Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Y,
-    Eigen::MatrixXi & IX);
+    Eigen::PlainObjectBase<DerivedX>& Y,
+    Eigen::PlainObjectBase<DerivedIX>& IX);
 
   // Act like matlab's [Y,I] = SORT(X) for std library vectors
   // Templates:

+ 550 - 0
tga.cpp

@@ -0,0 +1,550 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// WARNING
+//
+// THIS DOES NOT DEAL WITH VERTICALLY FLIPPED DATA CORRECTLY
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/* This file is derived from (actually an earlier version of)... */
+
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * $Id: tga.cpp,v 1.1.2.5 2007-05-10 02:10:07 elif Exp $
+ * TrueVision Targa loading and saving file filter for the Gimp.
+ * Targa code Copyright (C) 1997 Raphael FRANCOIS and Gordon Matzigkeit
+ *
+ * The Targa reading and writing code was written from scratch by
+ * Raphael FRANCOIS <fraph@ibm.net> and Gordon Matzigkeit
+ * <gord@gnu.ai.mit.edu> based on the TrueVision TGA File Format
+ * Specification, Version 2.0:
+ *
+ *   <URL:ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/>
+ *
+ * It does not contain any code written for other TGA file loaders.
+ * Not even the RLE handling. ;)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "tga.h"
+
+
+static char error[256];
+static unsigned int _verbose = 0;
+static int totbytes = 0;
+
+typedef struct {
+  unsigned char *statebuf;
+  int statelen;
+  int laststate;
+} RLEstate;
+
+static int
+std_fread(RLEstate *rleInfo, unsigned char *buf, size_t datasize, size_t nelems, FILE *fp)
+{
+  if (_verbose > 1) {
+    totbytes += nelems * datasize;
+    printf("TGA: std_fread %d (total %d)\n",
+      (int)(nelems * datasize), totbytes);
+  }
+  return fread(buf, datasize, nelems, fp);
+}
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define RLE_PACKETSIZE 0x80
+
+/* Decode a bufferful of file. */
+static int
+rle_fread(RLEstate *rleInfo, unsigned char *vbuf, size_t datasize, size_t nelems, FILE *fp)
+{
+
+  unsigned char *buf = vbuf;
+  int j, k;
+  int buflen, count, bytes, curbytes;
+  unsigned char *p;
+
+  /* Scale the buffer length. */
+  buflen = nelems * datasize;
+
+  j = 0;
+  curbytes = totbytes;
+  while (j < buflen) {
+    if (rleInfo->laststate < rleInfo->statelen) {
+      /* Copy bytes from our previously decoded buffer. */
+      bytes = MIN(buflen - j, rleInfo->statelen - rleInfo->laststate);
+      memcpy(buf + j, rleInfo->statebuf + rleInfo->laststate, bytes);
+      j += bytes;
+      rleInfo->laststate += bytes;
+
+      /* If we used up all of our state bytes, then reset them. */
+      if (rleInfo->laststate >= rleInfo->statelen) {
+        rleInfo->laststate = 0;
+        rleInfo->statelen = 0;
+      }
+
+      /* If we filled the buffer, then exit the loop. */
+      if (j >= buflen) break;
+    }
+
+    /* Decode the next packet. */
+    count = fgetc(fp);
+    if (count == EOF) {
+      if (_verbose) printf("TGA: hit EOF while looking for count\n");
+      return j / datasize;
+    }
+
+    /* Scale the byte length to the size of the data. */
+    bytes = ((count & ~RLE_PACKETSIZE) + 1) * datasize;
+
+    if (j + bytes <= buflen) {
+      /* We can copy directly into the image buffer. */
+      p = buf + j;
+    } else {
+#ifdef PROFILE
+      printf("TGA: needed to use statebuf for %d bytes\n", buflen - j);
+#endif
+      /* Allocate the state buffer if we haven't already. */
+      if (!rleInfo->statebuf) {
+        rleInfo->statebuf = (unsigned char *) malloc(RLE_PACKETSIZE * datasize);
+      }
+      p = rleInfo->statebuf;
+    }
+
+    if (count & RLE_PACKETSIZE) {
+      /* Fill the buffer with the next value. */
+      if (fread(p, datasize, 1, fp) != 1) {
+        if (_verbose) {
+          printf("TGA: EOF while reading %d/%d element RLE packet\n",
+            bytes, (int)datasize);
+        }
+        return j / datasize;
+      }
+
+      /* Optimized case for single-byte encoded data. */
+      if (datasize == 1) {
+        memset(p + 1, *p, bytes - 1);
+      } else {
+        for (k = datasize; k < bytes; k += datasize) {
+          memcpy(p + k, p, datasize);
+        }
+      }
+    } else {
+      /* Read in the buffer. */
+      if (fread(p, bytes, 1, fp) != 1) {
+        if (_verbose) {
+          printf("TGA: EOF while reading %d/%d element raw packet\n",
+            bytes, (int)datasize);
+        }
+        return j / datasize;
+      }
+    }
+
+    if (_verbose > 1) {
+      totbytes += bytes;
+      if (_verbose > 2) {
+        printf("TGA: %s packet %d/%d\n",
+          (count & RLE_PACKETSIZE) ? "RLE" : "raw",
+          bytes, totbytes);
+      }
+    }
+
+    /* We may need to copy bytes from the state buffer. */
+    if (p == rleInfo->statebuf) {
+      rleInfo->statelen = bytes;
+    } else {
+      j += bytes;
+    }
+  }
+
+  if (_verbose > 1) {
+    printf("TGA: rle_fread %d/%d (total %d)\n",
+    (int) ( nelems * datasize), totbytes - curbytes, totbytes);
+  }
+  return nelems;
+}
+
+igl::gliGenericImage *
+igl::gliReadTGA(FILE *fp, char *name, int hflip, int vflip)
+{
+  igl::TgaHeader tgaHeader;
+  igl::TgaFooter tgaFooter;
+  char horzrev, vertrev;
+  int width, height, bpp;
+  int start, end, dir;
+  int i, j, k;
+  int pelbytes, wbytes;
+  GLenum format;
+  int components;
+  RLEstate rleRec;
+  RLEstate *rleInfo;
+  int rle;
+  int index, colors, length;
+  GLubyte *cmap, *pixels, *data;
+  int (*myfread)(RLEstate *rleInfo, unsigned char*, size_t, size_t, FILE*);
+  igl::gliGenericImage *genericImage;
+
+  /* Check the footer. */
+  if (fseek(fp, 0L - sizeof(tgaFooter), SEEK_END)
+      || fread(&tgaFooter, sizeof(tgaFooter), 1, fp) != 1) {
+    sprintf(error, "TGA: Cannot read footer from \"%s\"", name);
+    if (_verbose) printf("%s\n", error);
+    return NULL;
+  }  
+
+  /* Check the signature. */
+  if (memcmp(tgaFooter.signature, TGA_SIGNATURE,
+             sizeof(tgaFooter.signature)) == 0) {
+    if (_verbose) printf("TGA: found New TGA\n");
+  } else {
+    if (_verbose) printf("TGA: found Original TGA\n");
+  }
+
+  if (fseek(fp, 0, SEEK_SET) ||
+      fread(&tgaHeader, sizeof(tgaHeader), 1, fp) != 1) {
+    sprintf(error, "TGA: Cannot read header from \"%s\"", name);
+    if (_verbose) printf("%s\n", error);
+    return NULL;
+  }
+
+  if (_verbose && tgaHeader.idLength) {
+    char *idString = (char*) malloc(tgaHeader.idLength);
+    
+    if (fread(idString, tgaHeader.idLength, 1, fp) != 1) {
+      sprintf(error, "TGA: Cannot read ID field in \"%s\"", name);
+      printf("%s\n", error);
+    } else {
+      printf("TGA: ID field: \"%*s\"\n", tgaHeader.idLength, idString);
+    }
+    free(idString);
+  } else {
+    /* Skip the image ID field. */
+    if (tgaHeader.idLength && fseek(fp, tgaHeader.idLength, SEEK_CUR)) {
+      sprintf(error, "TGA: Cannot skip ID field in \"%s\"", name);
+      if (_verbose) printf("%s\n", error);
+      return NULL;
+    }
+  }
+  
+  /* Reassemble the multi-byte values correctly, regardless of
+     host endianness. */
+  width = (tgaHeader.widthHi << 8) | tgaHeader.widthLo;
+  height = (tgaHeader.heightHi << 8) | tgaHeader.heightLo;
+  bpp = tgaHeader.bpp;
+  if (_verbose) {
+    printf("TGA: width=%d, height=%d, bpp=%d\n", width, height, bpp);
+  }
+
+  horzrev = tgaHeader.descriptor & TGA_DESC_HORIZONTAL;
+  vertrev = tgaHeader.descriptor & TGA_DESC_VERTICAL;
+  //vertrev=0;
+
+//   // JASON - we can force this stuff if we want
+//   if( hflip )
+//       horzrev = 1;
+  if( vflip )
+      vertrev = 1;
+
+  if (_verbose && horzrev) printf("TGA: horizontal reversed\n");
+  if (_verbose && vertrev) printf("TGA: vertical reversed\n");
+
+  rle = 0;
+  switch (tgaHeader.imageType) {
+  case TGA_TYPE_MAPPED_RLE:
+    rle = 1;
+    if (_verbose) printf("TGA: run-length encoded\n");
+  case TGA_TYPE_MAPPED:
+    /* Test for alpha channel. */
+    format = GL_COLOR_INDEX;
+    components = 1;
+    if (_verbose) {
+      printf("TGA: %d bit indexed image (%d bit palette)\n",
+        tgaHeader.colorMapSize, bpp);
+    }
+    break;
+
+  case TGA_TYPE_GRAY_RLE:
+    rle = 1;
+    if (_verbose) printf("TGA: run-length encoded\n");
+  case TGA_TYPE_GRAY:
+    format = GL_LUMINANCE;
+    components = 1;
+    if (_verbose) printf("TGA: %d bit grayscale image\n", bpp);
+    break;
+
+  case TGA_TYPE_COLOR_RLE:
+    rle = 1;
+    if (_verbose) printf("TGA: run-length encoded\n");
+  case TGA_TYPE_COLOR:
+    /* Test for alpha channel. */
+    if (bpp == 32) {
+      format = GL_BGRA_EXT;
+      components = 4;
+      if (_verbose) {
+        printf("TGA: %d bit color image with alpha channel\n", bpp);
+      }
+    } else {
+      format = GL_BGR_EXT;
+      components = 3;
+      if (_verbose) printf("TGA: %d bit color image\n", bpp);
+    }
+    break;
+
+  default:
+    sprintf(error,
+      "TGA: unrecognized image type %d\n", tgaHeader.imageType);
+    if (_verbose) printf("%s\n", error);
+    return NULL;
+  }
+
+  if ((format == GL_BGRA_EXT && bpp != 32) ||
+      (format == GL_BGR_EXT && bpp != 24) ||
+      ((format == GL_LUMINANCE || format == GL_COLOR_INDEX) && bpp != 8)) {
+    /* FIXME: We haven't implemented bit-packed fields yet. */
+    fprintf(stderr, "bpp %d, format %x\n", bpp, (unsigned int)format); 
+    sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
+    if (_verbose) printf("%s\n", error);
+    return NULL;
+  }
+
+  /* Check that we have a color map only when we need it. */
+  if (format == GL_COLOR_INDEX) {
+    if (tgaHeader.colorMapType != 1) {
+      sprintf(error, "TGA: indexed image has invalid color map type %d\n",
+        tgaHeader.colorMapType);
+      if (_verbose) printf("%s\n", error);
+      return NULL;
+    }
+  } else if (tgaHeader.colorMapType != 0) {
+    sprintf(error, "TGA: non-indexed image has invalid color map type %d\n",
+      tgaHeader.colorMapType);
+    if (_verbose) printf("%s\n", error);
+    return NULL;
+  }
+
+  if (tgaHeader.colorMapType == 1) {
+    /* We need to read in the colormap. */
+    index = (tgaHeader.colorMapIndexHi << 8) | tgaHeader.colorMapIndexLo;
+    length = (tgaHeader.colorMapLengthHi << 8) | tgaHeader.colorMapLengthLo;
+
+    if (_verbose) {
+      printf("TGA: reading color map (%d + %d) * (%d / 8)\n",
+        index, length, tgaHeader.colorMapSize);
+    }
+    if (length == 0) {
+      sprintf(error, "TGA: invalid color map length %d", length);
+      if (_verbose) printf("%s\n", error);
+      return NULL;
+    }
+    if (tgaHeader.colorMapSize != 24) {
+      /* We haven't implemented bit-packed fields yet. */
+      sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
+      if (_verbose) printf("%s\n", error);
+      return NULL;
+    }
+
+    pelbytes = tgaHeader.colorMapSize / 8;
+    colors = length + index;
+    cmap = (GLubyte*)malloc (colors * pelbytes);
+
+    /* Zero the entries up to the beginning of the map. */
+    memset(cmap, 0, index * pelbytes);
+
+    /* Read in the rest of the colormap. */
+    if (fread(cmap, pelbytes, length, fp) != (size_t) length) {
+      sprintf(error, "TGA: error reading colormap (ftell == %ld)\n",
+        ftell (fp));
+      if (_verbose) printf("%s\n", error);
+      return NULL;
+    }
+
+    if (pelbytes >= 3) {
+      /* Rearrange the colors from BGR to RGB. */
+      int tmp;
+      for (j = index; j < length * pelbytes; j += pelbytes) {
+        tmp = cmap[j];
+        cmap[j] = cmap[j + 2];
+        cmap[j + 2] = tmp;
+      }
+    }
+  } else {
+    colors = 0;
+    cmap = NULL;
+  }
+
+  /* Allocate the data. */
+  pelbytes = bpp / 8;
+  pixels = (unsigned char *) malloc (width * height * pelbytes);
+
+  if (rle) {
+    rleRec.statebuf = 0;
+    rleRec.statelen = 0;
+    rleRec.laststate = 0;
+    rleInfo = &rleRec;
+    myfread = rle_fread;
+  } else {
+    rleInfo = NULL;
+    myfread = std_fread;
+  }
+
+  wbytes = width * pelbytes;
+
+  if (vertrev) {
+    start = 0;
+    end = height;
+    dir = 1;
+  } else {
+    /* We need to reverse loading order of rows. */
+    start = height-1;
+    end = -1;
+    dir = -1;
+  }
+
+  for (i = start; i != end; i += dir) {
+    data = pixels + i*wbytes;
+
+    /* Suck in the data one row at a time. */
+    if (myfread(rleInfo, data, pelbytes, width, fp) != width) {
+      /* Probably premature end of file. */
+      if (_verbose) {
+        printf ("TGA: error reading (ftell == %ld, width=%d)\n",
+          ftell(fp), width);
+      }
+      return NULL;
+    }  
+
+    if (horzrev) {
+      /* We need to mirror row horizontally. */
+      for (j = 0; j < width/2; j++) {
+        GLubyte tmp;
+
+        for (k = 0; k < pelbytes; k++) {
+          tmp = data[j*pelbytes+k];
+          data[j*pelbytes+k] = data[(width-j-1)*pelbytes+k];
+          data[(width-j-1)*pelbytes+k] = tmp;
+        }
+      }
+    }
+  }
+
+  if (rle) {
+    free(rleInfo->statebuf);
+  }
+
+  if (fgetc (fp) != EOF) {
+    if (_verbose) printf ("TGA: too much input data, ignoring extra...\n");
+  }
+
+  genericImage = (igl::gliGenericImage*) malloc(sizeof(igl::gliGenericImage));
+  genericImage->width = width;
+  genericImage->height = height;
+  genericImage->format = format;
+  genericImage->components = components;
+  genericImage->cmapEntries = colors;
+  genericImage->cmapFormat = GL_BGR_EXT;  // XXX fix me
+  genericImage->cmap = cmap;
+  genericImage->pixels = pixels;
+
+  return genericImage;
+}
+
+int igl::gli_verbose(int new_verbose)
+{
+  _verbose = new_verbose;
+  return _verbose;
+}
+
+
+
+// added 10/2005, Denis Zorin
+// a very simple TGA output, supporting 
+// uncompressed luminance RGB and RGBA 
+// G22.2270 students: this is C (no C++) 
+// so this is not the style I would encourage
+// you to use; I used it for consistency 
+// with the rest of the code in this file 
+
+
+// fixed header values for the subset of TGA we use for writing
+unsigned char TGAHeaderColor[12] = 
+  { 0,// 0 ID length = no id
+    0,// 1 color map type = no color map
+    2,// 2 image type = uncompressed true color
+    0, 0, 0, 0, 0,// color map spec = empty
+    0, 0,  // x origin of image 
+    0, 0   // y origin of image
+  };
+
+unsigned char TGAHeaderBW[12] = 
+  { 0,// 0 ID length = no id
+    0,// 1 color map type = no color map
+    3,// 3 image type = uncompressed black and white
+    0, 0, 0, 0, 0,// color map spec = empty
+    0, 0,  // x origin of image 
+    0, 0   // y origin of image
+  };
+
+// this makes sure that 
+// image size is written in correct format 
+// and byte order (least first)
+void write16bit(int n, FILE* fp) { 
+  unsigned char bytes[] = { n % 256, n / 256 };
+  fwrite(bytes, 2, sizeof(unsigned char),fp);
+}
+
+
+
+void igl::writeTGA( igl::gliGenericImage* image, FILE *fp) {
+
+  assert(!image->cmap); // we do not deal with color map images
+    
+  if(image->components == 3 || image->components == 4) 
+    fwrite(TGAHeaderColor, 12, sizeof(unsigned char),fp);
+  else { 
+    if(image->components == 1 ) 
+      fwrite(TGAHeaderBW, 12, sizeof(unsigned char),fp);        
+    else { fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); }
+  }
+
+  write16bit(image->width,fp);  
+  write16bit(image->height,fp);  
+  switch (image->components ) { 
+  case 1: 
+    putc(8,fp);
+    break;
+  case 3: 
+    putc(24,fp); 
+    break;
+  case 4:
+    putc(32,fp);
+    break;
+  default: fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); 
+  };
+  
+  if(image-> components == 4) 
+    putc(0x04,fp); // bottom left image (0x00) + 8 bit alpha (0x4)
+  else 
+    putc(0x00,fp);
+
+  fwrite(image->pixels, image->height*image->width*image->components, sizeof(char),fp);
+}
+

+ 13 - 561
tga.h

@@ -1,64 +1,15 @@
 #ifndef IGL_TGA_H
 #define IGL_TGA_H
-#pragma once
 
-// interface for TrueVision (TGA) image file loader
-//
-
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// WARNING
-//
-// THIS DOES NOT DEAL WITH VERTICALLY FLIPPED DATA CORRECTLY
-//
-////////////////////////////////////////////////////////////////////////////////
-
-/* This file is derived from (actually an earlier version of)... */
-
-/* The GIMP -- an image manipulation program
- * Copyright (C) 1995 Spencer Kimball and Peter Mattis
- *
- * $Id: tga.cpp,v 1.1.2.5 2007-05-10 02:10:07 elif Exp $
- * TrueVision Targa loading and saving file filter for the Gimp.
- * Targa code Copyright (C) 1997 Raphael FRANCOIS and Gordon Matzigkeit
- *
- * The Targa reading and writing code was written from scratch by
- * Raphael FRANCOIS <fraph@ibm.net> and Gordon Matzigkeit
- * <gord@gnu.ai.mit.edu> based on the TrueVision TGA File Format
- * Specification, Version 2.0:
- *
- *   <URL:ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/>
- *
- * It does not contain any code written for other TGA file loaders.
- * Not even the RLE handling. ;)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
+/* tga.h - interface for TrueVision (TGA) image file loader */
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <iostream>
 
-#if defined(_WIN32) || defined(_WIN64)
+#ifdef _WIN32
 #include <windows.h>
 #endif
 
-#if defined(__APPLE__) || defined(__MACH__)
+#ifdef __APPLE__
 #include <OpenGL/gl.h>
 #include <GLUT/glut.h>
 #else
@@ -66,13 +17,8 @@
 #include <GL/glut.h>
 #endif
 
-
-// wrap everything in a namespace and expose read_tga function and Image type only
-
-namespace igl{
-
-////////////////////////////////////////////////////////////////////
-// declaration
+namespace igl
+{
 
 typedef struct {
 
@@ -140,512 +86,18 @@ typedef struct {
   char null;
 } TgaFooter;
 
+extern gliGenericImage *gliReadTGA(FILE *fp, char *name, int hflip, int vflip);
+int gli_verbose(int new_verbose);
+extern int gliVerbose(int newVerbose);
 
+void writeTGA( gliGenericImage* image, FILE *fp);
 
-//////////////////////////////////////////////////////////////////////////////////////////
-// implementation
-
-
-static char error[256];
-static unsigned int _verbose = 0;
-static int totbytes = 0;
-
-typedef struct {
-  unsigned char *statebuf;
-  int statelen;
-  int laststate;
-} RLEstate;
-
-static int
-std_fread(RLEstate *rleInfo, unsigned char *buf, size_t datasize, size_t nelems, FILE *fp)
-{
-  if (_verbose > 1) {
-    totbytes += nelems * datasize;
-    printf("TGA: std_fread %d (total %d)\n",
-      (int)(nelems * datasize), totbytes);
-  }
-  return fread(buf, datasize, nelems, fp);
-}
-
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-
-#define RLE_PACKETSIZE 0x80
-
-/* Decode a bufferful of file. */
-static int
-rle_fread(RLEstate *rleInfo, unsigned char *vbuf, size_t datasize, size_t nelems, FILE *fp)
-{
-
-  unsigned char *buf = vbuf;
-  int j, k;
-  int buflen, count, bytes, curbytes;
-  unsigned char *p;
-
-  /* Scale the buffer length. */
-  buflen = nelems * datasize;
-
-  j = 0;
-  curbytes = totbytes;
-  while (j < buflen) {
-    if (rleInfo->laststate < rleInfo->statelen) {
-      /* Copy bytes from our previously decoded buffer. */
-      bytes = MIN(buflen - j, rleInfo->statelen - rleInfo->laststate);
-      memcpy(buf + j, rleInfo->statebuf + rleInfo->laststate, bytes);
-      j += bytes;
-      rleInfo->laststate += bytes;
-
-      /* If we used up all of our state bytes, then reset them. */
-      if (rleInfo->laststate >= rleInfo->statelen) {
-        rleInfo->laststate = 0;
-        rleInfo->statelen = 0;
-      }
-
-      /* If we filled the buffer, then exit the loop. */
-      if (j >= buflen) break;
-    }
 
-    /* Decode the next packet. */
-    count = fgetc(fp);
-    if (count == EOF) {
-      if (_verbose) printf("TGA: hit EOF while looking for count\n");
-      return j / datasize;
-    }
 
-    /* Scale the byte length to the size of the data. */
-    bytes = ((count & ~RLE_PACKETSIZE) + 1) * datasize;
+} // end of igl namespace
 
-    if (j + bytes <= buflen) {
-      /* We can copy directly into the image buffer. */
-      p = buf + j;
-    } else {
-#ifdef PROFILE
-      printf("TGA: needed to use statebuf for %d bytes\n", buflen - j);
+#ifdef IGL_HEADER_ONLY
+#  include "tga.cpp"
 #endif
-      /* Allocate the state buffer if we haven't already. */
-      if (!rleInfo->statebuf) {
-        rleInfo->statebuf = (unsigned char *) malloc(RLE_PACKETSIZE * datasize);
-      }
-      p = rleInfo->statebuf;
-    }
-
-    if (count & RLE_PACKETSIZE) {
-      /* Fill the buffer with the next value. */
-      if (fread(p, datasize, 1, fp) != 1) {
-        if (_verbose) {
-          printf("TGA: EOF while reading %d/%d element RLE packet\n",
-            bytes, (int)datasize);
-        }
-        return j / datasize;
-      }
-
-      /* Optimized case for single-byte encoded data. */
-      if (datasize == 1) {
-        memset(p + 1, *p, bytes - 1);
-      } else {
-        for (k = datasize; k < bytes; k += datasize) {
-          memcpy(p + k, p, datasize);
-        }
-      }
-    } else {
-      /* Read in the buffer. */
-      if (fread(p, bytes, 1, fp) != 1) {
-        if (_verbose) {
-          printf("TGA: EOF while reading %d/%d element raw packet\n",
-            bytes, (int)datasize);
-        }
-        return j / datasize;
-      }
-    }
-
-    if (_verbose > 1) {
-      totbytes += bytes;
-      if (_verbose > 2) {
-        printf("TGA: %s packet %d/%d\n",
-          (count & RLE_PACKETSIZE) ? "RLE" : "raw",
-          bytes, totbytes);
-      }
-    }
-
-    /* We may need to copy bytes from the state buffer. */
-    if (p == rleInfo->statebuf) {
-      rleInfo->statelen = bytes;
-    } else {
-      j += bytes;
-    }
-  }
-
-  if (_verbose > 1) {
-    printf("TGA: rle_fread %d/%d (total %d)\n",
-    (int) ( nelems * datasize), totbytes - curbytes, totbytes);
-  }
-  return nelems;
-}
-
-static gliGenericImage *
-gliReadTGA(FILE *fp, const char *name, int hflip, int vflip)
-{
-  TgaHeader tgaHeader;
-  TgaFooter tgaFooter;
-  char horzrev, vertrev;
-  int width, height, bpp;
-  int start, end, dir;
-  int i, j, k;
-  int pelbytes, wbytes;
-  GLenum format;
-  int components;
-  RLEstate rleRec;
-  RLEstate *rleInfo;
-  int rle;
-  int index, colors, length;
-  GLubyte *cmap, *pixels, *data;
-  int (*myfread)(RLEstate *rleInfo, unsigned char*, size_t, size_t, FILE*);
-  gliGenericImage *genericImage;
-
-  /* Check the footer. */
-  if (fseek(fp, 0L - sizeof(tgaFooter), SEEK_END)
-      || fread(&tgaFooter, sizeof(tgaFooter), 1, fp) != 1) {
-    sprintf(error, "TGA: Cannot read footer from \"%s\"", name);
-    if (_verbose) printf("%s\n", error);
-    return NULL;
-  }  
-
-  /* Check the signature. */
-  if (memcmp(tgaFooter.signature, TGA_SIGNATURE,
-             sizeof(tgaFooter.signature)) == 0) {
-    if (_verbose) printf("TGA: found New TGA\n");
-  } else {
-    if (_verbose) printf("TGA: found Original TGA\n");
-  }
-
-  if (fseek(fp, 0, SEEK_SET) ||
-      fread(&tgaHeader, sizeof(tgaHeader), 1, fp) != 1) {
-    sprintf(error, "TGA: Cannot read header from \"%s\"", name);
-    if (_verbose) printf("%s\n", error);
-    return NULL;
-  }
-
-  if (_verbose && tgaHeader.idLength) {
-    char *idString = (char*) malloc(tgaHeader.idLength);
-    
-    if (fread(idString, tgaHeader.idLength, 1, fp) != 1) {
-      sprintf(error, "TGA: Cannot read ID field in \"%s\"", name);
-      printf("%s\n", error);
-    } else {
-      printf("TGA: ID field: \"%*s\"\n", tgaHeader.idLength, idString);
-    }
-    free(idString);
-  } else {
-    /* Skip the image ID field. */
-    if (tgaHeader.idLength && fseek(fp, tgaHeader.idLength, SEEK_CUR)) {
-      sprintf(error, "TGA: Cannot skip ID field in \"%s\"", name);
-      if (_verbose) printf("%s\n", error);
-      return NULL;
-    }
-  }
-  
-  /* Reassemble the multi-byte values correctly, regardless of
-     host endianness. */
-  width = (tgaHeader.widthHi << 8) | tgaHeader.widthLo;
-  height = (tgaHeader.heightHi << 8) | tgaHeader.heightLo;
-  bpp = tgaHeader.bpp;
-  if (_verbose) {
-    printf("TGA: width=%d, height=%d, bpp=%d\n", width, height, bpp);
-  }
-
-  horzrev = tgaHeader.descriptor & TGA_DESC_HORIZONTAL;
-  vertrev = tgaHeader.descriptor & TGA_DESC_VERTICAL;
-  //vertrev=0;
-
-//   // JASON - we can force this stuff if we want
-//   if( hflip )
-//       horzrev = 1;
-  if( vflip )
-      vertrev = 1;
-
-  if (_verbose && horzrev) printf("TGA: horizontal reversed\n");
-  if (_verbose && vertrev) printf("TGA: vertical reversed\n");
-
-  rle = 0;
-  switch (tgaHeader.imageType) {
-  case TGA_TYPE_MAPPED_RLE:
-    rle = 1;
-    if (_verbose) printf("TGA: run-length encoded\n");
-  case TGA_TYPE_MAPPED:
-    /* Test for alpha channel. */
-    format = GL_COLOR_INDEX;
-    components = 1;
-    if (_verbose) {
-      printf("TGA: %d bit indexed image (%d bit palette)\n",
-        tgaHeader.colorMapSize, bpp);
-    }
-    break;
-
-  case TGA_TYPE_GRAY_RLE:
-    rle = 1;
-    if (_verbose) printf("TGA: run-length encoded\n");
-  case TGA_TYPE_GRAY:
-    format = GL_LUMINANCE;
-    components = 1;
-    if (_verbose) printf("TGA: %d bit grayscale image\n", bpp);
-    break;
 
-  case TGA_TYPE_COLOR_RLE:
-    rle = 1;
-    if (_verbose) printf("TGA: run-length encoded\n");
-  case TGA_TYPE_COLOR:
-    /* Test for alpha channel. */
-    if (bpp == 32) {
-      format = GL_BGRA_EXT;
-      components = 4;
-      if (_verbose) {
-        printf("TGA: %d bit color image with alpha channel\n", bpp);
-      }
-    } else {
-      format = GL_BGR_EXT;
-      components = 3;
-      if (_verbose) printf("TGA: %d bit color image\n", bpp);
-    }
-    break;
-
-  default:
-    sprintf(error,
-      "TGA: unrecognized image type %d\n", tgaHeader.imageType);
-    if (_verbose) printf("%s\n", error);
-    return NULL;
-  }
-
-  if ((format == GL_BGRA_EXT && bpp != 32) ||
-      (format == GL_BGR_EXT && bpp != 24) ||
-      ((format == GL_LUMINANCE || format == GL_COLOR_INDEX) && bpp != 8)) {
-    /* FIXME: We haven't implemented bit-packed fields yet. */
-    fprintf(stderr, "bpp %d, format %x\n", bpp, (unsigned int)format); 
-    sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
-    if (_verbose) printf("%s\n", error);
-    return NULL;
-  }
-
-  /* Check that we have a color map only when we need it. */
-  if (format == GL_COLOR_INDEX) {
-    if (tgaHeader.colorMapType != 1) {
-      sprintf(error, "TGA: indexed image has invalid color map type %d\n",
-        tgaHeader.colorMapType);
-      if (_verbose) printf("%s\n", error);
-      return NULL;
-    }
-  } else if (tgaHeader.colorMapType != 0) {
-    sprintf(error, "TGA: non-indexed image has invalid color map type %d\n",
-      tgaHeader.colorMapType);
-    if (_verbose) printf("%s\n", error);
-    return NULL;
-  }
-
-  if (tgaHeader.colorMapType == 1) {
-    /* We need to read in the colormap. */
-    index = (tgaHeader.colorMapIndexHi << 8) | tgaHeader.colorMapIndexLo;
-    length = (tgaHeader.colorMapLengthHi << 8) | tgaHeader.colorMapLengthLo;
-
-    if (_verbose) {
-      printf("TGA: reading color map (%d + %d) * (%d / 8)\n",
-        index, length, tgaHeader.colorMapSize);
-    }
-    if (length == 0) {
-      sprintf(error, "TGA: invalid color map length %d", length);
-      if (_verbose) printf("%s\n", error);
-      return NULL;
-    }
-    if (tgaHeader.colorMapSize != 24) {
-      /* We haven't implemented bit-packed fields yet. */
-      sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
-      if (_verbose) printf("%s\n", error);
-      return NULL;
-    }
-
-    pelbytes = tgaHeader.colorMapSize / 8;
-    colors = length + index;
-    cmap = (GLubyte*)malloc (colors * pelbytes);
-
-    /* Zero the entries up to the beginning of the map. */
-    memset(cmap, 0, index * pelbytes);
-
-    /* Read in the rest of the colormap. */
-    if (fread(cmap, pelbytes, length, fp) != (size_t) length) {
-      sprintf(error, "TGA: error reading colormap (ftell == %ld)\n",
-        ftell (fp));
-      if (_verbose) printf("%s\n", error);
-      return NULL;
-    }
-
-    if (pelbytes >= 3) {
-      /* Rearrange the colors from BGR to RGB. */
-      int tmp;
-      for (j = index; j < length * pelbytes; j += pelbytes) {
-        tmp = cmap[j];
-        cmap[j] = cmap[j + 2];
-        cmap[j + 2] = tmp;
-      }
-    }
-  } else {
-    colors = 0;
-    cmap = NULL;
-  }
-
-  /* Allocate the data. */
-  pelbytes = bpp / 8;
-  pixels = (unsigned char *) malloc (width * height * pelbytes);
-
-  if (rle) {
-    rleRec.statebuf = 0;
-    rleRec.statelen = 0;
-    rleRec.laststate = 0;
-    rleInfo = &rleRec;
-    myfread = rle_fread;
-  } else {
-    rleInfo = NULL;
-    myfread = std_fread;
-  }
-
-  wbytes = width * pelbytes;
-
-  if (vertrev) {
-    start = 0;
-    end = height;
-    dir = 1;
-  } else {
-    /* We need to reverse loading order of rows. */
-    start = height-1;
-    end = -1;
-    dir = -1;
-  }
-
-  for (i = start; i != end; i += dir) {
-    data = pixels + i*wbytes;
-
-    /* Suck in the data one row at a time. */
-    if (myfread(rleInfo, data, pelbytes, width, fp) != width) {
-      /* Probably premature end of file. */
-      if (_verbose) {
-        printf ("TGA: error reading (ftell == %ld, width=%d)\n",
-          ftell(fp), width);
-      }
-      return NULL;
-    }  
-
-    if (horzrev) {
-      /* We need to mirror row horizontally. */
-      for (j = 0; j < width/2; j++) {
-        GLubyte tmp;
-
-        for (k = 0; k < pelbytes; k++) {
-          tmp = data[j*pelbytes+k];
-          data[j*pelbytes+k] = data[(width-j-1)*pelbytes+k];
-          data[(width-j-1)*pelbytes+k] = tmp;
-        }
-      }
-    }
-  }
-
-  if (rle) {
-    free(rleInfo->statebuf);
-  }
-
-  if (fgetc (fp) != EOF) {
-    if (_verbose) printf ("TGA: too much input data, ignoring extra...\n");
-  }
-
-  genericImage = (gliGenericImage*) malloc(sizeof(gliGenericImage));
-  genericImage->width = width;
-  genericImage->height = height;
-  genericImage->format = format;
-  genericImage->components = components;
-  genericImage->cmapEntries = colors;
-  genericImage->cmapFormat = GL_BGR_EXT;  // XXX fix me
-  genericImage->cmap = cmap;
-  genericImage->pixels = pixels;
-
-  return genericImage;
-}
-
-static int
-gli_verbose(int new_verbose)
-{
-  _verbose = new_verbose;
-  return _verbose;
-}
-
-
-
-// added 10/2005, Denis Zorin
-// a very simple TGA output, supporting 
-// uncompressed luminance RGB and RGBA 
-// G22.2270 students: this is C (no C++) 
-// so this is not the style I would encourage
-// you to use; I used it for consistency 
-// with the rest of the code in this file 
-
-
-// fixed header values for the subset of TGA we use for writing
-static unsigned char TGAHeaderColor[12] = 
-  { 0,// 0 ID length = no id
-    0,// 1 color map type = no color map
-    2,// 2 image type = uncompressed true color
-    0, 0, 0, 0, 0,// color map spec = empty
-    0, 0,  // x origin of image 
-    0, 0   // y origin of image
-  };
-
-static unsigned char TGAHeaderBW[12] = 
-  { 0,// 0 ID length = no id
-    0,// 1 color map type = no color map
-    3,// 3 image type = uncompressed black and white
-    0, 0, 0, 0, 0,// color map spec = empty
-    0, 0,  // x origin of image 
-    0, 0   // y origin of image
-  };
-
-// this makes sure that 
-// image size is written in correct format 
-// and byte order (least first)
-static void write16bit(int n, FILE* fp) { 
-  unsigned char bytes[] = { n % 256, n / 256 };
-  fwrite(bytes, 2, sizeof(unsigned char),fp);
-}
-
-
-
-static void writeTGA( gliGenericImage* image, FILE *fp) {
-
-  assert(!image->cmap); // we do not deal with color map images
-    
-  if(image->components == 3 || image->components == 4) 
-    fwrite(TGAHeaderColor, 12, sizeof(unsigned char),fp);
-  else { 
-    if(image->components == 1 ) 
-      fwrite(TGAHeaderBW, 12, sizeof(unsigned char),fp);        
-    else { fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); }
-  }
-
-  write16bit(image->width,fp);  
-  write16bit(image->height,fp);  
-  switch (image->components ) { 
-  case 1: 
-    putc(8,fp);
-    break;
-  case 3: 
-    putc(24,fp); 
-    break;
-  case 4:
-    putc(32,fp);
-    break;
-  default: fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); 
-  };
-  
-  if(image-> components == 4) 
-    putc(0x04,fp); // bottom left image (0x00) + 8 bit alpha (0x4)
-  else 
-    putc(0x00,fp);
-
-  fwrite(image->pixels, image->height*image->width*image->components, sizeof(char),fp);
-}
-
-} // end of namespace
-#endif
+#endif 

+ 9 - 3
write.cpp

@@ -3,12 +3,15 @@
 #include "writeOBJ.h"
 #include "writeOFF.h"
 
+#include <iostream>
+
 template <typename DerivedV, typename DerivedF>
 IGL_INLINE bool igl::write(
-                      const std::string str,
-                      const Eigen::PlainObjectBase<DerivedV>& V,
-                      const Eigen::PlainObjectBase<DerivedF>& F)
+  const std::string str,
+  const Eigen::PlainObjectBase<DerivedV>& V,
+  const Eigen::PlainObjectBase<DerivedF>& F)
 {
+  using namespace std;
   const char* p;
   for (p = str.c_str(); *p != '\0'; p++)
     ;
@@ -20,6 +23,9 @@ IGL_INLINE bool igl::write(
   
   if (!strcmp(p, ".off") || !strcmp(p, ".OFF"))
     return igl::writeOFF(str,V,F);
+
+  cerr<<"^write Unsupported extension: "<<string(p)<<endl;
+  return false;
 }
 
 #ifndef IGL_HEADER_ONLY

+ 10 - 10
writeOBJ.h

@@ -23,19 +23,19 @@ namespace igl
   // Returns true on success, false on error
   template <typename DerivedV, typename DerivedF>
   IGL_INLINE bool writeOBJ(
-                        const std::string str,
-                        const Eigen::PlainObjectBase<DerivedV>& V,
-                        const Eigen::PlainObjectBase<DerivedF>& F);
+    const std::string str,
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedF>& F);
   
   template <typename DerivedV, typename DerivedF, typename DerivedT>
   IGL_INLINE bool writeOBJ(
-                           const std::string str,
-                           const Eigen::PlainObjectBase<DerivedV>& V,
-                           const Eigen::PlainObjectBase<DerivedF>& F,
-                           const Eigen::PlainObjectBase<DerivedV>& CN,
-                           const Eigen::PlainObjectBase<DerivedF>& FN,
-                           const Eigen::PlainObjectBase<DerivedT>& TC,
-                           const Eigen::PlainObjectBase<DerivedF>& FTC);
+    const std::string str,
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedF>& F,
+    const Eigen::PlainObjectBase<DerivedV>& CN,
+    const Eigen::PlainObjectBase<DerivedF>& FN,
+    const Eigen::PlainObjectBase<DerivedT>& TC,
+    const Eigen::PlainObjectBase<DerivedF>& FTC);
 
 }