Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

OMFormat.hh

00001 /*===========================================================================*\
00002  *                                                                           *
00003  *                               OpenMesh                                    *
00004  *      Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen      *
00005  *                           www.openmesh.org                                *
00006  *                                                                           *
00007  *---------------------------------------------------------------------------* 
00008  *                                                                           *
00009  *                                License                                    *
00010  *                                                                           *
00011  *  This library is free software; you can redistribute it and/or modify it  *
00012  *  under the terms of the GNU Library General Public License as published   *
00013  *  by the Free Software Foundation, version 2.                              *
00014  *                                                                           *
00015  *  This library is distributed in the hope that it will be useful, but      *
00016  *  WITHOUT ANY WARRANTY; without even the implied warranty of               *
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        *
00018  *  Library General Public License for more details.                         *
00019  *                                                                           *
00020  *  You should have received a copy of the GNU Library General Public        *
00021  *  License along with this library; if not, write to the Free Software      *
00022  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                *
00023  *                                                                           *
00024 \*===========================================================================*/
00025 
00026 
00027 #ifndef OPENMESH_IO_OMFORMAT_HH
00028 #define OPENMESH_IO_OMFORMAT_HH
00029 
00030 
00031 //=== INCLUDES ================================================================
00032 
00033 #include <OpenMesh/Core/System/config.hh>
00034 #include <OpenMesh/Core/System/omstream.hh>
00035 #include <OpenMesh/Core/IO/SR_store.hh>
00036 #include <OpenMesh/Core/Utils/GenProg.hh>
00037 #include <OpenMesh/Core/Utils/Endian.hh>
00038 #include <OpenMesh/Core/Utils/vector_traits.hh>
00039 // --------------------
00040 #include <iostream>
00041 #if defined(OM_CC_GCC) && (OM_GCC_VERSION < 30000)
00042 #  include <OpenMesh/Tools/Utils/NumLimitsT.hh>
00043 #  define OM_MISSING_HEADER_LIMITS 1
00044 #else
00045 #  include <limits>
00046 #endif
00047 
00048 
00049 //== NAMESPACES ==============================================================
00050 
00051 #ifndef DOXY_IGNORE_THIS
00052 namespace OpenMesh {
00053 namespace IO   {
00054 namespace OMFormat {
00055 
00056 
00057 //=== IMPLEMENTATION ==========================================================
00058 
00059 
00063 
00064 //-----------------------------------------------------------------------------
00065 
00066   // <:Header>
00067   // <:Comment>
00068   // Chunk 0
00069   //   <:ChunkHeader>
00070   //   <:Comment>
00071   //   data
00072   // Chunk 1
00073   //   <:ChunkHeader>
00074   //   <:Comment>
00075   //   data
00076   // .
00077   // .
00078   // .
00079   // Chunk N
00080 
00081   typedef unsigned char      uchar;
00082   typedef uint8_t            uint8;
00083   typedef uint16_t           uint16;
00084   typedef uint32_t           uint32;
00085   typedef uint64_t           uint64;
00086   typedef int8_t             int8;
00087   typedef int16_t            int16;
00088   typedef int32_t            int32;
00089   typedef int64_t            int64;
00090   typedef float32_t          float32;
00091   typedef float64_t          float64;
00092 
00093   struct Header
00094   {
00095     uchar  magic_[2]; // OM
00096     uchar  mesh_;    // [T]riangles, [Q]uads, [P]olygonals
00097     uint8  version_;    
00098     uint32 n_vertices_;
00099     uint32 n_faces_;
00100     uint32 n_edges_;
00101 
00102     size_t store( std::ostream& _os, bool _swap ) const
00103     {
00104       _os.write( (char*)this, 4); // magic_, mesh_, version_
00105       size_t bytes = 4;
00106       bytes += binary<uint32_t>::store( _os, n_vertices_, _swap );
00107       bytes += binary<uint32_t>::store( _os, n_faces_, _swap );
00108       bytes += binary<uint32_t>::store( _os, n_edges_, _swap );
00109       return bytes;
00110     }
00111 
00112     size_t restore( std::istream& _is, bool _swap )
00113     {
00114       if (_is.read( (char*)this, 4 ).eof())
00115         return 0;
00116 
00117       size_t bytes = 4;
00118       bytes += binary<uint32_t>::restore( _is, n_vertices_, _swap );
00119       bytes += binary<uint32_t>::restore( _is, n_faces_, _swap );
00120       bytes += binary<uint32_t>::restore( _is, n_edges_, _swap );
00121       return bytes;
00122     }
00123 
00124   };
00125 
00126   struct Chunk
00127   {
00128     typedef size_t esize_t; // element size, used for custom properties
00129 
00130     enum Type {
00131       Type_Pos       = 0x00,
00132       Type_Normal    = 0x01,
00133       Type_Texcoord  = 0x02,
00134       Type_Status    = 0x03,
00135       Type_Color     = 0x04,
00136       Type_Custom    = 0x06,
00137       Type_Topology  = 0x07
00138     };
00139 
00140     enum Entity {
00141       Entity_Vertex    = 0x00,
00142       Entity_Mesh      = 0x01,
00143       Entity_Face      = 0x02,
00144       Entity_Edge      = 0x04,
00145       Entity_Halfedge  = 0x06,
00146     };
00147 
00148     enum Dim {
00149       Dim_1D = 0x00,
00150       Dim_2D = 0x01,
00151       Dim_3D = 0x02,
00152       Dim_4D = 0x03,
00153       Dim_5D = 0x04,
00154       Dim_6D = 0x05,
00155       Dim_7D = 0x06,
00156       Dim_8D = 0x07
00157     };
00158 
00159     enum Integer_Size {  
00160       Integer_8   = 0x00, // 1 byte for (unsigned) char
00161       Integer_16  = 0x01, // 2 bytes for short
00162       Integer_32  = 0x02, // 4 bytes for long
00163       Integer_64  = 0x03  // 8 bytes for long long
00164     };
00165 
00166     enum Float_Size {
00167       Float_32  = 0x00, //  4 bytes for float
00168       Float_64  = 0x01, //  8 bytes for double
00169       Float_128 = 0x02  // 16 bytes for long double (an assumption!)
00170     };
00171 
00172     static const int SIZE_RESERVED = 1; //  1
00173     static const int SIZE_NAME     = 1; //  2
00174     static const int SIZE_ENTITY   = 3; //  5
00175     static const int SIZE_TYPE     = 4; //  9
00176 
00177     static const int SIZE_SIGNED   = 1; // 10
00178     static const int SIZE_FLOAT    = 1; // 11
00179     static const int SIZE_DIM      = 3; // 14
00180     static const int SIZE_BITS     = 2; // 16
00181 
00182     static const int OFF_RESERVED = 0;                          //  0
00183     static const int OFF_NAME     = SIZE_RESERVED + OFF_RESERVED; //  2
00184     static const int OFF_ENTITY   = SIZE_NAME     + OFF_NAME;   //  3
00185     static const int OFF_TYPE     = SIZE_ENTITY   + OFF_ENTITY; //  5
00186     static const int OFF_SIGNED   = SIZE_TYPE     + OFF_TYPE;   //  9
00187     static const int OFF_FLOAT    = SIZE_SIGNED   + OFF_SIGNED; // 10
00188     static const int OFF_DIM      = SIZE_FLOAT    + OFF_FLOAT;  // 11
00189     static const int OFF_BITS     = SIZE_DIM      + OFF_DIM;    // 14
00190 
00191     // !Attention! When changing the bit size, the operators
00192     // << (uint16, Header) and << (Header, uint16) must be changed as well
00193     //
00194     // Entries signed_, float_, dim_, bits_ are not used when type_
00195     // equals Type_Custom
00196     //
00197     struct Header // 16 bits long
00198     {
00199       unsigned reserved_: SIZE_RESERVED;
00200       unsigned name_    : SIZE_NAME;   // 1 named property, 0 anonymous
00201       unsigned entity_  : SIZE_ENTITY; // 0 vertex, 1 mesh, 2 edge, 
00202                                        // 4 halfedge, 6 face
00203       unsigned type_    : SIZE_TYPE;   // 0 pos, 1 normal, 2 texcoord, 
00204                                        // 3 status, 4 color 6 custom 7 topology
00205       unsigned signed_  : SIZE_SIGNED; // bool
00206       unsigned float_   : SIZE_FLOAT;  // bool
00207       unsigned dim_     : SIZE_DIM;    // 0 1D, 1 2D, 2 3D, .., 7 8D
00208       unsigned bits_    : SIZE_BITS;   // {8, 16, 32, 64} | {32, 64, 128}
00209                                        // (integer)         (float)
00210       unsigned unused_  : 16; // fill up to 32 bits
00211     }; // struct Header
00212 
00213 
00214     class PropertyName : public std::string
00215     {
00216     public:
00217 
00218       static const size_t size_max = 256;
00219 
00220       PropertyName( ) { }
00221 
00222       PropertyName( const std::string& _name ) { *this = _name; }
00223 
00224       bool is_valid() const { return is_valid( size() ); }
00225 
00226       static bool is_valid( size_t _s ) { return _s <= size_max; }
00227 
00228       PropertyName& operator = ( const std::string& _rhs )
00229       {
00230         assert( is_valid( _rhs.size() ) );
00231 
00232         if ( is_valid( _rhs.size() ) )
00233           std::string::operator = ( _rhs );
00234         else
00235         {
00236           omerr() << "Warning! Property name too long. Will be shortened!\n";
00237           this->std::string::operator = ( _rhs.substr(0, size_max) );
00238         }
00239 
00240         return *this;
00241       }
00242 
00243     };
00244 
00245   }; // Chunk
00246 
00247   // ------------------------------------------------------------ Helper
00248 
00249   // -------------------- get size information
00250 
00252   inline size_t header_size(void) { return sizeof(Header); }
00253 
00254 
00256   inline size_t chunk_header_size( void ) { return sizeof(uint16); }
00257 
00258 
00260   inline size_t scalar_size( const Chunk::Header& _hdr )
00261   {
00262     return _hdr.float_ ? (0x01 << _hdr.bits_) : (0x04 << _hdr.bits_);
00263   }
00264 
00265 
00267   inline size_t dimensions(const Chunk::Header& _chdr) { return _chdr.dim_+1; }
00268   
00269 
00271   inline size_t vector_size( const Chunk::Header& _chdr )
00272   {
00273     return dimensions(_chdr)*scalar_size(_chdr);
00274   }
00275 
00276 
00278   inline size_t chunk_data_size( Header& _hdr,  Chunk::Header& _chunk_hdr )
00279   {
00280     size_t C     = 0;
00281 
00282     switch( _chunk_hdr.entity_ )
00283     {
00284       case Chunk::Entity_Vertex:   C  = _hdr.n_vertices_; break;
00285       case Chunk::Entity_Face:     C  = _hdr.n_faces_;    break;
00286       case Chunk::Entity_Halfedge: C  = _hdr.n_edges_;    // no break!
00287       case Chunk::Entity_Edge:     C += _hdr.n_edges_;    break;
00288       case Chunk::Entity_Mesh:     C  = 1;                break;
00289       default:
00290         std::cerr << "Invalid value in _chunk_hdr.entity_\n";
00291         assert( false );
00292     }
00293 
00294     return C * vector_size( _chunk_hdr );
00295   }
00296 
00297   inline size_t chunk_size( Header& _hdr, Chunk::Header& _chunk_hdr )
00298   {
00299     return chunk_header_size() + chunk_data_size( _hdr, _chunk_hdr );
00300   }
00301 
00302   // -------------------- convert from Chunk::Header to storage type
00303 
00304   uint16& operator << (uint16& val, const Chunk::Header& hdr);
00305   Chunk::Header& operator << (Chunk::Header& hdr, const uint16 val);
00306 
00307 
00308   // -------------------- type information
00309 
00310   template <typename T> bool is_float(const T&) 
00311   { 
00312 #if defined(OM_MISSING_HEADER_LIMITS)
00313     return !Utils::NumLimitsT<T>::is_integer();
00314 #else
00315     return !std::numeric_limits<T>::is_integer; 
00316 #endif
00317   }
00318 
00319   template <typename T> bool is_integer(const T) 
00320   { 
00321 #if defined(OM_MISSING_HEADER_LIMITS)
00322     return Utils::NumLimitsT<T>::is_integer();
00323 #else
00324     return std::numeric_limits<T>::is_integer; 
00325 #endif
00326   }
00327 
00328   template <typename T> bool is_signed(const T&) 
00329   { 
00330 #if defined(OM_MISSING_HEADER_LIMITS)
00331     return Utils::NumLimitsT<T>::is_signed();
00332 #else
00333     return std::numeric_limits<T>::is_signed; 
00334 #endif
00335   }
00336 
00337   // -------------------- conversions (format type <- type/value)
00338 
00339   template <typename VecType>
00340   inline
00341   Chunk::Dim dim( VecType )
00342   {
00343     assert( vector_traits< VecType >::size() < 9 );
00344     return static_cast<Chunk::Dim>(vector_traits< VecType >::size() - 1);
00345   }
00346 
00347   template <>
00348   inline
00349   Chunk::Dim dim( const Chunk::Header& _hdr )
00350   {
00351     return static_cast<Chunk::Dim>( _hdr.dim_ );
00352   }
00353 
00354   // calc minimum (power-of-2) number of bits needed
00355   Chunk::Integer_Size needed_bits( size_t s );
00356 
00357 
00358   // Return the storage type (Chunk::Header::bits_)
00359   template <typename T> 
00360   inline
00361   unsigned int bits(const T& val)
00362   {
00363     return is_integer(val) 
00364       ? (static_cast<unsigned int>(integer_size(val)))
00365       : (static_cast<unsigned int>(float_size(val)));
00366   }
00367 
00368   // Convert size of type to Integer_Size
00369   template <typename T> Chunk::Integer_Size integer_size(const T& d)
00370   {
00371     assert( is_integer(d) );
00372 
00373     switch( sizeof(T) )
00374     {
00375       case  1: return OMFormat::Chunk::Integer_8;
00376       case  2: return OMFormat::Chunk::Integer_16;
00377       case  4: return OMFormat::Chunk::Integer_32;
00378       case  8: return OMFormat::Chunk::Integer_64;
00379     }
00380     return Chunk::Integer_Size(0);
00381   }
00382 
00383 
00384   // Convert size of type to FLoat_Size 
00385   template <typename T> Chunk::Float_Size float_size(const T& d)
00386   {
00387     assert( is_float(d) );
00388 
00389     switch( sizeof(T) )
00390     {
00391       case  4: return OMFormat::Chunk::Float_32;
00392       case  8: return OMFormat::Chunk::Float_64;
00393       case 16: return OMFormat::Chunk::Float_128;
00394     }
00395     return Chunk::Float_Size(0);
00396   }
00397 
00398   // -------------------- create/read version
00399 
00400   inline uint8 mk_version(const uint16 major, const uint16 minor)
00401   { return (major & 0x07) << 5 | (minor & 0x1f); }
00402 
00403 
00404   inline uint16 major_version(const uint8 version) 
00405   { return (version >> 5) & 0x07; }
00406 
00407 
00408   inline uint16 minor_version(const uint8 version) 
00409   { return (version & 0x001f); }
00410 
00411 
00412   // ---------------------------------------- convenience functions
00413 
00414   const char *as_string(Chunk::Type t);
00415   const char *as_string(Chunk::Entity e);
00416   const char *as_string(Chunk::Dim d);
00417   const char *as_string(Chunk::Integer_Size d);
00418   const char *as_string(Chunk::Float_Size d);
00419 
00420   std::ostream& operator << ( std::ostream& _os, const Header& _h );
00421   std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c );
00422 
00424 } // namespace OMFormat
00425 
00426   // -------------------- (re-)store header
00427 
00428   template <> inline
00429   size_t store( std::ostream& _os, const OMFormat::Header& _hdr, bool _swap)
00430   { return _hdr.store( _os, _swap ); }
00431 
00432   template <> inline
00433   size_t restore( std::istream& _is, OMFormat::Header& _hdr, bool _swap )
00434   { return _hdr.restore( _is, _swap ); }
00435 
00436 
00437   // -------------------- (re-)store chunk header
00438 
00439   template <> inline
00440   size_t 
00441   store( std::ostream& _os, const OMFormat::Chunk::Header& _hdr, bool _swap)
00442   {
00443     OMFormat::uint16 val; val << _hdr;
00444     return binary<uint16_t>::store( _os, val, _swap );
00445   }
00446 
00447   template <> inline
00448   size_t 
00449   restore( std::istream& _is, OMFormat::Chunk::Header& _hdr, bool _swap )
00450   {
00451     OMFormat::uint16 val;
00452     size_t bytes = binary<uint16_t>::restore( _is, val, _swap );
00453 
00454     _hdr << val;
00455     
00456     return bytes;
00457   }
00458 
00459   // -------------------- (re-)store integer with wanted number of bits (bytes)
00460 
00461   typedef GenProg::True  t_signed;
00462   typedef GenProg::False t_unsigned;
00463 
00464 
00466   template< typename T > 
00467   inline
00468   size_t 
00469   store( std::ostream& _os, 
00470          const T& _val, 
00471          OMFormat::Chunk::Integer_Size _b, 
00472          bool _swap)
00473   {    
00474     assert( OMFormat::is_integer( _val ) );
00475 
00476     if ( OMFormat::is_signed( _val ) )
00477       return store( _os, _val, _b, _swap, t_signed()   );
00478     return   store( _os, _val, _b, _swap, t_unsigned() );
00479   }
00480 
00481 
00482   // helper to store a an integer
00483   template< typename T > 
00484   size_t 
00485   store( std::ostream& _os, 
00486          const T& _val, 
00487          OMFormat::Chunk::Integer_Size _b, 
00488          bool _swap,
00489          t_signed);
00490 
00491   // helper to store a an unsigned integer
00492   template< typename T > 
00493   size_t 
00494   store( std::ostream& _os, 
00495          const T& _val, 
00496          OMFormat::Chunk::Integer_Size _b, 
00497          bool _swap,
00498          t_unsigned);
00499 
00500 
00502   template< typename T > 
00503   inline
00504   size_t 
00505   restore( std::istream& _is, 
00506            T& _val, 
00507            OMFormat::Chunk::Integer_Size _b, 
00508            bool _swap)
00509   {    
00510     assert( OMFormat::is_integer( _val ) );
00511     
00512     if ( OMFormat::is_signed( _val ) )
00513       return restore( _is, _val, _b, _swap, t_signed() );
00514     return restore( _is, _val, _b, _swap, t_unsigned() );    
00515   }
00516 
00517 
00518   // helper to store a an integer
00519   template< typename T > inline
00520   size_t restore( std::istream& _is, 
00521                   T& _val, 
00522                   OMFormat::Chunk::Integer_Size _b, 
00523                   bool _swap,
00524                   t_signed);
00525 
00526   // helper to store a an unsigned integer
00527   template< typename T > inline
00528   size_t restore( std::istream& _is, 
00529                   T& _val, 
00530                   OMFormat::Chunk::Integer_Size _b, 
00531                   bool _swap,
00532                   t_unsigned);
00533   // 
00534   // ---------------------------------------- storing vectors
00535 
00537   template <typename VecT> inline
00538   size_t vector_store( std::ostream& _os, const VecT& _vec, bool _swap )
00539   {
00540     return store( _os, _vec, 
00541                   GenProg::Int2Type< vector_traits<VecT>::size_ >(),
00542                   _swap );
00543   }
00544 
00545   template <typename VecT> inline
00546   size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<1>, 
00547                 bool _swap )
00548   {
00549     return store( _os, _vec[0], _swap );
00550   }
00551 
00552   template <typename VecT> inline
00553   size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<2>, 
00554                 bool _swap )
00555   {
00556     size_t bytes =  store( _os, _vec[0], _swap );
00557     bytes += store( _os, _vec[1], _swap );
00558     return bytes;
00559   }
00560 
00561   template <typename VecT> inline
00562   size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<3>, 
00563                 bool _swap )
00564   {
00565     size_t bytes =  store( _os, _vec[0], _swap );
00566     bytes += store( _os, _vec[1], _swap );
00567     bytes += store( _os, _vec[2], _swap );
00568     return bytes;
00569   }
00570 
00571   template <typename VecT> inline
00572   size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<4>, 
00573                 bool _swap )
00574   {
00575     size_t bytes =  store( _os, _vec[0], _swap );
00576     bytes += store( _os, _vec[1], _swap );
00577     bytes += store( _os, _vec[2], _swap );
00578     bytes += store( _os, _vec[3], _swap );
00579     return bytes;
00580   }
00581 
00582   // ---------------------------------------- restoring vectors
00583 
00585   template <typename VecT>
00586   inline
00587   size_t
00588   vector_restore( std::istream& _is, VecT& _vec, bool _swap )
00589   {
00590     return restore( _is, _vec, 
00591                     GenProg::Int2Type< vector_traits<VecT>::size_ >(),
00592                     _swap );
00593   }
00594 
00595 
00596   template <typename VecT>
00597   inline 
00598   size_t
00599   restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<1>, 
00600          bool _swap )
00601   {
00602     return restore( _is, _vec[0], _swap );
00603   }
00604 
00605   template <typename VecT>
00606   inline
00607   size_t
00608   restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<2>, 
00609          bool _swap )
00610   {
00611     size_t bytes =  restore( _is, _vec[0], _swap );
00612     bytes += restore( _is, _vec[1], _swap );
00613     return bytes;
00614   }
00615 
00616   template <typename VecT>
00617   inline
00618   size_t
00619   restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<3>, 
00620          bool _swap )
00621   {
00622     typedef typename vector_traits<VecT>::value_type scalar_type;
00623     size_t bytes;
00624 
00625     bytes  = binary<scalar_type>::restore( _is, _vec[0], _swap );
00626     bytes += binary<scalar_type>::restore( _is, _vec[1], _swap );
00627     bytes += binary<scalar_type>::restore( _is, _vec[2], _swap );
00628     return bytes;
00629   }
00630 
00631   template <typename VecT>
00632   inline
00633   size_t
00634   restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<4>, 
00635            bool _swap )
00636   {
00637     typedef typename vector_traits<VecT>::value_type scalar_type;
00638     size_t bytes;
00639 
00640     bytes  = binary<scalar_type>::restore( _is, _vec[0], _swap );
00641     bytes += binary<scalar_type>::restore( _is, _vec[1], _swap );
00642     bytes += binary<scalar_type>::restore( _is, _vec[2], _swap );
00643     bytes += binary<scalar_type>::restore( _is, _vec[3], _swap );
00644     return bytes;
00645   }
00646 
00647   // ---------------------------------------- storing property names
00648   
00649   template <>
00650   inline
00651   size_t store( std::ostream& _os, const OMFormat::Chunk::PropertyName& _pn, 
00652                 bool _swap )
00653   {
00654     store( _os, _pn.size(), OMFormat::Chunk::Integer_8, _swap ); // 1 byte
00655     if ( _pn.size() )
00656       _os.write( _pn.c_str(), _pn.size() ); // size bytes
00657     return _pn.size() + 1;
00658   }
00659 
00660   template <>
00661   inline
00662   size_t restore( std::istream& _is, OMFormat::Chunk::PropertyName& _pn, 
00663                   bool _swap )
00664   {    
00665     size_t size;
00666 
00667     restore( _is, size, OMFormat::Chunk::Integer_8, _swap); // 1 byte
00668 
00669     assert( OMFormat::Chunk::PropertyName::is_valid( size ) );
00670 
00671     if ( size > 0 )
00672     {
00673       char buf[256];
00674       _is.read( buf, size ); // size bytes
00675       buf[size] = '\0';
00676       _pn.resize(size);
00677       _pn = buf;
00678     }
00679     return size+1;
00680   }
00681 
00682 //=============================================================================
00683 } // namespace IO
00684 } // namespace OpenMesh
00685 #endif
00686 //=============================================================================
00687 #if defined(OM_MISSING_HEADER_LIMITS)
00688 #  undef OM_MISSING_HEADER_LIMITS
00689 #endif
00690 //=============================================================================
00691 #if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_IO_OMFORMAT_CC)
00692 #  define OPENMESH_IO_OMFORMAT_TEMPLATES
00693 #  include "OMFormat.cc"
00694 #endif
00695 //=============================================================================
00696 #endif
00697 //=============================================================================

acg pic Project OpenMesh, ©  Computer Graphics Group, RWTH Aachen. Documentation generated using doxygen .