Browse Source

Merge upstream master

johnmaf 9 years ago
parent
commit
c9f28192d9
47 changed files with 10348 additions and 121 deletions
  1. 20 0
      cmake-modules/FindRT.cmake
  2. 4 5
      code/BlenderLoader.cpp
  3. 1 4
      code/BlenderModifier.cpp
  4. 1 1
      code/BlenderScene.cpp
  5. 6 11
      code/BlenderScene.h
  6. 53 0
      code/CMakeLists.txt
  7. 177 30
      code/glTFAsset.h
  8. 341 10
      code/glTFAsset.inl
  9. 58 4
      code/glTFAssetWriter.inl
  10. 179 17
      code/glTFExporter.cpp
  11. 40 9
      code/glTFImporter.cpp
  12. 155 0
      contrib/Open3DGC/o3dgcAdjacencyInfo.h
  13. 863 0
      contrib/Open3DGC/o3dgcArithmeticCodec.cpp
  14. 339 0
      contrib/Open3DGC/o3dgcArithmeticCodec.h
  15. 430 0
      contrib/Open3DGC/o3dgcBinaryStream.h
  16. 412 0
      contrib/Open3DGC/o3dgcCommon.h
  17. 62 0
      contrib/Open3DGC/o3dgcDVEncodeParams.h
  18. 84 0
      contrib/Open3DGC/o3dgcDynamicVector.h
  19. 278 0
      contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp
  20. 76 0
      contrib/Open3DGC/o3dgcDynamicVectorDecoder.h
  21. 295 0
      contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp
  22. 79 0
      contrib/Open3DGC/o3dgcDynamicVectorEncoder.h
  23. 97 0
      contrib/Open3DGC/o3dgcFIFO.h
  24. 263 0
      contrib/Open3DGC/o3dgcIndexedFaceSet.h
  25. 47 0
      contrib/Open3DGC/o3dgcIndexedFaceSet.inl
  26. 111 0
      contrib/Open3DGC/o3dgcSC3DMCDecoder.h
  27. 850 0
      contrib/Open3DGC/o3dgcSC3DMCDecoder.inl
  28. 140 0
      contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h
  29. 116 0
      contrib/Open3DGC/o3dgcSC3DMCEncoder.h
  30. 927 0
      contrib/Open3DGC/o3dgcSC3DMCEncoder.inl
  31. 134 0
      contrib/Open3DGC/o3dgcTimer.h
  32. 22 0
      contrib/Open3DGC/o3dgcTools.cpp
  33. 475 0
      contrib/Open3DGC/o3dgcTriangleFans.cpp
  34. 291 0
      contrib/Open3DGC/o3dgcTriangleFans.h
  35. 133 0
      contrib/Open3DGC/o3dgcTriangleListDecoder.h
  36. 364 0
      contrib/Open3DGC/o3dgcTriangleListDecoder.inl
  37. 101 0
      contrib/Open3DGC/o3dgcTriangleListEncoder.h
  38. 719 0
      contrib/Open3DGC/o3dgcTriangleListEncoder.inl
  39. 184 0
      contrib/Open3DGC/o3dgcVector.h
  40. 317 0
      contrib/Open3DGC/o3dgcVector.inl
  41. 656 0
      doc/architecture/Assimp_Arch_Import.class.violet.html
  42. 107 0
      doc/architecture/assimp.object.violet.html
  43. 2 1
      include/assimp/IOSystem.hpp
  44. 0 2
      include/assimp/anim.h
  45. 20 27
      include/assimp/scene.h
  46. 254 0
      test/unit/ModelDiffer.cpp
  47. 65 0
      test/unit/ModelDiffer.h

+ 20 - 0
cmake-modules/FindRT.cmake

@@ -0,0 +1,20 @@
+# Try to find real time libraries
+# Once done, this will define
+#
+# RT_FOUND - system has rt library
+# RT_LIBRARIES - rt libraries directory
+#
+# Source: https://gitlab.cern.ch/dss/eos/commit/44070e575faaa46bd998708ef03eedb381506ff0
+#
+
+if(RT_LIBRARIES)
+    set(RT_FIND_QUIETLY TRUE)
+endif(RT_LIBRARIES)
+
+find_library(RT_LIBRARY rt)
+set(RT_LIBRARIES ${RT_LIBRARY})
+# handle the QUIETLY and REQUIRED arguments and set
+# RT_FOUND to TRUE if all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(rt DEFAULT_MSG RT_LIBRARY)
+mark_as_advanced(RT_LIBRARY)

+ 4 - 5
code/BlenderLoader.cpp

@@ -404,7 +404,7 @@ void BlenderImporter::ConvertBlendFile(aiScene* out, const Scene& in,const FileD
     }
     }
 
 
     // acknowledge that the scene might come out incomplete
     // acknowledge that the scene might come out incomplete
-    // by Assimps definition of `complete`: blender scenes
+    // by Assimp's definition of `complete`: blender scenes
     // can consist of thousands of cameras or lights with
     // can consist of thousands of cameras or lights with
     // not a single mesh between them.
     // not a single mesh between them.
     if (!out->mNumMeshes) {
     if (!out->mNumMeshes) {
@@ -790,7 +790,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
     ConversionData& conv_data, TempArray<std::vector,aiMesh>&  temp
     ConversionData& conv_data, TempArray<std::vector,aiMesh>&  temp
     )
     )
 {
 {
-    // TODO: Resolve various problems with BMesh triangluation before re-enabling.
+    // TODO: Resolve various problems with BMesh triangulation before re-enabling.
     //       See issues #400, #373, #318  #315 and #132.
     //       See issues #400, #373, #318  #315 and #132.
 #if defined(TODO_FIX_BMESH_CONVERSION)
 #if defined(TODO_FIX_BMESH_CONVERSION)
     BlenderBMeshConverter BMeshConverter( mesh );
     BlenderBMeshConverter BMeshConverter( mesh );
@@ -852,7 +852,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
         //out->mNumVertices = 0
         //out->mNumVertices = 0
         out->mFaces = new aiFace[it.second]();
         out->mFaces = new aiFace[it.second]();
 
 
-        // all submeshes created from this mesh are named equally. this allows
+        // all sub-meshes created from this mesh are named equally. this allows
         // curious users to recover the original adjacency.
         // curious users to recover the original adjacency.
         out->mName = aiString(mesh->id.name+2);
         out->mName = aiString(mesh->id.name+2);
             // skip over the name prefix 'ME'
             // skip over the name prefix 'ME'
@@ -1304,5 +1304,4 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
     return node.dismiss();
     return node.dismiss();
 }
 }
 
 
-
-#endif
+#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 1 - 4
code/BlenderModifier.cpp

@@ -275,9 +275,6 @@ void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  co
         orig_object.id.name,"`");
         orig_object.id.name,"`");
 }
 }
 
 
-
-
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
 bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
 {
 {
@@ -323,4 +320,4 @@ void  BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data
         orig_object.id.name,"`");
         orig_object.id.name,"`");
 }
 }
 
 
-#endif
+#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 1 - 1
code/BlenderScene.cpp

@@ -806,4 +806,4 @@ void DNA::RegisterConverters() {
 }
 }
 
 
 
 
-#endif
+#endif ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 6 - 11
code/BlenderScene.h

@@ -64,7 +64,7 @@ namespace Blender {
 // * C++ style comments only
 // * C++ style comments only
 //
 //
 // * Structures may include the primitive types char, int, short,
 // * Structures may include the primitive types char, int, short,
-//   float, double. Signedness specifiers are not allowed on
+//   float, double. Signed specifiers are not allowed on
 //   integers. Enum types are allowed, but they must have been
 //   integers. Enum types are allowed, but they must have been
 //   defined in this header.
 //   defined in this header.
 //
 //
@@ -85,9 +85,9 @@ namespace Blender {
 //   provided they are neither pointers nor arrays.
 //   provided they are neither pointers nor arrays.
 //
 //
 // * One of WARN, FAIL can be appended to the declaration (
 // * One of WARN, FAIL can be appended to the declaration (
-//   prior to the semiolon to specifiy the error handling policy if
+//   prior to the semicolon to specify the error handling policy if
 //   this field is missing in the input DNA). If none of those
 //   this field is missing in the input DNA). If none of those
-//   is specified the default policy is to subtitute a default
+//   is specified the default policy is to substitute a default
 //   value for the field.
 //   value for the field.
 //
 //
 
 
@@ -102,16 +102,16 @@ struct Image;
 
 
 #define AI_BLEND_MESH_MAX_VERTS 2000000000L
 #define AI_BLEND_MESH_MAX_VERTS 2000000000L
 
 
+static const size_t MaxNameLen = 1024;
+
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct ID : ElemBase {
 struct ID : ElemBase {
-
-    char name[1024] WARN;
+    char name[ MaxNameLen ] WARN;
     short flag;
     short flag;
 };
 };
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct ListBase : ElemBase {
 struct ListBase : ElemBase {
-
     std::shared_ptr<ElemBase> first;
     std::shared_ptr<ElemBase> first;
     std::shared_ptr<ElemBase> last;
     std::shared_ptr<ElemBase> last;
 };
 };
@@ -126,7 +126,6 @@ struct PackedFile : ElemBase {
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct GroupObject : ElemBase {
 struct GroupObject : ElemBase {
-
     std::shared_ptr<GroupObject> prev,next FAIL;
     std::shared_ptr<GroupObject> prev,next FAIL;
     std::shared_ptr<Object> ob;
     std::shared_ptr<Object> ob;
 };
 };
@@ -142,7 +141,6 @@ struct Group : ElemBase {
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct World : ElemBase {
 struct World : ElemBase {
     ID id FAIL;
     ID id FAIL;
-
 };
 };
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
@@ -217,7 +215,6 @@ struct TFace : ElemBase {
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct MTFace : ElemBase {
 struct MTFace : ElemBase {
-
     float uv[4][2] FAIL;
     float uv[4][2] FAIL;
     char flag;
     char flag;
     short mode;
     short mode;
@@ -235,7 +232,6 @@ struct MDeformWeight : ElemBase  {
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct MDeformVert : ElemBase  {
 struct MDeformVert : ElemBase  {
-
     vector<MDeformWeight> dw WARN;
     vector<MDeformWeight> dw WARN;
     int totweight;
     int totweight;
 };
 };
@@ -264,7 +260,6 @@ struct Material : ElemBase {
     float darkness;
     float darkness;
     float refrac;
     float refrac;
 
 
-
     float amb;
     float amb;
     float ang;
     float ang;
     float spectra;
     float spectra;

+ 53 - 0
code/CMakeLists.txt

@@ -699,7 +699,54 @@ SET ( openddl_parser_SRCS
 )
 )
 SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
 SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
 
 
+SET ( open3dgc_SRCS
+  ../contrib/Open3DGC/o3dgcAdjacencyInfo.h
+  ../contrib/Open3DGC/o3dgcArithmeticCodec.cpp
+  ../contrib/Open3DGC/o3dgcArithmeticCodec.h
+  ../contrib/Open3DGC/o3dgcBinaryStream.h
+  ../contrib/Open3DGC/o3dgcCommon.h
+  ../contrib/Open3DGC/o3dgcDVEncodeParams.h
+  ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp
+  ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.h
+  ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp
+  ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.h
+  ../contrib/Open3DGC/o3dgcDynamicVector.h
+  ../contrib/Open3DGC/o3dgcFIFO.h
+  ../contrib/Open3DGC/o3dgcIndexedFaceSet.h
+  ../contrib/Open3DGC/o3dgcIndexedFaceSet.inl
+  ../contrib/Open3DGC/o3dgcSC3DMCDecoder.h
+  ../contrib/Open3DGC/o3dgcSC3DMCDecoder.inl
+  ../contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h
+  ../contrib/Open3DGC/o3dgcSC3DMCEncoder.h
+  ../contrib/Open3DGC/o3dgcSC3DMCEncoder.inl
+  ../contrib/Open3DGC/o3dgcTimer.h
+  ../contrib/Open3DGC/o3dgcTools.cpp
+  ../contrib/Open3DGC/o3dgcTriangleFans.cpp
+  ../contrib/Open3DGC/o3dgcTriangleFans.h
+  ../contrib/Open3DGC/o3dgcTriangleListDecoder.h
+  ../contrib/Open3DGC/o3dgcTriangleListDecoder.inl
+  ../contrib/Open3DGC/o3dgcTriangleListEncoder.h
+  ../contrib/Open3DGC/o3dgcTriangleListEncoder.inl
+  ../contrib/Open3DGC/o3dgcVector.h
+  ../contrib/Open3DGC/o3dgcVector.inl
+)
+SOURCE_GROUP( open3dgc FILES ${open3dgc_SRCS})
+
+# Check dependencies for glTF importer with Open3DGC-compression.
+# RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file
+# has implementation for different platforms: WIN32, __MACH__ and other ("else" block).
+FIND_PACKAGE(RT QUIET)
+IF (RT_FOUND OR MSVC)
+  SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 )
+  ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 )
+ELSE ()
+  SET (open3dgc_SRCS "")
+  MESSAGE (INFO " RT-extension not found. glTF import/export will be built without Open3DGC-compression.")
+  #!TODO: off course is better to remove statistics timers from o3dgc codec. Or propose to choose what to use.
+ENDIF ()
+
 INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" )
 INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" )
+INCLUDE_DIRECTORIES( "../contrib" )
 
 
 # VC2010 fixes
 # VC2010 fixes
 if(MSVC10)
 if(MSVC10)
@@ -746,6 +793,7 @@ SET( assimp_src
   ${Poly2Tri_SRCS}
   ${Poly2Tri_SRCS}
   ${Clipper_SRCS}
   ${Clipper_SRCS}
   ${openddl_parser_SRCS}
   ${openddl_parser_SRCS}
+  ${open3dgc_SRCS}
   # Necessary to show the headers in the project when using the VC++ generator:
   # Necessary to show the headers in the project when using the VC++ generator:
 
 
   ${PUBLIC_HEADERS}
   ${PUBLIC_HEADERS}
@@ -820,6 +868,11 @@ else (UNZIP_FOUND)
   INCLUDE_DIRECTORIES("../")
   INCLUDE_DIRECTORIES("../")
 endif (UNZIP_FOUND)
 endif (UNZIP_FOUND)
 
 
+# Add RT-extension library for glTF importer with Open3DGC-compression.
+IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC)
+  TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY})
+ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC)
+
 INSTALL( TARGETS assimp
 INSTALL( TARGETS assimp
   LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}

+ 177 - 30
code/glTFAsset.h

@@ -1,4 +1,4 @@
-/*
+/*
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
@@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include <map>
 #include <map>
 #include <string>
 #include <string>
+#include <list>
 #include <vector>
 #include <vector>
 #include <algorithm>
 #include <algorithm>
 #include <stdexcept>
 #include <stdexcept>
@@ -361,8 +362,6 @@ namespace glTF
             { return id; }
             { return id; }
     };
     };
 
 
-
-
     //
     //
     // Classes for each glTF top-level object type
     // Classes for each glTF top-level object type
     //
     //
@@ -451,32 +450,115 @@ namespace glTF
 
 
     //! A buffer points to binary geometry, animation, or skins.
     //! A buffer points to binary geometry, animation, or skins.
     struct Buffer : public Object
     struct Buffer : public Object
-    {
-    public:
-
-        enum Type
-        {
-            Type_arraybuffer,
-            Type_text
-        };
-
-        //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
-        size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
-        //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
-
-        Type type;
-
-    private:
-        shared_ptr<uint8_t> mData; //!< Pointer to the data
-        bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
-
-    public:
-        Buffer();
-
-        void Read(Value& obj, Asset& r);
+	{
+		/********************* Types *********************/
+	public:
+
+		enum Type
+		{
+			Type_arraybuffer,
+			Type_text
+		};
+
+		/// \struct SEncodedRegion
+		/// Descriptor of encoded region in "bufferView".
+		struct SEncodedRegion
+		{
+			const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes.
+			const size_t EncodedData_Length;///< Size of encoded region, in bytes.
+			uint8_t* const DecodedData;///< Cached encoded data.
+			const size_t DecodedData_Length;///< Size of decoded region, in bytes.
+			const std::string ID;///< ID of the region.
+
+			/// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
+			/// Constructor.
+			/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
+			/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
+			/// \param [in] pDecodedData - pointer to decoded data array.
+			/// \param [in] pDecodedData_Length - size of encoded region, in bytes.
+			/// \param [in] pID - ID of the region.
+			SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
+				: Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID)
+			{}
+
+			/// \fn ~SEncodedRegion()
+			/// Destructor.
+			~SEncodedRegion() { delete [] DecodedData; }
+		};
+
+		/******************* Variables *******************/
+
+		//std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
+		size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
+		//std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
+
+		Type type;
+
+		/// \var EncodedRegion_Current
+		/// Pointer to currently active encoded region.
+		/// Why not decoding all regions at once and not to set one buffer with decoded data?
+		/// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded
+		/// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But
+		/// offset is counted for another regions is encoded.
+		/// Example. You have two meshes. For every of it you have 4 bytes of data. That data compressed to 2 bytes. So, you have buffer with encoded data:
+		/// M1_E0, M1_E1, M2_E0, M2_E1.
+		/// After decoding you'll get:
+		/// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3.
+		/// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like
+		/// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4}
+		/// but in real life you'll get:
+		/// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4}
+		/// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded.
+		/// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished
+		/// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data.
+		///
+		/// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in
+		/// exporter and importer. And, thanks to such way, there is no need to load whole file into memory.
+		SEncodedRegion* EncodedRegion_Current;
+
+	private:
+
+		shared_ptr<uint8_t> mData; //!< Pointer to the data
+		bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
+
+		/// \var EncodedRegion_List
+		/// List of encoded regions.
+		std::list<SEncodedRegion*> EncodedRegion_List;
+
+		/******************* Functions *******************/
+
+	public:
+
+		Buffer();
+		~Buffer();
+
+		void Read(Value& obj, Asset& r);
 
 
         bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0);
         bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0);
 
 
+		/// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
+		/// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
+		/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
+		/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
+		/// \param [in] pDecodedData - pointer to decoded data array.
+		/// \param [in] pDecodedData_Length - size of encoded region, in bytes.
+		/// \param [in] pID - ID of the region.
+		void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID);
+
+		/// \fn void EncodedRegion_SetCurrent(const std::string& pID)
+		/// Select current encoded region by ID. \sa EncodedRegion_Current.
+		/// \param [in] pID - ID of the region.
+		void EncodedRegion_SetCurrent(const std::string& pID);
+
+		/// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
+		/// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
+		/// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
+		/// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
+		/// \param [in] pReplace_Data - pointer to array with new data for buffer.
+		/// \param [in] pReplace_Count - count of bytes in new data.
+		/// \return true - if successfully replaced, false if input arguments is out of range.
+		bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count);
+
         size_t AppendData(uint8_t* data, size_t length);
         size_t AppendData(uint8_t* data, size_t length);
         void Grow(size_t amount);
         void Grow(size_t amount);
 
 
@@ -495,7 +577,6 @@ namespace glTF
         static const char* TranslateId(Asset& r, const char* id);
         static const char* TranslateId(Asset& r, const char* id);
     };
     };
 
 
-
     //! A view into a buffer generally representing a subset of the buffer.
     //! A view into a buffer generally representing a subset of the buffer.
     struct BufferView : public Object
     struct BufferView : public Object
     {
     {
@@ -505,11 +586,9 @@ namespace glTF
 
 
         BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
         BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
 
 
-        BufferView() {}
         void Read(Value& obj, Asset& r);
         void Read(Value& obj, Asset& r);
     };
     };
 
 
-
     struct Camera : public Object
     struct Camera : public Object
     {
     {
         enum Type
         enum Type
@@ -634,10 +713,77 @@ namespace glTF
             Ref<Material> material;
             Ref<Material> material;
         };
         };
 
 
+		/// \struct SExtension
+		/// Extension used for mesh.
+		struct SExtension
+		{
+			/// \enum EType
+			/// Type of extension.
+			enum EType
+			{
+				#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+					Compression_Open3DGC,///< Compression of mesh data using Open3DGC algorythm.
+				#endif
+
+				Unknown
+			};
+
+			EType Type;///< Type of extension.
+
+			/// \fn SExtension
+			/// Constructor.
+			/// \param [in] pType - type of extension.
+			SExtension(const EType pType)
+				: Type(pType)
+			{}
+		};
+
+		#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+			/// \struct SCompression_Open3DGC
+			/// Compression of mesh data using Open3DGC algorythm.
+			struct SCompression_Open3DGC : public SExtension
+			{
+				using SExtension::Type;
+
+				std::string Buffer;///< ID of "buffer" used for storing compressed data.
+				size_t Offset;///< Offset in "bufferView" where compressed data are stored.
+				size_t Count;///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type".
+				bool Binary;///< If true then "binary" mode is used for coding, if false - "ascii" mode.
+				size_t IndicesCount;///< Count of indices in mesh.
+				size_t VerticesCount;///< Count of vertices in mesh.
+				// AttribType::Value Type;///< Is always "SCALAR".
+				// ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121).
+
+				/// \fn SCompression_Open3DGC
+				/// Constructor.
+				SCompression_Open3DGC()
+				: SExtension(Compression_Open3DGC)
+				{}
+			};
+		#endif
+
         std::vector<Primitive> primitives;
         std::vector<Primitive> primitives;
+		std::list<SExtension*> Extension;///< List of extensions used in mesh.
 
 
         Mesh() {}
         Mesh() {}
-        void Read(Value& obj, Asset& r);
+
+		/// \fn ~Mesh()
+		/// Destructor.
+		~Mesh() { for(std::list<SExtension*>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { delete *it; }; }
+
+		/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)
+		/// Get mesh data from JSON-object and place them to root asset.
+		/// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
+		/// \param [out] pAsset_Root - reference to root assed where data will be stored.
+		void Read(Value& pJSON_Object, Asset& pAsset_Root);
+
+		#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+			/// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
+			/// Decode part of "buffer" which encoded with Open3DGC algorithm.
+			/// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
+			/// \param [out] pAsset_Root - reference to root assed where data will be stored.
+			void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root);
+		#endif
     };
     };
 
 
     struct Node : public Object
     struct Node : public Object
@@ -808,6 +954,7 @@ namespace glTF
 
 
         Ref<T> Get(const char* id);
         Ref<T> Get(const char* id);
         Ref<T> Get(unsigned int i);
         Ref<T> Get(unsigned int i);
+		Ref<T> Get(const std::string& pID) { return Get(pID.c_str()); }
 
 
         Ref<T> Create(const char* id);
         Ref<T> Create(const char* id);
         Ref<T> Create(const std::string& id)
         Ref<T> Create(const std::string& id)

+ 341 - 10
code/glTFAsset.inl

@@ -1,4 +1,4 @@
-/*
+/*
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
@@ -40,6 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "StringUtils.h"
 #include "StringUtils.h"
 
 
+// Header files, Assimp
+#include <assimp/DefaultLogger.hpp>
+
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+	// Header files, Open3DGC.
+#	include <Open3DGC/o3dgcSC3DMCDecoder.h>
+#endif
+
 using namespace Assimp;
 using namespace Assimp;
 
 
 namespace glTF {
 namespace glTF {
@@ -243,9 +251,14 @@ Ref<T> LazyDict<T>::Create(const char* id)
 
 
 
 
 inline Buffer::Buffer()
 inline Buffer::Buffer()
-: byteLength(0), type(Type_arraybuffer), mIsSpecial(false)
+	: byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false)
 { }
 { }
 
 
+inline Buffer::~Buffer()
+{
+	for(SEncodedRegion* reg : EncodedRegion_List) delete reg;
+}
+
 inline const char* Buffer::TranslateId(Asset& r, const char* id)
 inline const char* Buffer::TranslateId(Asset& r, const char* id)
 {
 {
     // Compatibility with old spec
     // Compatibility with old spec
@@ -326,6 +339,79 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO
     return true;
     return true;
 }
 }
 
 
+inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
+{
+	// Check pointer to data
+	if(pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided.");
+
+	// Check offset
+	if(pOffset > byteLength)
+	{
+		const uint8_t val_size = 32;
+
+		char val[val_size];
+
+		ai_snprintf(val, val_size, "%llu", (long long)pOffset);
+		throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region.");
+	}
+
+	// Check length
+	if((pOffset + pEncodedData_Length) > byteLength)
+	{
+		const uint8_t val_size = 64;
+
+		char val[val_size];
+
+		ai_snprintf(val, val_size, "%llu, %llu", (long long)pOffset, (long long)pEncodedData_Length);
+		throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range.");
+	}
+
+	// Add new region
+	EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID));
+	// And set new value for "byteLength"
+	byteLength += (pDecodedData_Length - pEncodedData_Length);
+}
+
+inline void Buffer::EncodedRegion_SetCurrent(const std::string& pID)
+{
+	if((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return;
+
+	for(SEncodedRegion* reg : EncodedRegion_List)
+	{
+		if(reg->ID == pID)
+		{
+			EncodedRegion_Current = reg;
+
+			return;
+		}
+
+	}
+
+	throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found.");
+}
+
+inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
+{
+const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
+
+uint8_t* new_data;
+
+	if((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false;
+
+	new_data = new uint8_t[new_data_size];
+	// Copy data which place before replacing part.
+	memcpy(new_data, mData.get(), pBufferData_Offset);
+	// Copy new data.
+	memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
+	// Copy data which place after replacing part.
+	memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset);
+	// Apply new data
+	mData.reset(new_data);
+	byteLength = new_data_size;
+
+	return true;
+}
+
 inline size_t Buffer::AppendData(uint8_t* data, size_t length)
 inline size_t Buffer::AppendData(uint8_t* data, size_t length)
 {
 {
     size_t offset = this->byteLength;
     size_t offset = this->byteLength;
@@ -343,6 +429,9 @@ inline void Buffer::Grow(size_t amount)
     byteLength += amount;
     byteLength += amount;
 }
 }
 
 
+//
+// struct BufferView
+//
 
 
 inline void BufferView::Read(Value& obj, Asset& r)
 inline void BufferView::Read(Value& obj, Asset& r)
 {
 {
@@ -355,7 +444,9 @@ inline void BufferView::Read(Value& obj, Asset& r)
     byteLength = MemberOrDefault(obj, "byteLength", 0u);
     byteLength = MemberOrDefault(obj, "byteLength", 0u);
 }
 }
 
 
-
+//
+// struct Accessor
+//
 
 
 inline void Accessor::Read(Value& obj, Asset& r)
 inline void Accessor::Read(Value& obj, Asset& r)
 {
 {
@@ -395,7 +486,18 @@ inline uint8_t* Accessor::GetPointer()
     if (!basePtr) return 0;
     if (!basePtr) return 0;
 
 
     size_t offset = byteOffset + bufferView->byteOffset;
     size_t offset = byteOffset + bufferView->byteOffset;
-    return basePtr + offset;
+
+	// Check if region is encoded.
+	if(bufferView->buffer->EncodedRegion_Current != nullptr)
+	{
+		const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
+		const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
+
+		if((offset >= begin) && (offset < end))
+			return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
+	}
+
+	return basePtr + offset;
 }
 }
 
 
 namespace {
 namespace {
@@ -678,9 +780,10 @@ namespace {
     }
     }
 }
 }
 
 
-inline void Mesh::Read(Value& obj, Asset& r)
-{  
-    if (Value* primitives = FindArray(obj, "primitives")) {
+inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
+{
+	/****************** Mesh primitives ******************/
+	if (Value* primitives = FindArray(pJSON_Object, "primitives")) {
         this->primitives.resize(primitives->Size());
         this->primitives.resize(primitives->Size());
         for (unsigned int i = 0; i < primitives->Size(); ++i) {
         for (unsigned int i = 0; i < primitives->Size(); ++i) {
             Value& primitive = (*primitives)[i];
             Value& primitive = (*primitives)[i];
@@ -700,22 +803,250 @@ inline void Mesh::Read(Value& obj, Asset& r)
                     if (GetAttribVector(prim, attr, vec, undPos)) {
                     if (GetAttribVector(prim, attr, vec, undPos)) {
                         size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
                         size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
                         if ((*vec).size() <= idx) (*vec).resize(idx + 1);
                         if ((*vec).size() <= idx) (*vec).resize(idx + 1);
-                        (*vec)[idx] = r.accessors.Get(it->value.GetString());
+						(*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString());
                     }
                     }
                 }
                 }
             }
             }
 
 
             if (Value* indices = FindString(primitive, "indices")) {
             if (Value* indices = FindString(primitive, "indices")) {
-                prim.indices = r.accessors.Get(indices->GetString());
+				prim.indices = pAsset_Root.accessors.Get(indices->GetString());
             }
             }
 
 
             if (Value* material = FindString(primitive, "material")) {
             if (Value* material = FindString(primitive, "material")) {
-                prim.material = r.materials.Get(material->GetString());
+				prim.material = pAsset_Root.materials.Get(material->GetString());
             }
             }
         }
         }
     }
     }
+
+	/****************** Mesh extensions ******************/
+	Value* json_extensions = FindObject(pJSON_Object, "extensions");
+
+	if(json_extensions == nullptr) goto mr_skip_extensions;
+
+	for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++)
+	{
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+        if(it_memb->name.GetString() == std::string("Open3DGC-compression"))
+		{
+			// Search for compressed data.
+			// Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and
+			// new data will replace old encoded part by request. In fact \"compressedData\" is kind of "accessor" structure.
+			Value* comp_data = FindObject(it_memb->value, "compressedData");
+
+			if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\".");
+
+			DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data.");
+
+			/************** Read data from JSON-document **************/
+			#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
+				if(!ReadMember(*comp_data, pFieldName, pOut)) \
+				{ \
+					throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); \
+				}
+
+			const char* mode_str;
+			const char* type_str;
+			ComponentType component_type;
+			SCompression_Open3DGC* ext_o3dgc = new SCompression_Open3DGC;
+
+			MESH_READ_COMPRESSEDDATA_MEMBER("buffer", ext_o3dgc->Buffer);
+			MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", ext_o3dgc->Offset);
+			MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type);
+			MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str);
+			MESH_READ_COMPRESSEDDATA_MEMBER("count", ext_o3dgc->Count);
+			MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str);
+			MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", ext_o3dgc->IndicesCount);
+			MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", ext_o3dgc->VerticesCount);
+
+			#undef MESH_READ_COMPRESSEDDATA_MEMBER
+
+			// Check some values
+			if(strcmp(type_str, "SCALAR")) throw DeadlyImportError("GLTF: only \"SCALAR\" type is supported for compressed data.");
+			if(component_type != ComponentType_UNSIGNED_BYTE) throw DeadlyImportError("GLTF: only \"UNSIGNED_BYTE\" component type is supported for compressed data.");
+
+			// Set read/write data mode.
+			if(strcmp(mode_str, "binary") == 0)
+				ext_o3dgc->Binary = true;
+			else if(strcmp(mode_str, "ascii") == 0)
+				ext_o3dgc->Binary = false;
+			else
+				throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\".");
+
+			/************************ Decoding ************************/
+			Decode_O3DGC(*ext_o3dgc, pAsset_Root);
+			Extension.push_back(ext_o3dgc);// store info in mesh extensions list.
+		}// if(it_memb->name.GetString() == "Open3DGC-compression")
+		else
+#endif
+		{
+			throw DeadlyImportError(std::string("GLTF: Unknown mesh extension: \"") + it_memb->name.GetString() + "\".");
+		}
+	}// for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
+
+mr_skip_extensions:
+
+	return;// After label some operators must be present.
 }
 }
 
 
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
+{
+typedef unsigned short IndicesType;///< \sa glTFExporter::ExportMeshes.
+
+o3dgc::SC3DMCDecoder<IndicesType> decoder;
+o3dgc::IndexedFaceSet<IndicesType> ifs;
+o3dgc::BinaryStream bstream;
+uint8_t* decoded_data;
+size_t decoded_data_size = 0;
+Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
+
+	// Read data from buffer and place it in BinaryStream for decoder.
+	// Just "Count" because always is used type equivalent to uint8_t.
+	bstream.LoadFromBuffer(&buf->GetPointer()[pCompression_Open3DGC.Offset], pCompression_Open3DGC.Count);
+
+	// After decoding header we can get size of primitives.
+	if(decoder.DecodeHeader(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC header.");
+
+	/****************** Get sizes of arrays and check sizes ******************/
+	// Note. See "Limitations for meshes when using Open3DGC-compression".
+
+	// Indices
+	size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note.
+
+	if(primitives[0].indices->count != size_coordindex)
+		throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + std::to_string(size_coordindex) +
+								") not equal to uncompressed (" + std::to_string(primitives[0].indices->count) + ").");
+
+	size_coordindex *= sizeof(IndicesType);
+	// Coordinates
+	size_t size_coord = ifs.GetNCoord();// See float attributes note.
+
+	if(primitives[0].attributes.position[0]->count != size_coord)
+		throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + std::to_string(size_coord) +
+								") not equal to uncompressed (" + std::to_string(primitives[0].attributes.position[0]->count) + ").");
+
+	size_coord *= 3 * sizeof(float);
+	// Normals
+	size_t size_normal = ifs.GetNNormal();// See float attributes note.
+
+	if(primitives[0].attributes.normal[0]->count != size_normal)
+		throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + std::to_string(size_normal) +
+								") not equal to uncompressed (" + std::to_string(primitives[0].attributes.normal[0]->count) + ").");
+
+	size_normal *= 3 * sizeof(float);
+	// Additional attributes.
+	std::vector<size_t> size_floatattr;
+	std::vector<size_t> size_intattr;
+
+	size_floatattr.resize(ifs.GetNumFloatAttributes());
+	size_intattr.resize(ifs.GetNumIntAttributes());
+
+	decoded_data_size = size_coordindex + size_coord + size_normal;
+	for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++)
+	{
+		// size = number_of_elements * components_per_element * size_of_component.
+		// Note. But as you can see above, at first we are use this variable in meaning "count". After checking count of objects...
+		size_t tval = ifs.GetNFloatAttribute(idx);
+
+		switch(ifs.GetFloatAttributeType(idx))
+		{
+			case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
+				// Check situation when encoded data contain texture coordinates but primitive not.
+				if(idx_texcoord < primitives[0].attributes.texcoord.size())
+				{
+					if(primitives[0].attributes.texcoord[idx]->count != tval)
+						throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + std::to_string(tval) +
+												") not equal to uncompressed (" + std::to_string(primitives[0].attributes.texcoord[idx]->count) + ").");
+
+					idx_texcoord++;
+				}
+				else
+				{
+					ifs.SetNFloatAttribute(idx, 0);// Disable decoding this attribute.
+				}
+
+				break;
+			default:
+				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + std::to_string(ifs.GetFloatAttributeType(idx)));
+		}
+
+		tval *=  ifs.GetFloatAttributeDim(idx) * sizeof(o3dgc::Real);// After checking count of objects we can get size of array.
+		size_floatattr[idx] = tval;
+		decoded_data_size += tval;
+	}
+
+	for(size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++)
+	{
+		// size = number_of_elements * components_per_element * size_of_component. See float attributes note.
+		size_t tval = ifs.GetNIntAttribute(idx);
+
+		switch(ifs.GetIntAttributeType(idx))
+		{
+			default:
+				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + std::to_string(ifs.GetIntAttributeType(idx)));
+		}
+
+		tval *= ifs.GetIntAttributeDim(idx) * sizeof(long);// See float attributes note.
+		size_intattr[idx] = tval;
+		decoded_data_size += tval;
+	}
+
+	// Create array for decoded data.
+	decoded_data = new uint8_t[decoded_data_size];
+
+	/****************** Set right array regions for decoder ******************/
+
+	auto get_buf_offset = [](Ref<Accessor>& pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; };
+
+	// Indices
+	ifs.SetCoordIndex((IndicesType* const)(decoded_data + get_buf_offset(primitives[0].indices)));
+	// Coordinates
+	ifs.SetCoord((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.position[0])));
+	// Normals
+	if(size_normal)
+	{
+		ifs.SetNormal((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0])));
+	}
+
+	for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++)
+	{
+		switch(ifs.GetFloatAttributeType(idx))
+		{
+			case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
+				if(idx_texcoord < primitives[0].attributes.texcoord.size())
+				{
+					// See above about absent attributes.
+					ifs.SetFloatAttribute(idx, (o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
+					idx_texcoord++;
+				}
+
+				break;
+			default:
+				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + std::to_string(ifs.GetFloatAttributeType(idx)));
+		}
+	}
+
+	for(size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++)
+	{
+		switch(ifs.GetIntAttributeType(idx))
+		{
+			// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
+			default:
+				throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + std::to_string(ifs.GetIntAttributeType(idx)));
+		}
+	}
+
+	//
+	// Decode data
+	//
+	if(decoder.DecodePayload(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC data.");
+
+	// Set encoded region for "buffer".
+	buf->EncodedRegion_Mark(pCompression_Open3DGC.Offset, pCompression_Open3DGC.Count, decoded_data, decoded_data_size, id);
+	// No. Do not delete "output_data". After calling "EncodedRegion_Mark" bufferView is owner of "output_data".
+	// "delete [] output_data;"
+}
+#endif
 
 
 inline void Camera::Read(Value& obj, Asset& r)
 inline void Camera::Read(Value& obj, Asset& r)
 {
 {

+ 58 - 4
code/glTFAssetWriter.inl

@@ -1,4 +1,4 @@
-/*
+/*
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
@@ -56,11 +56,11 @@ namespace glTF {
         inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
         inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
             val.SetArray();
             val.SetArray();
             val.Reserve(N, al);
             val.Reserve(N, al);
-            for (int i = 0; i < N; ++i) {
+			for (decltype(N) i = 0; i < N; ++i) {
                 val.PushBack(r[i], al);
                 val.PushBack(r[i], al);
             }
             }
             return val;
             return val;
-        };
+        }
 
 
         template<class T>
         template<class T>
         inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
         inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
@@ -72,7 +72,7 @@ namespace glTF {
                 lst.PushBack(StringRef(v[i]->id), al);
                 lst.PushBack(StringRef(v[i]->id), al);
             }
             }
             obj.AddMember(StringRef(fieldId), lst, al);
             obj.AddMember(StringRef(fieldId), lst, al);
-        };
+        }
 
 
 
 
     }
     }
@@ -196,6 +196,60 @@ namespace glTF {
 
 
     inline void Write(Value& obj, Mesh& m, AssetWriter& w)
     inline void Write(Value& obj, Mesh& m, AssetWriter& w)
     {
     {
+		/********************* Name **********************/
+		obj.AddMember("name", m.name, w.mAl);
+
+		/**************** Mesh extensions ****************/
+		if(m.Extension.size() > 0)
+		{
+			Value json_extensions;
+
+			json_extensions.SetObject();
+			for(Mesh::SExtension* ptr_ext : m.Extension)
+			{
+				switch(ptr_ext->Type)
+				{
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+					case Mesh::SExtension::EType::Compression_Open3DGC:
+						{
+							Value json_comp_data;
+							Mesh::SCompression_Open3DGC* ptr_ext_comp = (Mesh::SCompression_Open3DGC*)ptr_ext;
+
+							// filling object "compressedData"
+							json_comp_data.SetObject();
+							json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl);
+							json_comp_data.AddMember("byteOffset", ptr_ext_comp->Offset, w.mAl);
+							json_comp_data.AddMember("componentType", 5121, w.mAl);
+							json_comp_data.AddMember("type", "SCALAR", w.mAl);
+							json_comp_data.AddMember("count", ptr_ext_comp->Count, w.mAl);
+							if(ptr_ext_comp->Binary)
+								json_comp_data.AddMember("mode", "binary", w.mAl);
+							else
+								json_comp_data.AddMember("mode", "ascii", w.mAl);
+
+							json_comp_data.AddMember("indicesCount", ptr_ext_comp->IndicesCount, w.mAl);
+							json_comp_data.AddMember("verticesCount", ptr_ext_comp->VerticesCount, w.mAl);
+							// filling object "Open3DGC-compression"
+							Value json_o3dgc;
+
+							json_o3dgc.SetObject();
+							json_o3dgc.AddMember("compressedData", json_comp_data, w.mAl);
+							// add member to object "extensions"
+							json_extensions.AddMember("Open3DGC-compression", json_o3dgc, w.mAl);
+						}
+
+						break;
+#endif
+					default:
+						throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported.");
+				}// switch(ptr_ext->Type)
+			}// for(Mesh::SExtension* ptr_ext : m.Extension)
+
+			// Add extensions to mesh
+			obj.AddMember("extensions", json_extensions, w.mAl);
+		}// if(m.Extension.size() > 0)
+
+		/****************** Primitives *******************/
         Value primitives;
         Value primitives;
         primitives.SetArray();
         primitives.SetArray();
         primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
         primitives.Reserve(unsigned(m.primitives.size()), w.mAl);

+ 179 - 17
code/glTFExporter.cpp

@@ -1,4 +1,4 @@
-/*
+/*
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
@@ -58,10 +58,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/material.h>
 #include <assimp/material.h>
 #include <assimp/scene.h>
 #include <assimp/scene.h>
 
 
+// Header files, standart library.
 #include <memory>
 #include <memory>
+#include <inttypes.h>
 
 
 #include "glTFAssetWriter.h"
 #include "glTFAssetWriter.h"
 
 
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+	// Header files, Open3DGC.
+#	include <Open3DGC/o3dgcSC3DMCEncoder.h>
+#endif
+
 using namespace rapidjson;
 using namespace rapidjson;
 
 
 using namespace Assimp;
 using namespace Assimp;
@@ -271,17 +278,58 @@ void glTFExporter::ExportMaterials()
 
 
 void glTFExporter::ExportMeshes()
 void glTFExporter::ExportMeshes()
 {
 {
+    // Not for
+    //     using IndicesType = decltype(aiFace::mNumIndices);
+    // But yes for
+    //     using IndicesType = unsigned short;
+    // because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
+    typedef unsigned short IndicesType;
+
+    // Variables needed for compression. BEGIN.
+    // Indices, not pointers - because pointer to buffer is changin while writing to it.
+    size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
+    size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
+    std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
+    size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
+    bool comp_allow;// Point that data of current mesh can be compressed.
+    // Variables needed for compression. END.
+
     std::string fname = std::string(mFilename);
     std::string fname = std::string(mFilename);
     std::string bufferIdPrefix = fname.substr(0, fname.find("."));
     std::string bufferIdPrefix = fname.substr(0, fname.find("."));
     std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str());
     std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str());
 
 
     Ref<Buffer> b = mAsset->GetBodyBuffer();
     Ref<Buffer> b = mAsset->GetBodyBuffer();
     if (!b) {
     if (!b) {
-        b = mAsset->buffers.Create(bufferId);
+       b = mAsset->buffers.Create(bufferId);
     }
     }
 
 
-    for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
-        const aiMesh* aim = mScene->mMeshes[i];
+	for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
+		const aiMesh* aim = mScene->mMeshes[idx_mesh];
+
+		// Check if compressing requested and mesh can be encoded.
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+		comp_allow = mProperties->GetPropertyBool("extensions.Open3DGC.use", false);
+#else
+		comp_allow = false;
+#endif
+
+		if(comp_allow && (aim->mPrimitiveTypes == aiPrimitiveType_TRIANGLE) && (aim->mNumVertices > 0) && (aim->mNumFaces > 0))
+		{
+			idx_srcdata_tc.clear();
+			idx_srcdata_tc.reserve(AI_MAX_NUMBER_OF_TEXTURECOORDS);
+		}
+		else
+		{
+			std::string msg;
+
+			if(aim->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
+				msg = "all primitives of the mesh must be a triangles.";
+			else
+				msg = "mesh must has vertices and faces.";
+
+			DefaultLogger::get()->warn("GLTF: can not use Open3DGC-compression: " + msg);
+            comp_allow = false;
+		}
 
 
         std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh");
         std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh");
         Ref<Mesh> m = mAsset->meshes.Create(meshId);
         Ref<Mesh> m = mAsset->meshes.Create(meshId);
@@ -290,31 +338,53 @@ void glTFExporter::ExportMeshes()
 
 
         p.material = mAsset->materials.Get(aim->mMaterialIndex);
         p.material = mAsset->materials.Get(aim->mMaterialIndex);
 
 
+		/******************* Vertices ********************/
+		// If compression is used then you need parameters of uncompressed region: begin and size. At this step "begin" is stored.
+		if(comp_allow) idx_srcdata_begin = b->byteLength;
+
         Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
         Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
-        if (v) p.attributes.position.push_back(v);
+		if (v) p.attributes.position.push_back(v);
+
+		/******************** Normals ********************/
+		if(comp_allow && (aim->mNormals > 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array.
 
 
-        Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
-        if (n) p.attributes.normal.push_back(n);
+		Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
+		if (n) p.attributes.normal.push_back(n);
 
 
+		/************** Texture coordinates **************/
         for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
         for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+            // Flip UV y coords
+            if (aim -> mNumUVComponents[i] > 1) {
+                for (unsigned int j = 0; j < aim->mNumVertices; ++j) {
+                    aim->mTextureCoords[i][j].y = 1 - aim->mTextureCoords[i][j].y;
+                }
+            }
+
             if (aim->mNumUVComponents[i] > 0) {
             if (aim->mNumUVComponents[i] > 0) {
                 AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
                 AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
-                Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true);
-                if (tc) p.attributes.texcoord.push_back(tc);
-            }
-        }
 
 
-        if (aim->mNumFaces > 0) {
-            unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices;
-            std::vector<uint16_t> indices;
+				if(comp_allow) idx_srcdata_tc.push_back(b->byteLength);// Store index of texture coordinates array.
+
+				Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true);
+				if (tc) p.attributes.texcoord.push_back(tc);
+			}
+		}
+
+		/*************** Vertices indices ****************/
+		idx_srcdata_ind = b->byteLength;// Store index of indices array.
+
+		if (aim->mNumFaces > 0) {
+			std::vector<IndicesType> indices;
+			unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices;
             indices.resize(aim->mNumFaces * nIndicesPerFace);
             indices.resize(aim->mNumFaces * nIndicesPerFace);
             for (size_t i = 0; i < aim->mNumFaces; ++i) {
             for (size_t i = 0; i < aim->mNumFaces; ++i) {
                 for (size_t j = 0; j < nIndicesPerFace; ++j) {
                 for (size_t j = 0; j < nIndicesPerFace; ++j) {
                     indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]);
                     indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]);
                 }
                 }
             }
             }
-            p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT, true);
-        }
+
+			p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT, true);
+		}
 
 
         switch (aim->mPrimitiveTypes) {
         switch (aim->mPrimitiveTypes) {
             case aiPrimitiveType_POLYGON:
             case aiPrimitiveType_POLYGON:
@@ -326,7 +396,99 @@ void glTFExporter::ExportMeshes()
             default: // aiPrimitiveType_TRIANGLE
             default: // aiPrimitiveType_TRIANGLE
                 p.mode = PrimitiveMode_TRIANGLES;
                 p.mode = PrimitiveMode_TRIANGLES;
         }
         }
-    }
+
+		/****************** Compression ******************/
+		///TODO: animation: weights, joints.
+		if(comp_allow)
+		{
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+			// Only one type of compression supported at now - Open3DGC.
+			//
+			o3dgc::BinaryStream bs;
+			o3dgc::SC3DMCEncoder<IndicesType> encoder;
+			o3dgc::IndexedFaceSet<IndicesType> comp_o3dgc_ifs;
+			o3dgc::SC3DMCEncodeParams comp_o3dgc_params;
+
+			//
+			// Fill data for encoder.
+			//
+			// Quantization
+			unsigned quant_coord = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.POSITION", 12);
+			unsigned quant_normal = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.NORMAL", 10);
+			unsigned quant_texcoord = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.TEXCOORD", 10);
+
+			// Prediction
+			o3dgc::O3DGCSC3DMCPredictionMode prediction_position = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
+			o3dgc::O3DGCSC3DMCPredictionMode prediction_normal =  o3dgc::O3DGC_SC3DMC_SURF_NORMALS_PREDICTION;
+			o3dgc::O3DGCSC3DMCPredictionMode prediction_texcoord = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
+
+			// IndexedFacesSet: "Crease angle", "solid", "convex" are set to default.
+			comp_o3dgc_ifs.SetCCW(true);
+			comp_o3dgc_ifs.SetIsTriangularMesh(true);
+			comp_o3dgc_ifs.SetNumFloatAttributes(0);
+			// Coordinates
+			comp_o3dgc_params.SetCoordQuantBits(quant_coord);
+			comp_o3dgc_params.SetCoordPredMode(prediction_position);
+			comp_o3dgc_ifs.SetNCoord(aim->mNumVertices);
+			comp_o3dgc_ifs.SetCoord((o3dgc::Real* const)&b->GetPointer()[idx_srcdata_begin]);
+			// Normals
+			if(idx_srcdata_normal != SIZE_MAX)
+			{
+				comp_o3dgc_params.SetNormalQuantBits(quant_normal);
+				comp_o3dgc_params.SetNormalPredMode(prediction_normal);
+				comp_o3dgc_ifs.SetNNormal(aim->mNumVertices);
+				comp_o3dgc_ifs.SetNormal((o3dgc::Real* const)&b->GetPointer()[idx_srcdata_normal]);
+			}
+
+			// Texture coordinates
+			for(size_t num_tc = 0; num_tc < idx_srcdata_tc.size(); num_tc++)
+			{
+				size_t num = comp_o3dgc_ifs.GetNumFloatAttributes();
+
+				comp_o3dgc_params.SetFloatAttributeQuantBits(num, quant_texcoord);
+				comp_o3dgc_params.SetFloatAttributePredMode(num, prediction_texcoord);
+				comp_o3dgc_ifs.SetNFloatAttribute(num, aim->mNumVertices);// number of elements.
+				comp_o3dgc_ifs.SetFloatAttributeDim(num, aim->mNumUVComponents[num_tc]);// components per element: aiVector3D => x * float
+				comp_o3dgc_ifs.SetFloatAttributeType(num, o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD);
+				comp_o3dgc_ifs.SetFloatAttribute(num, (o3dgc::Real* const)&b->GetPointer()[idx_srcdata_tc[num_tc]]);
+				comp_o3dgc_ifs.SetNumFloatAttributes(num + 1);
+			}
+
+			// Coordinates indices
+			comp_o3dgc_ifs.SetNCoordIndex(aim->mNumFaces);
+			comp_o3dgc_ifs.SetCoordIndex((IndicesType* const)&b->GetPointer()[idx_srcdata_ind]);
+			// Prepare to enconding
+			comp_o3dgc_params.SetNumFloatAttributes(comp_o3dgc_ifs.GetNumFloatAttributes());
+			if(mProperties->GetPropertyBool("extensions.Open3DGC.binary", true))
+				comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_BINARY);
+			else
+				comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_ASCII);
+
+			comp_o3dgc_ifs.ComputeMinMax(o3dgc::O3DGC_SC3DMC_MAX_ALL_DIMS);
+			//
+			// Encoding
+			//
+			encoder.Encode(comp_o3dgc_params, comp_o3dgc_ifs, bs);
+			// Replace data in buffer.
+			b->ReplaceData(idx_srcdata_begin, b->byteLength - idx_srcdata_begin, bs.GetBuffer(), bs.GetSize());
+			//
+			// Add information about extension to mesh.
+			//
+			// Create extension structure.
+			Mesh::SCompression_Open3DGC* ext = new Mesh::SCompression_Open3DGC;
+
+			// Fill it.
+			ext->Buffer = b->id;
+			ext->Offset = idx_srcdata_begin;
+			ext->Count = b->byteLength - idx_srcdata_begin;
+			ext->Binary = mProperties->GetPropertyBool("extensions.Open3DGC.binary");
+			ext->IndicesCount = comp_o3dgc_ifs.GetNCoordIndex() * 3;
+			ext->VerticesCount = comp_o3dgc_ifs.GetNCoord();
+			// And assign to mesh.
+			m->Extension.push_back(ext);
+#endif
+		}// if(comp_allow)
+	}// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
 }
 }
 
 
 unsigned int glTFExporter::ExportNode(const aiNode* n)
 unsigned int glTFExporter::ExportNode(const aiNode* n)

+ 40 - 9
code/glTFImporter.cpp

@@ -1,4 +1,4 @@
-/*
+/*
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
@@ -259,7 +259,39 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
     for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
     for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
         Mesh& mesh = r.meshes[m];
         Mesh& mesh = r.meshes[m];
 
 
-        meshOffsets.push_back(k);
+		// Check if mesh extensions is used
+		if(mesh.Extension.size() > 0)
+		{
+			for(Mesh::SExtension* cur_ext : mesh.Extension)
+			{
+#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
+				if(cur_ext->Type == Mesh::SExtension::EType::Compression_Open3DGC)
+				{
+					// Limitations for meshes when using Open3DGC-compression.
+					// It's a current limitation of sp... Specification have not this part still - about mesh compression. Why only one primitive?
+					// Because glTF is very flexibly. But in fact it ugly flexible. Every primitive can has own set of accessors and accessors can
+					// point to a-a-a-a-any part of buffer (thru bufferview ofcourse) and even to another buffer. We know that "Open3DGC-compression"
+					// is applicable only to part of buffer. As we can't guaranty continuity of the data for decoder, we will limit quantity of primitives.
+					// Yes indices, coordinates etc. still can br stored in different buffers, but with current specification it's a exporter problem.
+					// Also primitive can has only one of "POSITION", "NORMAL" and less then "AI_MAX_NUMBER_OF_TEXTURECOORDS" of "TEXCOORD". All accessor
+					// of primitive must point to one continuous region of the buffer.
+					if(mesh.primitives.size() > 2) throw DeadlyImportError("GLTF: When using Open3DGC compression then only one primitive per mesh are allowed.");
+
+					Mesh::SCompression_Open3DGC* o3dgc_ext = (Mesh::SCompression_Open3DGC*)cur_ext;
+					Ref<Buffer> buf = r.buffers.Get(o3dgc_ext->Buffer);
+
+					buf->EncodedRegion_SetCurrent(mesh.id);
+				}
+				else
+#endif
+				{
+					throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension (code: \"" + std::to_string(cur_ext->Type) +
+											"\"), only Open3DGC is supported.");
+				}
+			}
+		}// if(mesh.Extension.size() > 0)
+
+		meshOffsets.push_back(k);
         k += unsigned(mesh.primitives.size());
         k += unsigned(mesh.primitives.size());
 
 
         for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
         for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
@@ -294,14 +326,13 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
             }
             }
 
 
             Mesh::Primitive::Attributes& attr = prim.attributes;
             Mesh::Primitive::Attributes& attr = prim.attributes;
-            if (attr.position.size() > 0 && attr.position[0]) {
+
+			if (attr.position.size() > 0 && attr.position[0]) {
                 aim->mNumVertices = attr.position[0]->count;
                 aim->mNumVertices = attr.position[0]->count;
                 attr.position[0]->ExtractData(aim->mVertices);
                 attr.position[0]->ExtractData(aim->mVertices);
-            }
+			}
 
 
-            if (attr.normal.size() > 0 && attr.normal[0]) {
-                attr.normal[0]->ExtractData(aim->mNormals);
-            }
+			if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals);
 
 
             for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
             for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
                 attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
                 attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
@@ -315,7 +346,7 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
 
 
 
 
             if (prim.indices) {
             if (prim.indices) {
-                aiFace* faces = 0;
+				aiFace* faces = 0;
                 unsigned int nFaces = 0;
                 unsigned int nFaces = 0;
 
 
                 unsigned int count = prim.indices->count;
                 unsigned int count = prim.indices->count;
@@ -641,7 +672,7 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS
 
 
     // TODO: it does not split the loaded vertices, should it?
     // TODO: it does not split the loaded vertices, should it?
     //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
     //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
-    Assimp::MakeVerboseFormatProcess process;
+	MakeVerboseFormatProcess process;
     process.Execute(pScene);
     process.Execute(pScene);
     
     
 
 

+ 155 - 0
contrib/Open3DGC/o3dgcAdjacencyInfo.h

@@ -0,0 +1,155 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_ADJACENCY_INFO_H
+#define O3DGC_ADJACENCY_INFO_H
+
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    const long O3DGC_MIN_NEIGHBORS_SIZE     = 128;
+    const long O3DGC_MIN_NUM_NEIGHBORS_SIZE = 16;
+    //! 
+    class AdjacencyInfo
+    {
+    public:
+        //! Constructor.
+                                AdjacencyInfo(long numNeighborsSize = O3DGC_MIN_NUM_NEIGHBORS_SIZE,
+                                              long neighborsSize    = O3DGC_MIN_NUM_NEIGHBORS_SIZE)
+                                {
+                                    m_numElements      = 0;
+                                    m_neighborsSize    = neighborsSize; 
+                                    m_numNeighborsSize = numNeighborsSize;
+                                    m_numNeighbors     = new long [m_numNeighborsSize];
+                                    m_neighbors        = new long [m_neighborsSize   ];
+                                };
+        //! Destructor.
+                                ~AdjacencyInfo(void)
+                                {
+                                    delete [] m_neighbors;
+                                    delete [] m_numNeighbors;
+                                };
+        O3DGCErrorCode          Allocate(long numNeighborsSize, long neighborsSize)
+                                {
+                                    m_numElements = numNeighborsSize;
+                                    if (neighborsSize > m_neighborsSize)
+                                    {
+                                        delete [] m_numNeighbors;
+                                        m_neighborsSize    = neighborsSize;
+                                        m_numNeighbors     = new long [m_numNeighborsSize];
+                                    }
+                                    if (numNeighborsSize > m_numNeighborsSize)
+                                    {
+                                        delete [] m_neighbors;
+                                        m_numNeighborsSize = numNeighborsSize;
+                                        m_neighbors        = new long [m_neighborsSize];
+                                    }
+                                    return O3DGC_OK;
+                                }
+        O3DGCErrorCode          AllocateNumNeighborsArray(long numElements)
+                                {
+                                    if (numElements > m_numNeighborsSize)
+                                    {
+                                        delete [] m_numNeighbors;
+                                        m_numNeighborsSize = numElements;
+                                        m_numNeighbors = new long [m_numNeighborsSize];
+                                    }
+                                    m_numElements = numElements;
+                                    return O3DGC_OK;
+                                }
+        O3DGCErrorCode          AllocateNeighborsArray()
+                                {
+                                    for(long i = 1; i < m_numElements; ++i)
+                                    {
+                                        m_numNeighbors[i] += m_numNeighbors[i-1];
+                                    }
+                                    if (m_numNeighbors[m_numElements-1] > m_neighborsSize)
+                                    {
+                                        delete [] m_neighbors;
+                                        m_neighborsSize = m_numNeighbors[m_numElements-1];
+                                        m_neighbors = new long [m_neighborsSize];
+                                    }
+                                    return O3DGC_OK;
+                                }
+        O3DGCErrorCode          ClearNumNeighborsArray()
+                                {
+                                    memset(m_numNeighbors, 0x00, sizeof(long) * m_numElements);
+                                    return O3DGC_OK;
+                                }
+        O3DGCErrorCode          ClearNeighborsArray()
+                                {
+                                    memset(m_neighbors, 0xFF, sizeof(long) * m_neighborsSize);
+                                    return O3DGC_OK;
+                                }
+        O3DGCErrorCode          AddNeighbor(long element, long neighbor)
+                                {
+                                    assert(m_numNeighbors[element] <= m_numNeighbors[m_numElements-1]);
+                                    long p0 = Begin(element);
+                                    long p1 = End(element);
+                                    for(long p = p0; p < p1; p++)
+                                    {
+                                        if (m_neighbors[p] == -1)
+                                        {
+                                            m_neighbors[p] = neighbor;
+                                            return O3DGC_OK;
+                                        }
+                                    }
+                                    return O3DGC_ERROR_BUFFER_FULL;
+                                }
+        long                    Begin(long element) const 
+                                {
+                                    assert(element < m_numElements);
+                                    assert(element >= 0);
+                                    return (element>0)?m_numNeighbors[element-1]:0;
+                                }
+        long                    End(long element) const
+                                {
+                                    assert(element < m_numElements);
+                                    assert(element >= 0);
+                                    return m_numNeighbors[element];
+                                }
+        long                    GetNeighbor(long element) const
+                                {
+                                    assert(element < m_neighborsSize);
+                                    assert(element >= 0);
+                                    return m_neighbors[element];
+                                }    
+        long                    GetNumNeighbors(long element)  const 
+                                { 
+                                    return End(element) - Begin(element);
+                                }
+        long * const            GetNumNeighborsBuffer() { return m_numNeighbors;}
+        long * const            GetNeighborsBuffer()    { return m_neighbors;}
+
+    private:
+        long                    m_neighborsSize;    // actual allocated size for m_neighbors
+        long                    m_numNeighborsSize; // actual allocated size for m_numNeighbors
+        long                    m_numElements;      // number of elements 
+        long *                  m_neighbors;        // 
+        long *                  m_numNeighbors;     //         
+    };
+}
+#endif // O3DGC_ADJACENCY_INFO_H
+

+ 863 - 0
contrib/Open3DGC/o3dgcArithmeticCodec.cpp

@@ -0,0 +1,863 @@
+/*
+Copyright (c) 2004 Amir Said ([email protected]) & William A. Pearlman ([email protected])
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+-   Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer. 
+
+-   Redistributions in binary form must reproduce the above copyright notice, this list of 
+    conditions and the following disclaimer in the documentation and/or other materials 
+    provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+OF SUCH DAMAGE.
+
+*/
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+//                       ****************************                        -
+//                        ARITHMETIC CODING EXAMPLES                         -
+//                       ****************************                        -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+// Fast arithmetic coding implementation                                     -
+// -> 32-bit variables, 32-bit product, periodic updates, table decoding     -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+// Version 1.00  -  April 25, 2004                                           -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+//                                  WARNING                                  -
+//                                 =========                                 -
+//                                                                           -
+// The only purpose of this program is to demonstrate the basic principles   -
+// of arithmetic coding. It is provided as is, without any express or        -
+// implied warranty, without even the warranty of fitness for any particular -
+// purpose, or that the implementations are correct.                         -
+//                                                                           -
+// Permission to copy and redistribute this code is hereby granted, provided -
+// that this warning and copyright notices are not removed or altered.       -
+//                                                                           -
+// Copyright (c) 2004 by Amir Said ([email protected]) &                         -
+//                       William A. Pearlman ([email protected])           -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+// A description of the arithmetic coding method used here is available in   -
+//                                                                           -
+// Lossless Compression Handbook, ed. K. Sayood                              -
+// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
+//                                                                           -
+// A. Said, Introduction to Arithetic Coding Theory and Practice             -
+// HP Labs report HPL-2004-76  -  http://www.hpl.hp.com/techreports/         -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+// - - Inclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#include <stdlib.h>
+#include "o3dgcArithmeticCodec.h"
+
+namespace o3dgc
+{
+    // - - Constants - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    const unsigned AC__MinLength = 0x01000000U;   // threshold for renormalization
+    const unsigned AC__MaxLength = 0xFFFFFFFFU;      // maximum AC interval length
+
+                                               // Maximum values for binary models
+    const unsigned BM__LengthShift = 13;     // length bits discarded before mult.
+    const unsigned BM__MaxCount    = 1 << BM__LengthShift;  // for adaptive models
+
+                                              // Maximum values for general models
+    const unsigned DM__LengthShift = 15;     // length bits discarded before mult.
+    const unsigned DM__MaxCount    = 1 << DM__LengthShift;  // for adaptive models
+
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - - Static functions  - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    static void AC_Error(const char * msg)
+    {
+      fprintf(stderr, "\n\n -> Arithmetic coding error: ");
+      fputs(msg, stderr);
+      fputs("\n Execution terminated!\n", stderr);
+      getchar();
+      exit(1);
+    }
+
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - - Coding implementations  - - - - - - - - - - - - - - - - - - - - - - - -
+
+    inline void Arithmetic_Codec::propagate_carry(void)
+    {
+      unsigned char * p;            // carry propagation on compressed data buffer
+      for (p = ac_pointer - 1; *p == 0xFFU; p--) *p = 0;
+      ++*p;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    inline void Arithmetic_Codec::renorm_enc_interval(void)
+    {
+      do {                                          // output and discard top byte
+        *ac_pointer++ = (unsigned char)(base >> 24);
+        base <<= 8;
+      } while ((length <<= 8) < AC__MinLength);        // length multiplied by 256
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    inline void Arithmetic_Codec::renorm_dec_interval(void)
+    {
+      do {                                          // read least-significant byte
+        value = (value << 8) | unsigned(*++ac_pointer);
+      } while ((length <<= 8) < AC__MinLength);        // length multiplied by 256
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::put_bit(unsigned bit)
+    {
+    #ifdef _DEBUG
+      if (mode != 1) AC_Error("encoder not initialized");
+    #endif
+
+      length >>= 1;                                              // halve interval
+      if (bit) {
+        unsigned init_base = base;
+        base += length;                                               // move base
+        if (init_base > base) propagate_carry();               // overflow = carry
+      }
+
+      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::get_bit(void)
+    {
+    #ifdef _DEBUG
+      if (mode != 2) AC_Error("decoder not initialized");
+    #endif
+
+      length >>= 1;                                              // halve interval
+      unsigned bit = (value >= length);                              // decode bit
+      if (bit) value -= length;                                       // move base
+
+      if (length < AC__MinLength) renorm_dec_interval();        // renormalization
+
+      return bit;                                         // return data bit value
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::put_bits(unsigned data, unsigned bits)
+    {
+    #ifdef _DEBUG
+      if (mode != 1) AC_Error("encoder not initialized");
+      if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
+      if (data >= (1U << bits)) AC_Error("invalid data");
+    #endif
+
+      unsigned init_base = base;
+      base += data * (length >>= bits);            // new interval base and length
+
+      if (init_base > base) propagate_carry();                 // overflow = carry
+      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::get_bits(unsigned bits)
+    {
+    #ifdef _DEBUG
+      if (mode != 2) AC_Error("decoder not initialized");
+      if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
+    #endif
+
+      unsigned s = value / (length >>= bits);      // decode symbol, change length
+
+      value -= length * s;                                      // update interval
+      if (length < AC__MinLength) renorm_dec_interval();        // renormalization
+
+      return s;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::encode(unsigned bit,
+                                  Static_Bit_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 1) AC_Error("encoder not initialized");
+    #endif
+
+      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
+                                                                // update interval
+      if (bit == 0)
+        length  = x;
+      else {
+        unsigned init_base = base;
+        base   += x;
+        length -= x;
+        if (init_base > base) propagate_carry();               // overflow = carry
+      }
+
+      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::decode(Static_Bit_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 2) AC_Error("decoder not initialized");
+    #endif
+
+      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
+      unsigned bit = (value >= x);                                     // decision
+                                                        // update & shift interval
+      if (bit == 0)
+        length  = x;
+      else {
+        value  -= x;                                 // shifted interval base = 0
+        length -= x;
+      }
+
+      if (length < AC__MinLength) renorm_dec_interval();        // renormalization
+
+      return bit;                                         // return data bit value
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::encode(unsigned bit,
+                                  Adaptive_Bit_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 1) AC_Error("encoder not initialized");
+    #endif
+
+      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
+                                                                // update interval
+      if (bit == 0) {
+        length = x;
+        ++M.bit_0_count;
+      }
+      else {
+        unsigned init_base = base;
+        base   += x;
+        length -= x;
+        if (init_base > base) propagate_carry();               // overflow = carry
+      }
+
+      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
+
+      if (--M.bits_until_update == 0) M.update();         // periodic model update
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::decode(Adaptive_Bit_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 2) AC_Error("decoder not initialized");
+    #endif
+
+      unsigned x = M.bit_0_prob * (length >> BM__LengthShift);   // product l x p0
+      unsigned bit = (value >= x);                                     // decision
+                                                                // update interval
+      if (bit == 0) {
+        length = x;
+        ++M.bit_0_count;
+      }
+      else {
+        value  -= x;
+        length -= x;
+      }
+
+      if (length < AC__MinLength) renorm_dec_interval();        // renormalization
+
+      if (--M.bits_until_update == 0) M.update();         // periodic model update
+
+      return bit;                                         // return data bit value
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::encode(unsigned data,
+                                  Static_Data_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 1) AC_Error("encoder not initialized");
+      if (data >= M.data_symbols) AC_Error("invalid data symbol");
+    #endif
+
+      unsigned x, init_base = base;
+                                                               // compute products
+      if (data == M.last_symbol) {
+        x = M.distribution[data] * (length >> DM__LengthShift);
+        base   += x;                                            // update interval
+        length -= x;                                          // no product needed
+      }
+      else {
+        x = M.distribution[data] * (length >>= DM__LengthShift);
+        base   += x;                                            // update interval
+        length  = M.distribution[data+1] * length - x;
+      }
+             
+      if (init_base > base) propagate_carry();                 // overflow = carry
+
+      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::decode(Static_Data_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 2) AC_Error("decoder not initialized");
+    #endif
+
+      unsigned n, s, x, y = length;
+
+      if (M.decoder_table) {              // use table look-up for faster decoding
+
+        unsigned dv = value / (length >>= DM__LengthShift);
+        unsigned t = dv >> M.table_shift;
+
+        s = M.decoder_table[t];         // initial decision based on table look-up
+        n = M.decoder_table[t+1] + 1;
+
+        while (n > s + 1) {                        // finish with bisection search
+          unsigned m = (s + n) >> 1;
+          if (M.distribution[m] > dv) n = m; else s = m;
+        }
+                                                               // compute products
+        x = M.distribution[s] * length;
+        if (s != M.last_symbol) y = M.distribution[s+1] * length;
+      }
+
+      else {                                  // decode using only multiplications
+
+        x = s = 0;
+        length >>= DM__LengthShift;
+        unsigned m = (n = M.data_symbols) >> 1;
+                                                    // decode via bisection search
+        do {
+          unsigned z = length * M.distribution[m];
+          if (z > value) {
+            n = m;
+            y = z;                                             // value is smaller
+          }
+          else {
+            s = m;
+            x = z;                                     // value is larger or equal
+          }
+        } while ((m = (s + n) >> 1) != s);
+      }
+
+      value -= x;                                               // update interval
+      length = y - x;
+
+      if (length < AC__MinLength) renorm_dec_interval();        // renormalization
+
+      return s;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::encode(unsigned data,
+                                  Adaptive_Data_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 1) AC_Error("encoder not initialized");
+      if (data >= M.data_symbols) 
+      {
+          AC_Error("invalid data symbol");
+      }
+    #endif
+
+      unsigned x, init_base = base;
+                                                               // compute products
+      if (data == M.last_symbol) {
+        x = M.distribution[data] * (length >> DM__LengthShift);
+        base   += x;                                            // update interval
+        length -= x;                                          // no product needed
+      }
+      else {
+        x = M.distribution[data] * (length >>= DM__LengthShift);
+        base   += x;                                            // update interval
+        length  = M.distribution[data+1] * length - x;
+      }
+
+      if (init_base > base) propagate_carry();                 // overflow = carry
+
+      if (length < AC__MinLength) renorm_enc_interval();        // renormalization
+
+      ++M.symbol_count[data];
+      if (--M.symbols_until_update == 0) M.update(true);  // periodic model update
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::decode(Adaptive_Data_Model & M)
+    {
+    #ifdef _DEBUG
+      if (mode != 2) AC_Error("decoder not initialized");
+    #endif
+
+      unsigned n, s, x, y = length;
+
+      if (M.decoder_table) {              // use table look-up for faster decoding
+
+        unsigned dv = value / (length >>= DM__LengthShift);
+        unsigned t = dv >> M.table_shift;
+
+        s = M.decoder_table[t];         // initial decision based on table look-up
+        n = M.decoder_table[t+1] + 1;
+
+        while (n > s + 1) {                        // finish with bisection search
+          unsigned m = (s + n) >> 1;
+          if (M.distribution[m] > dv) n = m; else s = m;
+        }
+                                                               // compute products
+        x = M.distribution[s] * length;
+        if (s != M.last_symbol) {
+            y = M.distribution[s+1] * length;
+        }
+      }
+
+      else {                                  // decode using only multiplications
+
+        x = s = 0;
+        length >>= DM__LengthShift;
+        unsigned m = (n = M.data_symbols) >> 1;
+                                                    // decode via bisection search
+        do {
+          unsigned z = length * M.distribution[m];
+          if (z > value) {
+            n = m;
+            y = z;                                             // value is smaller
+          }
+          else {
+            s = m;
+            x = z;                                     // value is larger or equal
+          }
+        } while ((m = (s + n) >> 1) != s);
+      }
+
+      value -= x;                                               // update interval
+      length = y - x;
+
+      if (length < AC__MinLength) renorm_dec_interval();        // renormalization
+
+      ++M.symbol_count[s];
+      if (--M.symbols_until_update == 0) M.update(false);  // periodic model update
+
+      return s;
+    }
+
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - - Other Arithmetic_Codec implementations  - - - - - - - - - - - - - - - -
+
+    Arithmetic_Codec::Arithmetic_Codec(void)
+    {
+      mode = buffer_size = 0;
+      new_buffer = code_buffer = 0;
+    }
+
+    Arithmetic_Codec::Arithmetic_Codec(unsigned max_code_bytes,
+                                       unsigned char * user_buffer)
+    {
+      mode = buffer_size = 0;
+      new_buffer = code_buffer = 0;
+      set_buffer(max_code_bytes, user_buffer);
+    }
+
+    Arithmetic_Codec::~Arithmetic_Codec(void)
+    {
+      delete [] new_buffer;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::set_buffer(unsigned max_code_bytes,
+                                      unsigned char * user_buffer)
+    {
+                                                      // test for reasonable sizes
+      if (!max_code_bytes)// || (max_code_bytes > 0x10000000U)) // updated by K. Mammou
+      {
+        AC_Error("invalid codec buffer size");
+      }
+      if (mode != 0) AC_Error("cannot set buffer while encoding or decoding");
+
+      if (user_buffer != 0) {                       // user provides memory buffer
+        buffer_size = max_code_bytes;
+        code_buffer = user_buffer;               // set buffer for compressed data
+        delete [] new_buffer;                 // free anything previously assigned
+        new_buffer = 0;
+        return;
+      }
+
+      if (max_code_bytes <= buffer_size) return;               // enough available
+
+      buffer_size = max_code_bytes;                           // assign new memory
+      delete [] new_buffer;                   // free anything previously assigned
+      if ((new_buffer = new unsigned char[buffer_size+16]) == 0) // 16 extra bytes
+        AC_Error("cannot assign memory for compressed data buffer");
+      code_buffer = new_buffer;                  // set buffer for compressed data
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::start_encoder(void)
+    {
+      if (mode != 0) AC_Error("cannot start encoder");
+      if (buffer_size == 0) AC_Error("no code buffer set");
+
+      mode   = 1;
+      base   = 0;            // initialize encoder variables: interval and pointer
+      length = AC__MaxLength;
+      ac_pointer = code_buffer;                       // pointer to next data byte
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::start_decoder(void)
+    {
+      if (mode != 0) AC_Error("cannot start decoder");
+      if (buffer_size == 0) AC_Error("no code buffer set");
+
+                      // initialize decoder: interval, pointer, initial code value
+      mode   = 2;
+      length = AC__MaxLength;
+      ac_pointer = code_buffer + 3;
+      value = (unsigned(code_buffer[0]) << 24)|(unsigned(code_buffer[1]) << 16) |
+              (unsigned(code_buffer[2]) <<  8)| unsigned(code_buffer[3]);
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::read_from_file(FILE * code_file)
+    {
+      unsigned shift = 0, code_bytes = 0;
+      int file_byte;
+                          // read variable-length header with number of code bytes
+      do {
+        if ((file_byte = getc(code_file)) == EOF)
+          AC_Error("cannot read code from file");
+        code_bytes |= unsigned(file_byte & 0x7F) << shift;
+        shift += 7;
+      } while (file_byte & 0x80);
+                                                           // read compressed data
+      if (code_bytes > buffer_size) AC_Error("code buffer overflow");
+      if (fread(code_buffer, 1, code_bytes, code_file) != code_bytes)
+        AC_Error("cannot read code from file");
+
+      start_decoder();                                       // initialize decoder
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::stop_encoder(void)
+    {
+      if (mode != 1) AC_Error("invalid to stop encoder");
+      mode = 0;
+
+      unsigned init_base = base;            // done encoding: set final data bytes
+
+      if (length > 2 * AC__MinLength) {
+        base  += AC__MinLength;                                     // base offset
+        length = AC__MinLength >> 1;             // set new length for 1 more byte
+      }
+      else {
+        base  += AC__MinLength >> 1;                                // base offset
+        length = AC__MinLength >> 9;            // set new length for 2 more bytes
+      }
+
+      if (init_base > base) propagate_carry();                 // overflow = carry
+
+      renorm_enc_interval();                // renormalization = output last bytes
+
+      unsigned code_bytes = unsigned(ac_pointer - code_buffer);
+      if (code_bytes > buffer_size) AC_Error("code buffer overflow");
+
+      return code_bytes;                                   // number of bytes used
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    unsigned Arithmetic_Codec::write_to_file(FILE * code_file)
+    {
+      unsigned header_bytes = 0, code_bytes = stop_encoder(), nb = code_bytes;
+
+                         // write variable-length header with number of code bytes
+      do {
+        int file_byte = int(nb & 0x7FU);
+        if ((nb >>= 7) > 0) file_byte |= 0x80;
+        if (putc(file_byte, code_file) == EOF)
+          AC_Error("cannot write compressed data to file");
+        header_bytes++;
+      } while (nb);
+                                                          // write compressed data
+      if (fwrite(code_buffer, 1, code_bytes, code_file) != code_bytes)
+        AC_Error("cannot write compressed data to file");
+
+      return code_bytes + header_bytes;                              // bytes used
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Arithmetic_Codec::stop_decoder(void)
+    {
+      if (mode != 2) AC_Error("invalid to stop decoder");
+      mode = 0;
+    }
+
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - Static bit model implementation - - - - - - - - - - - - - - - - - - - - -
+
+    Static_Bit_Model::Static_Bit_Model(void)
+    {
+      bit_0_prob = 1U << (BM__LengthShift - 1);                        // p0 = 0.5
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Static_Bit_Model::set_probability_0(double p0)
+    {
+      if ((p0 < 0.0001)||(p0 > 0.9999)) AC_Error("invalid bit probability");
+      bit_0_prob = unsigned(p0 * (1 << BM__LengthShift));
+    }
+
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - Adaptive bit model implementation - - - - - - - - - - - - - - - - - - - -
+
+    Adaptive_Bit_Model::Adaptive_Bit_Model(void)
+    {
+      reset();
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Adaptive_Bit_Model::reset(void)
+    {
+                                           // initialization to equiprobable model
+      bit_0_count = 1;
+      bit_count   = 2;
+      bit_0_prob  = 1U << (BM__LengthShift - 1);
+      update_cycle = bits_until_update = 4;         // start with frequent updates
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Adaptive_Bit_Model::update(void)
+    {
+                                       // halve counts when a threshold is reached
+
+      if ((bit_count += update_cycle) > BM__MaxCount) {
+        bit_count = (bit_count + 1) >> 1;
+        bit_0_count = (bit_0_count + 1) >> 1;
+        if (bit_0_count == bit_count) ++bit_count;
+      }
+                                               // compute scaled bit 0 probability
+      unsigned scale = 0x80000000U / bit_count;
+      bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift);
+
+                                                 // set frequency of model updates
+      update_cycle = (5 * update_cycle) >> 2;
+      if (update_cycle > 64) update_cycle = 64;
+      bits_until_update = update_cycle;
+    }
+
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - - Static data model implementation  - - - - - - - - - - - - - - - - - - -
+
+    Static_Data_Model::Static_Data_Model(void)
+    {
+      data_symbols = 0;
+      distribution = 0;
+    }
+
+    Static_Data_Model::~Static_Data_Model(void)
+    {
+      delete [] distribution;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Static_Data_Model::set_distribution(unsigned number_of_symbols,
+                                             const double probability[])
+    {
+      if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
+        AC_Error("invalid number of data symbols");
+
+      if (data_symbols != number_of_symbols) {     // assign memory for data model
+        data_symbols = number_of_symbols;
+        last_symbol = data_symbols - 1;
+        delete [] distribution;
+                                         // define size of table for fast decoding
+        if (data_symbols > 16) {
+          unsigned table_bits = 3;
+          while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
+          table_size  = 1 << table_bits;
+          table_shift = DM__LengthShift - table_bits;
+          distribution = new unsigned[data_symbols+table_size+2];
+          decoder_table = distribution + data_symbols;
+        }
+        else {                                  // small alphabet: no table needed
+          decoder_table = 0;
+          table_size = table_shift = 0;
+          distribution = new unsigned[data_symbols];
+        }
+        if (distribution == 0) AC_Error("cannot assign model memory");
+      }
+                                 // compute cumulative distribution, decoder table
+      unsigned s = 0;
+      double sum = 0.0, p = 1.0 / double(data_symbols);
+
+      for (unsigned k = 0; k < data_symbols; k++) {
+        if (probability) p = probability[k];
+        if ((p < 0.0001) || (p > 0.9999)) AC_Error("invalid symbol probability");
+        distribution[k] = unsigned(sum * (1 << DM__LengthShift));
+        sum += p;
+        if (table_size == 0) continue;
+        unsigned w = distribution[k] >> table_shift;
+        while (s < w) decoder_table[++s] = k - 1;
+      }
+
+      if (table_size != 0) {
+        decoder_table[0] = 0;
+        while (s <= table_size) decoder_table[++s] = data_symbols - 1;
+      }
+
+      if ((sum < 0.9999) || (sum > 1.0001)) AC_Error("invalid probabilities");
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - - Adaptive data model implementation  - - - - - - - - - - - - - - - - - -
+
+    Adaptive_Data_Model::Adaptive_Data_Model(void)
+    {
+      data_symbols = 0;
+      distribution = 0;
+    }
+
+    Adaptive_Data_Model::Adaptive_Data_Model(unsigned number_of_symbols)
+    {
+      data_symbols = 0;
+      distribution = 0;
+      set_alphabet(number_of_symbols);
+    }
+
+    Adaptive_Data_Model::~Adaptive_Data_Model(void)
+    {
+      delete [] distribution;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Adaptive_Data_Model::set_alphabet(unsigned number_of_symbols)
+    {
+      if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
+        AC_Error("invalid number of data symbols");
+
+      if (data_symbols != number_of_symbols) {     // assign memory for data model
+        data_symbols = number_of_symbols;
+        last_symbol = data_symbols - 1;
+        delete [] distribution;
+                                         // define size of table for fast decoding
+        if (data_symbols > 16) {
+          unsigned table_bits = 3;
+          while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
+          table_size  = 1 << table_bits;
+          table_shift = DM__LengthShift - table_bits;
+          distribution = new unsigned[2*data_symbols+table_size+2];
+          decoder_table = distribution + 2 * data_symbols;
+        }
+        else {                                  // small alphabet: no table needed
+          decoder_table = 0;
+          table_size = table_shift = 0;
+          distribution = new unsigned[2*data_symbols];
+        }
+        symbol_count = distribution + data_symbols;
+        if (distribution == 0) AC_Error("cannot assign model memory");
+      }
+
+      reset();                                                 // initialize model
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Adaptive_Data_Model::update(bool from_encoder)
+    {
+                                       // halve counts when a threshold is reached
+
+      if ((total_count += update_cycle) > DM__MaxCount) {
+        total_count = 0;
+        for (unsigned n = 0; n < data_symbols; n++)
+          total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
+      }
+                                 // compute cumulative distribution, decoder table
+      unsigned k, sum = 0, s = 0;
+      unsigned scale = 0x80000000U / total_count;
+
+      if (from_encoder || (table_size == 0))
+        for (k = 0; k < data_symbols; k++) {
+          distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
+          sum += symbol_count[k];
+        }
+      else {
+        for (k = 0; k < data_symbols; k++) {
+          distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
+          sum += symbol_count[k];
+          unsigned w = distribution[k] >> table_shift;
+          while (s < w) decoder_table[++s] = k - 1;
+        }
+        decoder_table[0] = 0;
+        while (s <= table_size) decoder_table[++s] = data_symbols - 1;
+      }
+                                                 // set frequency of model updates
+      update_cycle = (5 * update_cycle) >> 2;
+      unsigned max_cycle = (data_symbols + 6) << 3;
+      if (update_cycle > max_cycle) update_cycle = max_cycle;
+      symbols_until_update = update_cycle;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    void Adaptive_Data_Model::reset(void)
+    {
+      if (data_symbols == 0) return;
+
+                          // restore probability estimates to uniform distribution
+      total_count = 0;
+      update_cycle = data_symbols;
+      for (unsigned k = 0; k < data_symbols; k++) symbol_count[k] = 1;
+      update(false);
+      symbols_until_update = update_cycle = (data_symbols + 6) >> 1;
+    }
+}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

+ 339 - 0
contrib/Open3DGC/o3dgcArithmeticCodec.h

@@ -0,0 +1,339 @@
+/*
+Copyright (c) 2004 Amir Said ([email protected]) & William A. Pearlman ([email protected])
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+-   Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer. 
+
+-   Redistributions in binary form must reproduce the above copyright notice, this list of 
+    conditions and the following disclaimer in the documentation and/or other materials 
+    provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+OF SUCH DAMAGE.
+*/
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+//                       ****************************                        -
+//                        ARITHMETIC CODING EXAMPLES                         -
+//                       ****************************                        -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+// Fast arithmetic coding implementation                                     -
+// -> 32-bit variables, 32-bit product, periodic updates, table decoding     -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+// Version 1.00  -  April 25, 2004                                           -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+//                                  WARNING                                  -
+//                                 =========                                 -
+//                                                                           -
+// The only purpose of this program is to demonstrate the basic principles   -
+// of arithmetic coding. It is provided as is, without any express or        -
+// implied warranty, without even the warranty of fitness for any particular -
+// purpose, or that the implementations are correct.                         -
+//                                                                           -
+// Permission to copy and redistribute this code is hereby granted, provided -
+// that this warning and copyright notices are not removed or altered.       -
+//                                                                           -
+// Copyright (c) 2004 by Amir Said ([email protected]) &                         -
+//                       William A. Pearlman ([email protected])           -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+//                                                                           -
+// A description of the arithmetic coding method used here is available in   -
+//                                                                           -
+// Lossless Compression Handbook, ed. K. Sayood                              -
+// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
+//                                                                           -
+// A. Said, Introduction to Arithetic Coding Theory and Practice             -
+// HP Labs report HPL-2004-76  -  http://www.hpl.hp.com/techreports/         -
+//                                                                           -
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+// - - Definitions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#ifndef O3DGC_ARITHMETIC_CODEC
+#define O3DGC_ARITHMETIC_CODEC
+
+#include <stdio.h>
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - - Class definitions - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    class Static_Bit_Model                         // static model for binary data
+    {
+    public:
+
+      Static_Bit_Model(void);
+
+      void set_probability_0(double);             // set probability of symbol '0'
+
+    private:  //  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+      unsigned bit_0_prob;
+      friend class Arithmetic_Codec;
+    };
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    class Static_Data_Model                       // static model for general data
+    {
+    public:
+
+      Static_Data_Model(void);
+     ~Static_Data_Model(void);
+
+      unsigned model_symbols(void) { return data_symbols; }
+
+      void set_distribution(unsigned number_of_symbols,
+                            const double probability[] = 0);    // 0 means uniform
+
+    private:  //  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+      unsigned * distribution, * decoder_table;
+      unsigned data_symbols, last_symbol, table_size, table_shift;
+      friend class Arithmetic_Codec;
+    };
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    class Adaptive_Bit_Model                     // adaptive model for binary data
+    {
+    public:
+
+      Adaptive_Bit_Model(void);         
+
+      void reset(void);                             // reset to equiprobable model
+
+    private:  //  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+      void     update(void);
+      unsigned update_cycle, bits_until_update;
+      unsigned bit_0_prob, bit_0_count, bit_count;
+      friend class Arithmetic_Codec;
+    };
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    class Adaptive_Data_Model                    // adaptive model for binary data
+    {
+    public:
+
+      Adaptive_Data_Model(void);
+      Adaptive_Data_Model(unsigned number_of_symbols);
+     ~Adaptive_Data_Model(void);
+
+      unsigned model_symbols(void) { return data_symbols; }
+
+      void reset(void);                             // reset to equiprobable model
+      void set_alphabet(unsigned number_of_symbols);
+
+    private:  //  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+      void     update(bool);
+      unsigned * distribution, * symbol_count, * decoder_table;
+      unsigned total_count, update_cycle, symbols_until_update;
+      unsigned data_symbols, last_symbol, table_size, table_shift;
+      friend class Arithmetic_Codec;
+    };
+
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    // - - Encoder and decoder class - - - - - - - - - - - - - - - - - - - - - - -
+
+    // Class with both the arithmetic encoder and decoder.  All compressed data is
+    // saved to a memory buffer
+
+    class Arithmetic_Codec
+    {
+    public:
+
+      Arithmetic_Codec(void);
+     ~Arithmetic_Codec(void);
+      Arithmetic_Codec(unsigned max_code_bytes,
+                       unsigned char * user_buffer = 0);         // 0 = assign new
+
+      unsigned char * buffer(void) { return code_buffer; }
+
+      void set_buffer(unsigned max_code_bytes,
+                      unsigned char * user_buffer = 0);          // 0 = assign new
+
+      void     start_encoder(void);
+      void     start_decoder(void);
+      void     read_from_file(FILE * code_file);  // read code data, start decoder
+
+      unsigned stop_encoder(void);                 // returns number of bytes used
+      unsigned write_to_file(FILE * code_file);   // stop encoder, write code data
+      void     stop_decoder(void);
+
+      void     put_bit(unsigned bit);
+      unsigned get_bit(void);
+
+      void     put_bits(unsigned data, unsigned number_of_bits);
+      unsigned get_bits(unsigned number_of_bits);
+
+      void     encode(unsigned bit,
+                      Static_Bit_Model &);
+      unsigned decode(Static_Bit_Model &);
+
+      void     encode(unsigned data,
+                      Static_Data_Model &);
+      unsigned decode(Static_Data_Model &);
+
+      void     encode(unsigned bit,
+                      Adaptive_Bit_Model &);
+      unsigned decode(Adaptive_Bit_Model &);
+
+      void     encode(unsigned data,
+                      Adaptive_Data_Model &);
+      unsigned decode(Adaptive_Data_Model &);
+
+//   This section was added by K. Mammou
+      void     ExpGolombEncode(unsigned int symbol, 
+                               int k,
+                               Static_Bit_Model & bModel0,
+                               Adaptive_Bit_Model & bModel1)
+               {
+                   while(1)
+                   {
+                       if (symbol >= (unsigned int)(1<<k))
+                       {
+                           encode(1, bModel1);
+                           symbol = symbol - (1<<k);
+                           k++;
+                       }
+                       else
+                       {
+                           encode(0, bModel1); // now terminated zero of unary part
+                           while (k--) // next binary part
+                           {
+                               encode((signed short)((symbol>>k)&1), bModel0);
+                           }
+                           break;
+                       }
+                   }
+               }
+
+
+    unsigned   ExpGolombDecode(int k,
+                               Static_Bit_Model & bModel0,
+                               Adaptive_Bit_Model & bModel1)
+               {
+                   unsigned int l;
+                   int symbol = 0;
+                   int binary_symbol = 0;
+                   do
+                   {
+                       l=decode(bModel1);
+                       if (l==1)
+                       {
+                           symbol += (1<<k);
+                           k++;
+                        }
+                   }
+                   while (l!=0);
+                   while (k--)                             //next binary part
+                   if (decode(bModel0)==1)
+                   {
+                       binary_symbol |= (1<<k);
+                   }
+                   return (unsigned int) (symbol+binary_symbol);
+                }
+//----------------------------------------------------------
+
+    private:  //  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+      void propagate_carry(void);
+      void renorm_enc_interval(void);
+      void renorm_dec_interval(void);
+      unsigned char * code_buffer, * new_buffer, * ac_pointer;
+      unsigned base, value, length;                     // arithmetic coding state
+      unsigned buffer_size, mode;     // mode: 0 = undef, 1 = encoder, 2 = decoder
+    };
+    inline long DecodeIntACEGC(Arithmetic_Codec & acd,
+                               Adaptive_Data_Model & mModelValues,
+                               Static_Bit_Model & bModel0,
+                               Adaptive_Bit_Model & bModel1,
+                               const unsigned long exp_k,
+                               const unsigned long M)
+    {
+        unsigned long uiValue = acd.decode(mModelValues);
+        if (uiValue == M) 
+        {
+            uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
+        }
+        return UIntToInt(uiValue);
+    }
+    inline unsigned long DecodeUIntACEGC(Arithmetic_Codec & acd,
+                                         Adaptive_Data_Model & mModelValues,
+                                         Static_Bit_Model & bModel0,
+                                         Adaptive_Bit_Model & bModel1,
+                                         const unsigned long exp_k,
+                                         const unsigned long M)
+    {
+        unsigned long uiValue = acd.decode(mModelValues);
+        if (uiValue == M) 
+        {
+            uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
+        }
+        return uiValue;
+    }
+
+    inline void EncodeIntACEGC(long predResidual, 
+                               Arithmetic_Codec & ace,
+                               Adaptive_Data_Model & mModelValues,
+                               Static_Bit_Model & bModel0,
+                               Adaptive_Bit_Model & bModel1,
+                               const unsigned long M)
+    {
+        unsigned long uiValue = IntToUInt(predResidual);
+        if (uiValue < M) 
+        {
+            ace.encode(uiValue, mModelValues);
+        }
+        else 
+        {
+            ace.encode(M, mModelValues);
+            ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
+        }
+    }
+    inline void EncodeUIntACEGC(long predResidual, 
+                                Arithmetic_Codec & ace,
+                                Adaptive_Data_Model & mModelValues,
+                                Static_Bit_Model & bModel0,
+                                Adaptive_Bit_Model & bModel1,
+                                const unsigned long M)
+    {
+        unsigned long uiValue = (unsigned long) predResidual;
+        if (uiValue < M) 
+        {
+            ace.encode(uiValue, mModelValues);
+        }
+        else 
+        {
+            ace.encode(M, mModelValues);
+            ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
+        }
+    }
+
+}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#endif
+

+ 430 - 0
contrib/Open3DGC/o3dgcBinaryStream.h

@@ -0,0 +1,430 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_BINARY_STREAM_H
+#define O3DGC_BINARY_STREAM_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcVector.h"
+
+namespace o3dgc
+{
+    const unsigned long O3DGC_BINARY_STREAM_DEFAULT_SIZE       = 4096;
+    const unsigned long O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0   = 7;
+    const unsigned long O3DGC_BINARY_STREAM_MAX_SYMBOL0        = (1 << O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0) - 1;
+    const unsigned long O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1   = 6;
+    const unsigned long O3DGC_BINARY_STREAM_MAX_SYMBOL1        = (1 << O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1) - 1;
+    const unsigned long O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32 = (32+O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0-1) / 
+                                                                 O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
+
+    //! 
+    class BinaryStream
+    {
+    public:    
+        //! Constructor.
+                                BinaryStream(unsigned long size = O3DGC_BINARY_STREAM_DEFAULT_SIZE)
+                                {
+                                    m_endianness = SystemEndianness();
+                                    m_stream.Allocate(size);
+                                };
+        //! Destructor.
+                                ~BinaryStream(void){};
+
+        void                    WriteFloat32(float value, O3DGCStreamType streamType)
+                                {
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        WriteFloat32ASCII(value);
+                                    }
+                                    else
+                                    {
+                                        WriteFloat32Bin(value);
+                                    }
+                                }
+        void                    WriteUInt32(unsigned long position, unsigned long value, O3DGCStreamType streamType)
+                                {
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        WriteUInt32ASCII(position, value);
+                                    }
+                                    else
+                                    {
+                                        WriteUInt32Bin(position, value);
+                                    }
+                                }
+        void                    WriteUInt32(unsigned long value, O3DGCStreamType streamType)
+                                {
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        WriteUInt32ASCII(value);
+                                    }
+                                    else
+                                    {
+                                        WriteUInt32Bin(value);
+                                    }
+                                }
+        void                    WriteUChar(unsigned int position, unsigned char value, O3DGCStreamType streamType)
+                                {
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        WriteUInt32ASCII(position, value);
+                                    }
+                                    else
+                                    {
+                                        WriteUInt32Bin(position, value);
+                                    }
+                                }
+        void                    WriteUChar(unsigned char value, O3DGCStreamType streamType)
+                                {
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        WriteUCharASCII(value);
+                                    }
+                                    else
+                                    {
+                                        WriteUChar8Bin(value);
+                                    }
+                                }
+        float                   ReadFloat32(unsigned long & position, O3DGCStreamType streamType) const
+                                {
+                                    float value;
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        value = ReadFloat32ASCII(position);
+                                    }
+                                    else
+                                    {
+                                        value = ReadFloat32Bin(position);
+                                    }
+                                    return value;
+                                }
+        unsigned long           ReadUInt32(unsigned long & position, O3DGCStreamType streamType) const
+                                {
+                                    unsigned long value;
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        value = ReadUInt32ASCII(position);
+                                    }
+                                    else
+                                    {
+                                        value = ReadUInt32Bin(position);
+                                    }
+                                    return value;
+                                }
+        unsigned char           ReadUChar(unsigned long & position, O3DGCStreamType streamType) const
+                                {
+                                    unsigned char value;
+                                    if (streamType == O3DGC_STREAM_TYPE_ASCII)
+                                    {
+                                        value = ReadUCharASCII(position);
+                                    }
+                                    else
+                                    {
+                                        value = ReadUChar8Bin(position);
+                                    }
+                                    return value;
+                                }
+
+        void                    WriteFloat32Bin(unsigned long position, float value) 
+                                {
+                                    assert(position < m_stream.GetSize() - 4);
+                                    unsigned char * ptr = (unsigned char *) (&value);
+                                    if (m_endianness == O3DGC_BIG_ENDIAN)
+                                    {
+                                        m_stream[position++] = ptr[3];
+                                        m_stream[position++] = ptr[2];
+                                        m_stream[position++] = ptr[1];
+                                        m_stream[position  ] = ptr[0];
+                                    }
+                                    else
+                                    {
+                                        m_stream[position++] = ptr[0];
+                                        m_stream[position++] = ptr[1];
+                                        m_stream[position++] = ptr[2];
+                                        m_stream[position  ] = ptr[3];
+                                    }
+                                }
+        void                    WriteFloat32Bin(float value) 
+                                {
+                                    unsigned char * ptr = (unsigned char *) (&value);
+                                    if (m_endianness == O3DGC_BIG_ENDIAN)
+                                    {
+                                        m_stream.PushBack(ptr[3]);
+                                        m_stream.PushBack(ptr[2]);
+                                        m_stream.PushBack(ptr[1]);
+                                        m_stream.PushBack(ptr[0]);
+                                    }
+                                    else
+                                    {
+                                        m_stream.PushBack(ptr[0]);
+                                        m_stream.PushBack(ptr[1]);
+                                        m_stream.PushBack(ptr[2]);
+                                        m_stream.PushBack(ptr[3]);
+                                    }
+                                }
+        void                    WriteUInt32Bin(unsigned long position, unsigned long value) 
+                                {
+                                    assert(position < m_stream.GetSize() - 4);
+                                    unsigned char * ptr = (unsigned char *) (&value);
+                                    if (m_endianness == O3DGC_BIG_ENDIAN)
+                                    {
+                                        m_stream[position++] = ptr[3];
+                                        m_stream[position++] = ptr[2];
+                                        m_stream[position++] = ptr[1];
+                                        m_stream[position  ] = ptr[0];
+                                    }
+                                    else
+                                    {
+                                        m_stream[position++] = ptr[0];
+                                        m_stream[position++] = ptr[1];
+                                        m_stream[position++] = ptr[2];
+                                        m_stream[position  ] = ptr[3];
+                                    }
+                                }
+        void                    WriteUInt32Bin(unsigned long value) 
+                                {
+                                    unsigned char * ptr = (unsigned char *) (&value);
+                                    if (m_endianness == O3DGC_BIG_ENDIAN)
+                                    {
+                                        m_stream.PushBack(ptr[3]);
+                                        m_stream.PushBack(ptr[2]);
+                                        m_stream.PushBack(ptr[1]);
+                                        m_stream.PushBack(ptr[0]);
+                                    }
+                                    else
+                                    {
+                                        m_stream.PushBack(ptr[0]);
+                                        m_stream.PushBack(ptr[1]);
+                                        m_stream.PushBack(ptr[2]);
+                                        m_stream.PushBack(ptr[3]);
+                                    }
+                                }
+        void                    WriteUChar8Bin(unsigned int position, unsigned char value) 
+                                {
+                                    m_stream[position] = value;
+                                }
+        void                    WriteUChar8Bin(unsigned char value) 
+                                {
+                                    m_stream.PushBack(value);
+                                }
+        float                   ReadFloat32Bin(unsigned long & position) const
+                                {
+                                    unsigned long value = ReadUInt32Bin(position);
+                                    float fvalue = *((float *)(&value));
+                                    return fvalue;
+                                }
+        unsigned long           ReadUInt32Bin(unsigned long & position)  const
+                                {
+                                    assert(position < m_stream.GetSize() - 4);
+                                    unsigned long value = 0;
+                                    if (m_endianness == O3DGC_BIG_ENDIAN)
+                                    {
+                                        value += (m_stream[position++]<<24);
+                                        value += (m_stream[position++]<<16);
+                                        value += (m_stream[position++]<<8);
+                                        value += (m_stream[position++]);
+                                    }
+                                    else
+                                    {
+                                        value += (m_stream[position++]);
+                                        value += (m_stream[position++]<<8);
+                                        value += (m_stream[position++]<<16);
+                                        value += (m_stream[position++]<<24);
+                                    }
+                                    return value;
+                                }
+        unsigned char           ReadUChar8Bin(unsigned long & position) const
+                                {
+                                    return m_stream[position++];
+                                }
+
+        void                    WriteFloat32ASCII(float value) 
+                                {
+                                    unsigned long uiValue = *((unsigned long *)(&value));
+                                    WriteUInt32ASCII(uiValue);
+                                }
+        void                    WriteUInt32ASCII(unsigned long position, unsigned long value) 
+                                {
+                                    assert(position < m_stream.GetSize() - O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32);
+                                    unsigned long value0 = value;
+                                    for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i)
+                                    {
+                                        m_stream[position++] = (value0 & O3DGC_BINARY_STREAM_MAX_SYMBOL0);
+                                        value0 >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
+                                    }
+                                }
+        void                    WriteUInt32ASCII(unsigned long value) 
+                                {
+                                    for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i)
+                                    {
+                                        m_stream.PushBack(value & O3DGC_BINARY_STREAM_MAX_SYMBOL0);
+                                        value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
+                                    }
+                                }
+        void                    WriteIntASCII(long value) 
+                                {
+                                    WriteUIntASCII(IntToUInt(value));
+                                }
+        void                    WriteUIntASCII(unsigned long value) 
+                                {
+                                    if (value >= O3DGC_BINARY_STREAM_MAX_SYMBOL0)
+                                    {
+                                        m_stream.PushBack(O3DGC_BINARY_STREAM_MAX_SYMBOL0);
+                                        value -= O3DGC_BINARY_STREAM_MAX_SYMBOL0;
+                                        unsigned char a, b;
+                                        do
+                                        {
+                                            a  = ((value & O3DGC_BINARY_STREAM_MAX_SYMBOL1) << 1);
+                                            b  = ( (value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1) > 0);
+                                            a += b;
+                                            m_stream.PushBack(a);
+                                        } while (b);
+                                    }
+                                    else
+                                    {
+                                        m_stream.PushBack((unsigned char) value);
+                                    }
+                                }
+        void                    WriteUCharASCII(unsigned char value) 
+                                {
+                                    assert(value <= O3DGC_BINARY_STREAM_MAX_SYMBOL0);
+                                    m_stream.PushBack(value);
+                                }
+        float                   ReadFloat32ASCII(unsigned long & position) const
+                                {
+                                    unsigned long value = ReadUInt32ASCII(position);
+                                    float fvalue = *((float *)(&value));
+                                    return fvalue;
+                                }
+        unsigned long           ReadUInt32ASCII(unsigned long & position)  const
+                                {
+                                    assert(position < m_stream.GetSize() - O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32);
+                                    unsigned long value = 0;
+                                    unsigned long shift = 0;
+                                    for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i)
+                                    {
+                                        value  += (m_stream[position++] << shift);
+                                        shift  += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
+                                    }
+                                    return value;
+                                }
+        long                    ReadIntASCII(unsigned long & position) const
+                                {
+                                    return UIntToInt(ReadUIntASCII(position));
+                                }
+        unsigned long           ReadUIntASCII(unsigned long & position) const
+                                {
+                                    unsigned long value = m_stream[position++];
+                                    if (value == O3DGC_BINARY_STREAM_MAX_SYMBOL0)
+                                    {
+                                        long x;
+                                        unsigned long i = 0;
+                                        do
+                                        {
+                                            x = m_stream[position++];
+                                            value += ( (x>>1) << i);
+                                            i += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1;
+                                        } while (x & 1);
+                                    }
+                                    return value;
+                                }
+        unsigned char           ReadUCharASCII(unsigned long & position) const
+                                {
+                                    return m_stream[position++];
+                                }
+        O3DGCErrorCode          Save(const char * const fileName) 
+                                {
+                                    FILE * fout = fopen(fileName, "wb");
+                                    if (!fout)
+                                    {
+                                        return O3DGC_ERROR_CREATE_FILE;
+                                    }
+                                    fwrite(m_stream.GetBuffer(), 1, m_stream.GetSize(), fout);
+                                    fclose(fout);
+                                    return O3DGC_OK;
+                                }
+        O3DGCErrorCode          Load(const char * const fileName) 
+                                {
+                                    FILE * fin = fopen(fileName, "rb");
+                                    if (!fin)
+                                    {
+                                        return O3DGC_ERROR_OPEN_FILE;
+                                    }
+                                    fseek(fin, 0, SEEK_END);
+                                    unsigned long size = ftell(fin);
+                                    m_stream.Allocate(size);
+                                    rewind(fin);
+                                    unsigned int nread = (unsigned int) fread((void *) m_stream.GetBuffer(), 1, size, fin);
+                                    m_stream.SetSize(size);
+                                    if (nread != size)
+                                    {
+                                        return O3DGC_ERROR_READ_FILE;
+                                    }
+                                    fclose(fin);
+                                    return O3DGC_OK;
+                                }
+        O3DGCErrorCode          LoadFromBuffer(unsigned char * buffer, unsigned long bufferSize)
+                                {
+                                    m_stream.Allocate(bufferSize);
+                                    memcpy(m_stream.GetBuffer(), buffer, bufferSize);
+                                    m_stream.SetSize(bufferSize);
+                                    return O3DGC_OK;
+                                }
+        unsigned long           GetSize() const
+                                {
+                                    return m_stream.GetSize();
+                                }
+    const unsigned char * const GetBuffer(unsigned long position) const
+                                {
+                                    return m_stream.GetBuffer() + position;
+                                }
+    unsigned char * const       GetBuffer(unsigned long position)
+                                {
+                                    return (m_stream.GetBuffer() + position);
+                                }                                
+    unsigned char * const       GetBuffer()
+                                {
+                                    return m_stream.GetBuffer();
+                                }                                
+    void                        GetBuffer(unsigned long position, unsigned char * & buffer) const
+                                {
+                                    buffer = (unsigned char *) (m_stream.GetBuffer() + position); // fix me: ugly!
+                                }
+    void                        SetSize(unsigned long size)
+                                { 
+                                    m_stream.SetSize(size);
+                                };
+    void                        Allocate(unsigned long size)
+                                {
+                                    m_stream.Allocate(size);
+                                }
+
+    private:
+        Vector<unsigned char>   m_stream;
+        O3DGCEndianness         m_endianness;
+    };
+
+}
+#endif // O3DGC_BINARY_STREAM_H
+

+ 412 - 0
contrib/Open3DGC/o3dgcCommon.h

@@ -0,0 +1,412 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_COMMON_H
+#define O3DGC_COMMON_H
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+namespace o3dgc
+{
+    typedef float        Real;
+    const double O3DGC_MAX_DOUBLE       = 1.79769e+308;
+    const long O3DGC_MIN_LONG           = -2147483647;
+    const long O3DGC_MAX_LONG           =  2147483647;
+    const long O3DGC_MAX_UCHAR8         = 255;
+    const long O3DGC_MAX_TFAN_SIZE      = 256;
+    const unsigned long O3DGC_MAX_ULONG = 4294967295;
+
+    const unsigned long O3DGC_SC3DMC_START_CODE               = 0x00001F1;
+    const unsigned long O3DGC_DV_START_CODE                   = 0x00001F2;
+    const unsigned long O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES = 256;
+    const unsigned long O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES   = 256;
+    const unsigned long O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES = 32;
+
+    const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS = 2;
+    const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS   = 257;
+
+    enum O3DGCEndianness
+    {
+        O3DGC_BIG_ENDIAN     = 0,
+        O3DGC_LITTLE_ENDIAN  = 1
+    };
+    enum O3DGCErrorCode
+    {
+        O3DGC_OK,
+        O3DGC_ERROR_BUFFER_FULL,
+        O3DGC_ERROR_CREATE_FILE,
+        O3DGC_ERROR_OPEN_FILE,
+        O3DGC_ERROR_READ_FILE,
+        O3DGC_ERROR_CORRUPTED_STREAM,
+        O3DGC_ERROR_NON_SUPPORTED_FEATURE
+    };
+    enum O3DGCSC3DMCBinarization
+    {
+        O3DGC_SC3DMC_BINARIZATION_FL     = 0,            // Fixed Length (not supported)
+        O3DGC_SC3DMC_BINARIZATION_BP     = 1,            // BPC (not supported)
+        O3DGC_SC3DMC_BINARIZATION_FC     = 2,            // 4 bits Coding (not supported)
+        O3DGC_SC3DMC_BINARIZATION_AC     = 3,            // Arithmetic Coding (not supported)
+        O3DGC_SC3DMC_BINARIZATION_AC_EGC = 4,            // Arithmetic Coding & EGCk
+        O3DGC_SC3DMC_BINARIZATION_ASCII  = 5             // Arithmetic Coding & EGCk
+    };
+    enum O3DGCStreamType
+    {
+        O3DGC_STREAM_TYPE_UNKOWN = 0,
+        O3DGC_STREAM_TYPE_ASCII  = 1,
+        O3DGC_STREAM_TYPE_BINARY = 2
+    };
+    enum O3DGCSC3DMCQuantizationMode
+    {
+        O3DGC_SC3DMC_DIAG_BB             = 0, // supported
+        O3DGC_SC3DMC_MAX_ALL_DIMS        = 1, // supported
+        O3DGC_SC3DMC_MAX_SEP_DIM         = 2  // supported
+    };
+    enum O3DGCSC3DMCPredictionMode
+    {
+        O3DGC_SC3DMC_NO_PREDICTION                    = 0, // supported
+        O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION          = 1, // supported
+        O3DGC_SC3DMC_XOR_PREDICTION                   = 2, // not supported
+        O3DGC_SC3DMC_ADAPTIVE_DIFFERENTIAL_PREDICTION = 3, // not supported
+        O3DGC_SC3DMC_CIRCULAR_DIFFERENTIAL_PREDICTION = 4, // not supported
+        O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION         = 5,  // supported
+        O3DGC_SC3DMC_SURF_NORMALS_PREDICTION          = 6   // supported
+    };
+    enum O3DGCSC3DMCEncodingMode
+    {
+        O3DGC_SC3DMC_ENCODE_MODE_QBCR       = 0,        // not supported
+        O3DGC_SC3DMC_ENCODE_MODE_SVA        = 1,        // not supported
+        O3DGC_SC3DMC_ENCODE_MODE_TFAN       = 2,        // supported
+    };
+    enum O3DGCDVEncodingMode
+    {
+        O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT       = 0
+    };
+    enum O3DGCIFSFloatAttributeType
+    {
+        O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_UNKOWN   = 0,
+        O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_POSITION = 1,
+        O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_NORMAL   = 2,
+        O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_COLOR    = 3,
+        O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD = 4,
+        O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_WEIGHT   = 5
+        
+    };
+    enum O3DGCIFSIntAttributeType
+    {
+        O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN   = 0,
+        O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX    = 1,
+        O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID = 2,
+        O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID = 3
+    };
+
+    template<class T> 
+    inline const T absolute(const T& a)
+    {
+        return (a < (T)(0)) ? -a : a;
+    }
+    template<class T> 
+    inline const T min(const T& a, const T& b)
+    {
+        return (b < a) ? b : a;
+    }
+    template<class T> 
+    inline const T max(const T& a, const T& b)
+    {
+        return (b > a) ? b : a;
+    }
+    template<class T> 
+    inline void swap(T& a, T& b)
+    {
+        T tmp = a;
+        a = b;
+        b = tmp;
+    }
+    inline double log2( double n )  
+    {  
+        return log(n) / log(2.0);  
+    }
+
+    inline O3DGCEndianness SystemEndianness()
+    {
+        unsigned long num = 1;
+        return ( *((char *)(&num)) == 1 )? O3DGC_LITTLE_ENDIAN : O3DGC_BIG_ENDIAN ;
+    }
+    class SC3DMCStats
+    {
+    public: 
+                                    SC3DMCStats(void)
+                                    {
+                                        memset(this, 0, sizeof(SC3DMCStats));
+                                    };
+                                    ~SC3DMCStats(void){};
+        
+        double                      m_timeCoord;
+        double                      m_timeNormal;
+        double                      m_timeCoordIndex;
+        double                      m_timeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        double                      m_timeIntAttribute  [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES  ];
+        double                      m_timeReorder;
+
+        unsigned long               m_streamSizeCoord;
+        unsigned long               m_streamSizeNormal;
+        unsigned long               m_streamSizeCoordIndex;
+        unsigned long               m_streamSizeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        unsigned long               m_streamSizeIntAttribute  [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES  ];
+
+    };
+    typedef struct 
+    {
+        long          m_a;
+        long          m_b;
+        long          m_c;
+    } SC3DMCTriplet;
+
+    typedef struct 
+    {
+        SC3DMCTriplet m_id;
+        long          m_pred[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
+    } SC3DMCPredictor;
+
+    inline bool operator< (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs)
+    {
+          if (lhs.m_c != rhs.m_c)
+          {
+              return (lhs.m_c < rhs.m_c);
+          }
+          else if (lhs.m_b != rhs.m_b)
+          {
+              return (lhs.m_b < rhs.m_b);
+          }
+          return (lhs.m_a < rhs.m_a);
+    }
+    inline bool operator== (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs)
+    {
+          return (lhs.m_c == rhs.m_c && lhs.m_b == rhs.m_b && lhs.m_a == rhs.m_a);
+    }
+
+
+    // fix me: optimize this function (e.g., binary search)
+    inline unsigned long Insert(SC3DMCTriplet e, unsigned long & nPred, SC3DMCPredictor * const list)
+    {
+        unsigned long pos = 0xFFFFFFFF;
+        bool foundOrInserted = false;
+        for (unsigned long j = 0; j < nPred; ++j)
+        {
+            if (e == list[j].m_id)
+            {
+                foundOrInserted = true;
+                break;
+            }
+            else if (e < list[j].m_id)
+            {
+                if (nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS)
+                {
+                    ++nPred;
+                }
+                for (unsigned long h = nPred-1; h > j; --h)
+                {
+                    list[h] = list[h-1];
+                }
+                list[j].m_id = e;
+                pos = j;
+                foundOrInserted = true;
+                break;
+            }
+        }
+        if (!foundOrInserted && nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS)
+        {
+            pos = nPred;
+            list[nPred++].m_id = e;
+        }
+        return pos;
+    }
+    template <class T> 
+    inline void SphereToCube(const T x, const T y, const T z, 
+                             T & a, T & b, char & index)
+    {
+        T ax = absolute(x);
+        T ay = absolute(y);
+        T az = absolute(z);
+        if (az >= ax && az >= ay)
+        {
+            if (z >= (T)(0))
+            {
+                index = 0;
+                a = x;
+                b = y;
+            }
+            else
+            {
+                index = 1;
+                a = -x;
+                b = -y;
+            }
+        }
+        else if (ay >= ax && ay >= az)
+        {
+            if (y >= (T)(0))
+            {
+                index = 2;
+                a = z;
+                b = x;
+            }
+            else
+            {
+                index = 3;
+                a = -z;
+                b = -x;
+            }
+        }
+        else if (ax >= ay && ax >= az)
+        {
+            if (x >= (T)(0))
+            {
+                index = 4;
+                a = y;
+                b = z;
+            }
+            else
+            {
+                index = 5;
+                a = -y;
+                b = -z;
+            }
+        }
+    }
+    inline void CubeToSphere(const Real a, const Real b, const char index,
+                             Real & x, Real & y, Real & z)
+    {
+        switch( index )
+        {
+        case 0:
+            x = a;
+            y = b;
+            z =  (Real) sqrt(max(0.0, 1.0 - x*x-y*y));
+            break;
+        case 1:
+            x = -a;
+            y = -b;
+            z = -(Real) sqrt(max(0.0, 1.0 - x*x-y*y));
+            break;
+        case 2:
+            z = a;
+            x = b;
+            y =  (Real) sqrt(max(0.0, 1.0 - x*x-z*z));
+            break;
+        case 3:
+            z = -a;
+            x = -b;
+            y = -(Real) sqrt(max(0.0, 1.0 - x*x-z*z));
+            break;
+        case 4:
+            y = a;
+            z = b;
+            x =  (Real) sqrt(max(0.0, 1.0 - y*y-z*z));
+            break;
+        case 5:
+            y = -a;
+            z = -b;
+            x = -(Real) sqrt(max(0.0, 1.0 - y*y-z*z));
+            break;
+        }
+    }
+    inline unsigned long IntToUInt(long value)
+    {
+        return (value < 0)?(unsigned long) (-1 - (2 * value)):(unsigned long) (2 * value);
+    }
+    inline long UIntToInt(unsigned long uiValue)
+    {
+        return (uiValue & 1)?-((long) ((uiValue+1) >> 1)):((long) (uiValue >> 1));
+    }
+    inline void ComputeVectorMinMax(const Real * const tab, 
+                                    unsigned long size, 
+                                    unsigned long dim,
+                                    unsigned long stride,
+                                    Real * minTab,
+                                    Real * maxTab,
+                                    O3DGCSC3DMCQuantizationMode quantMode)
+    {
+        if (size == 0 || dim == 0)
+        {
+            return;
+        }
+        unsigned long p = 0;
+        for(unsigned long d = 0; d < dim; ++d)
+        {
+            maxTab[d] = minTab[d] = tab[p++];
+        }
+        p = stride;
+        for(unsigned long i = 1; i < size; ++i)
+        {
+            for(unsigned long d = 0; d < dim; ++d)
+            {
+                if (maxTab[d] < tab[p+d]) maxTab[d] = tab[p+d];
+                if (minTab[d] > tab[p+d]) minTab[d] = tab[p+d];
+            }
+            p += stride;
+        }
+
+        if (quantMode == O3DGC_SC3DMC_DIAG_BB)
+        {
+            Real diag = 0.0;
+            Real r;
+            for(unsigned long d = 0; d < dim; ++d)
+            {
+                r     = (maxTab[d] - minTab[d]);
+                diag += r*r;
+            } 
+            diag = sqrt(diag);
+            for(unsigned long d = 0; d < dim; ++d)
+            {
+                 maxTab[d] = minTab[d] + diag;
+            } 
+        }
+        else if (quantMode == O3DGC_SC3DMC_MAX_ALL_DIMS)
+        {            
+            Real maxr = (maxTab[0] - minTab[0]);
+            Real r;
+            for(unsigned long d = 1; d < dim; ++d)
+            {
+                r = (maxTab[d] - minTab[d]);
+                if ( r > maxr)
+                {
+                    maxr = r;
+                }
+            } 
+            for(unsigned long d = 0; d < dim; ++d)
+            {
+                 maxTab[d] = minTab[d] + maxr;
+            } 
+        }
+    }
+}
+#endif // O3DGC_COMMON_H
+

+ 62 - 0
contrib/Open3DGC/o3dgcDVEncodeParams.h

@@ -0,0 +1,62 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_DV_ENCODE_PARAMS_H
+#define O3DGC_DV_ENCODE_PARAMS_H
+
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    class DVEncodeParams
+    {
+    public:
+        //! Constructor.
+                                    DVEncodeParams(void)
+                                    {
+                                        m_quantBits         = 10;
+                                        m_streamTypeMode    = O3DGC_STREAM_TYPE_ASCII;
+                                        m_encodeMode        = O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT;
+                                    };
+        //! Destructor.
+                                    ~DVEncodeParams(void) {};
+
+        unsigned long               GetQuantBits()     const { return m_quantBits;}
+        O3DGCStreamType             GetStreamType()    const { return m_streamTypeMode;}
+        O3DGCDVEncodingMode         GetEncodeMode()    const { return m_encodeMode;}
+
+        void                        SetQuantBits   (unsigned long quantBits  ) { m_quantBits = quantBits;}
+
+        void                        SetStreamType(O3DGCStreamType     streamTypeMode) { m_streamTypeMode = streamTypeMode;}
+        void                        SetEncodeMode(O3DGCDVEncodingMode encodeMode    ) { m_encodeMode     = encodeMode    ;}
+
+
+    private:
+        unsigned long               m_quantBits;
+        O3DGCStreamType             m_streamTypeMode;
+        O3DGCDVEncodingMode         m_encodeMode;
+    };
+}
+#endif // O3DGC_DV_ENCODE_PARAMS_H
+

+ 84 - 0
contrib/Open3DGC/o3dgcDynamicVector.h

@@ -0,0 +1,84 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_DYNAMIC_VECTOR_SET_H
+#define O3DGC_DYNAMIC_VECTOR_SET_H
+
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    class DynamicVector
+    {
+    public:
+        //! Constructor.
+                                    DynamicVector(void)
+                                    {
+                                        m_num               = 0;
+                                        m_dim               = 0;
+                                        m_stride            = 0;
+                                        m_max               = 0;
+                                        m_min               = 0;
+                                        m_vectors           = 0;
+                                    };
+        //! Destructor.
+                                    ~DynamicVector(void) {};
+
+        unsigned long               GetNVector()       const { return m_num;}
+        unsigned long               GetDimVector()     const { return m_dim;}
+        unsigned long               GetStride()        const { return m_stride;}
+        const Real * const          GetMin()           const { return m_min;}
+        const Real * const          GetMax()           const { return m_max;}
+        const Real * const          GetVectors()       const { return m_vectors;}
+        Real * const                GetVectors()             { return m_vectors;}
+        Real                        GetMin(unsigned long j) const { return m_min[j];}
+        Real                        GetMax(unsigned long j) const { return m_max[j];}
+
+        void                        SetNVector     (unsigned long num        ) { m_num       = num      ;}
+        void                        SetDimVector   (unsigned long dim        ) { m_dim       = dim      ;}
+        void                        SetStride      (unsigned long stride     ) { m_stride    = stride   ;}
+        void                        SetMin         (Real * const min         ) { m_min       = min      ;}
+        void                        SetMax         (Real * const max         ) { m_max       = max      ;}
+        void                        SetMin         (unsigned long j, Real min) { m_min[j]    = min      ;}
+        void                        SetMax         (unsigned long j, Real max) { m_max[j]    = max      ;}
+        void                        SetVectors     (Real * const vectors)      { m_vectors   = vectors  ;}
+
+        void                        ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode)
+                                    {
+                                        assert( m_max && m_min && m_vectors && m_stride && m_dim && m_num);
+                                        ComputeVectorMinMax(m_vectors, m_num , m_dim, m_stride, m_min , m_max , quantMode);
+                                    }
+
+    private:
+        unsigned long               m_num;
+        unsigned long               m_dim;
+        unsigned long               m_stride;
+        Real *                      m_max;
+        Real *                      m_min;
+        Real *                      m_vectors;
+    };
+
+}
+#endif // O3DGC_DYNAMIC_VECTOR_SET_H
+

+ 278 - 0
contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp

@@ -0,0 +1,278 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include "o3dgcDynamicVectorDecoder.h"
+#include "o3dgcArithmeticCodec.h"
+
+
+//#define DEBUG_VERBOSE
+
+namespace o3dgc
+{
+#ifdef DEBUG_VERBOSE
+        FILE * g_fileDebugDVCDec = NULL;
+#endif //DEBUG_VERBOSE
+
+    O3DGCErrorCode IUpdate(long * const data, const long size)
+    {   
+        assert(size > 1);
+        const long size1 = size - 1;
+        long p = 2;
+        data[0] -= data[1] >> 1;
+        while(p < size1)
+        {
+            data[p] -= (data[p-1] + data[p+1] + 2) >> 2;
+            p += 2;
+        }
+        if ( p == size1)
+        {
+            data[p] -= data[p-1]>>1;
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode IPredict(long * const data, const long size)
+    {   
+        assert(size > 1);
+        const long size1 = size - 1;
+        long p = 1;
+        while(p < size1)
+        {
+            data[p] += (data[p-1] + data[p+1] + 1) >> 1;
+            p += 2;
+        }
+        if ( p == size1)
+        {
+            data[p] += data[p-1];
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode Merge(long * const data, const long size)
+    {
+        assert(size > 1);
+        const long h = (size >> 1) + (size & 1);
+        long       a = h-1;
+        long       b = h;
+        while (a > 0)
+        {
+            for (long i = a; i < b; i += 2)
+            {
+                swap(data[i], data[i+1]);
+            }
+            --a;
+            ++b;
+        }
+        return O3DGC_OK;
+    }
+    inline O3DGCErrorCode ITransform(long * const data, const unsigned long size)
+    {   
+        unsigned long n    = size;
+        unsigned long even = 0;
+        unsigned long k    = 0;
+        even += ((n&1) << k++);
+        while(n > 1)
+        {
+            n = (n >> 1) + (n & 1);
+            even += ((n&1) << k++);
+        }
+        for(long i = k-2; i >= 0; --i)
+        {
+            n = (n << 1) - ((even>>i) & 1);
+            Merge  (data, n);
+            IUpdate (data, n);
+            IPredict(data, n);
+        }
+        return O3DGC_OK;
+    }
+    DynamicVectorDecoder::DynamicVectorDecoder(void)
+    {
+        m_streamSize    = 0;
+        m_maxNumVectors = 0;
+        m_numVectors    = 0;
+        m_dimVectors    = 0;
+        m_quantVectors  = 0;
+        m_iterator      = 0;
+        m_streamType    = O3DGC_STREAM_TYPE_UNKOWN;
+    }
+    DynamicVectorDecoder::~DynamicVectorDecoder()
+    {
+        delete [] m_quantVectors;
+    }    
+    O3DGCErrorCode DynamicVectorDecoder::DecodeHeader(DynamicVector & dynamicVector,
+                                                      const BinaryStream & bstream)
+    {
+        unsigned long iterator0 = m_iterator;
+        unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY);
+        if (start_code != O3DGC_DV_START_CODE)
+        {
+            m_iterator = iterator0;
+            start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII);
+            if (start_code != O3DGC_DV_START_CODE)
+            {
+                return O3DGC_ERROR_CORRUPTED_STREAM;
+            }
+            else
+            {
+                m_streamType = O3DGC_STREAM_TYPE_ASCII;
+            }
+        }
+        else
+        {
+            m_streamType = O3DGC_STREAM_TYPE_BINARY;
+        }
+        m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType);
+        m_params.SetEncodeMode( (O3DGCDVEncodingMode) bstream.ReadUChar(m_iterator, m_streamType));
+        dynamicVector.SetNVector   ( bstream.ReadUInt32(m_iterator, m_streamType) );
+          
+        if (dynamicVector.GetNVector() > 0)
+        {
+            dynamicVector.SetDimVector( bstream.ReadUInt32(m_iterator, m_streamType) );
+            m_params.SetQuantBits(bstream.ReadUChar(m_iterator, m_streamType));
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode DynamicVectorDecoder::DecodePlayload(DynamicVector & dynamicVector,
+                                                        const BinaryStream & bstream)
+    {
+        O3DGCErrorCode ret = O3DGC_OK;
+#ifdef DEBUG_VERBOSE
+        g_fileDebugDVCDec = fopen("dv_dec.txt", "w");
+#endif //DEBUG_VERBOSE
+        unsigned long       start            = m_iterator;
+        unsigned long       streamSize       = bstream.ReadUInt32(m_iterator, m_streamType);        // bitsream size
+
+        const unsigned long dim  = dynamicVector.GetDimVector();
+        const unsigned long num  = dynamicVector.GetNVector();
+        const unsigned long size = dim * num;
+        for(unsigned long j=0 ; j < dynamicVector.GetDimVector() ; ++j)
+        {
+            dynamicVector.SetMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+            dynamicVector.SetMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+        }
+        Arithmetic_Codec acd;
+        Static_Bit_Model bModel0;
+        Adaptive_Bit_Model bModel1;
+        unsigned char *     buffer           = 0;
+        streamSize                          -= (m_iterator - start);
+        unsigned int        exp_k            = 0;
+        unsigned int        M                = 0;        
+        if (m_streamType == O3DGC_STREAM_TYPE_BINARY)
+        {
+            bstream.GetBuffer(m_iterator, buffer);
+            m_iterator += streamSize;
+            acd.set_buffer(streamSize, buffer);
+            acd.start_decoder();
+            exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
+            M     = acd.ExpGolombDecode(0, bModel0, bModel1);
+        }
+        Adaptive_Data_Model mModelValues(M+2);
+
+        if (m_maxNumVectors < size)
+        {
+            delete [] m_quantVectors;
+            m_maxNumVectors = size;
+            m_quantVectors  = new long [size];
+        }
+        if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            for(unsigned long v = 0; v < num; ++v)
+            {
+                for(unsigned long d = 0; d < dim; ++d)
+                {
+                    m_quantVectors[d * num + v] = bstream.ReadIntASCII(m_iterator);
+                }
+            }
+        }
+        else
+        {
+            for(unsigned long v = 0; v < num; ++v)
+            {
+                for(unsigned long d = 0; d < dim; ++d)
+                {
+                    m_quantVectors[d * num + v] = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
+                }
+            }
+        }
+        #ifdef DEBUG_VERBOSE
+        printf("IntArray (%i, %i)\n", num, dim);
+        fprintf(g_fileDebugDVCDec, "IntArray (%i, %i)\n", num, dim);
+        for(unsigned long v = 0; v < num; ++v)
+        {
+            for(unsigned long d = 0; d < dim; ++d)
+            {
+                printf("%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
+                fprintf(g_fileDebugDVCDec, "%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
+            }
+        }
+        fflush(g_fileDebugDVCDec);
+        #endif //DEBUG_VERBOSE
+        for(unsigned long d = 0; d < dim; ++d)
+        {
+            ITransform(m_quantVectors + d * num, num);
+        }
+        IQuantize(dynamicVector.GetVectors(), 
+                  num, 
+                  dim,
+                  dynamicVector.GetStride(),
+                  dynamicVector.GetMin(),
+                  dynamicVector.GetMax(),
+                  m_params.GetQuantBits());
+
+#ifdef DEBUG_VERBOSE
+        fclose(g_fileDebugDVCDec);
+#endif //DEBUG_VERBOSE
+        return ret;
+    }
+    O3DGCErrorCode DynamicVectorDecoder::IQuantize(Real * const floatArray, 
+                                                   unsigned long numFloatArray,
+                                                   unsigned long dimFloatArray,
+                                                   unsigned long stride,
+                                                   const Real * const minFloatArray,
+                                                   const Real * const maxFloatArray,
+                                                   unsigned long nQBits)
+    {
+        const unsigned long size = numFloatArray * dimFloatArray;
+        Real r;
+        if (m_maxNumVectors < size)
+        {
+            delete [] m_quantVectors;
+            m_maxNumVectors = size;
+            m_quantVectors = new long [m_maxNumVectors];
+        }
+        Real idelta;
+        for(unsigned long d = 0; d < dimFloatArray; ++d)
+        {
+            r = maxFloatArray[d] - minFloatArray[d];
+            if (r > 0.0f)
+            {
+                idelta = (float)(r) / ((1 << nQBits) - 1);
+            }
+            else
+            {
+                idelta = 1.0f;
+            }
+            for(unsigned long v = 0; v < numFloatArray; ++v)
+            {
+                floatArray[v * stride + d] = m_quantVectors[v + d * numFloatArray] * idelta + minFloatArray[d];
+            }
+        }
+        return O3DGC_OK;
+    }
+}

+ 76 - 0
contrib/Open3DGC/o3dgcDynamicVectorDecoder.h

@@ -0,0 +1,76 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_DYNAMIC_VECTOR_DECODER_H
+#define O3DGC_DYNAMIC_VECTOR_DECODER_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcBinaryStream.h"
+#include "o3dgcDVEncodeParams.h"
+#include "o3dgcDynamicVector.h"
+
+namespace o3dgc
+{
+    //! 
+    class DynamicVectorDecoder
+    {
+    public:    
+        //! Constructor.
+                                    DynamicVectorDecoder(void);
+        //! Destructor.
+                                    ~DynamicVectorDecoder(void);
+        //! 
+        //!
+        O3DGCErrorCode              DecodeHeader(DynamicVector & dynamicVector,
+                                                 const BinaryStream & bstream);
+        //!                         
+        O3DGCErrorCode              DecodePlayload(DynamicVector & dynamicVector, 
+                                                   const BinaryStream & bstream);
+
+        O3DGCStreamType             GetStreamType() const { return m_streamType; }
+        void                        SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
+        unsigned long               GetIterator() const { return m_iterator;}
+        O3DGCErrorCode              SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; }
+
+        private:
+        O3DGCErrorCode              IQuantize(Real * const floatArray, 
+                                              unsigned long numFloatArray,
+                                              unsigned long dimFloatArray,
+                                              unsigned long stride,
+                                              const Real * const minFloatArray,
+                                              const Real * const maxFloatArray,
+                                              unsigned long nQBits);
+
+        unsigned long               m_streamSize;
+        unsigned long               m_maxNumVectors;
+        unsigned long               m_numVectors;
+        unsigned long               m_dimVectors;
+        unsigned long               m_iterator;
+        long *                      m_quantVectors;
+        DVEncodeParams              m_params;
+        O3DGCStreamType             m_streamType;
+    };
+}
+#endif // O3DGC_DYNAMIC_VECTOR_DECODER_H
+

+ 295 - 0
contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp

@@ -0,0 +1,295 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include "o3dgcDVEncodeParams.h"
+#include "o3dgcDynamicVectorEncoder.h"
+#include "o3dgcArithmeticCodec.h"
+#include "o3dgcBinaryStream.h"
+
+//#define DEBUG_VERBOSE
+
+namespace o3dgc
+{
+#ifdef DEBUG_VERBOSE
+        FILE * g_fileDebugDVEnc = NULL;
+#endif //DEBUG_VERBOSE
+
+    inline O3DGCErrorCode Update(long * const data, const long size)
+    {
+        assert(size > 1);
+        const long size1 = size - 1;
+        long p = 2;
+        data[0] += data[1] >> 1;
+        while(p < size1)
+        {
+            data[p] += (data[p-1] + data[p+1] + 2) >> 2;
+            p += 2;
+        }
+        if ( p == size1)
+        {
+            data[p] += data[p-1]>>1;
+        }
+        return O3DGC_OK;
+    }
+    inline O3DGCErrorCode Predict(long * const data, const long size)
+    {   
+        assert(size > 1);
+        const long size1 = size - 1;
+        long p = 1;
+        while(p < size1)
+        {
+            data[p] -= (data[p-1] + data[p+1] + 1) >> 1;
+            p += 2;
+        }
+        if ( p == size1)
+        {
+            data[p] -= data[p-1];
+        }
+        return O3DGC_OK;
+    }
+    inline O3DGCErrorCode Split(long * const data, const long size)
+    {   
+        assert(size > 1);
+        long a = 1;
+        long b = size-1;
+        while (a < b) 
+        {
+            for (long i = a; i < b; i += 2) 
+            {
+                swap(data[i], data[i+1]);
+            }
+            ++a;
+            --b;
+        }
+        return O3DGC_OK;
+    }
+    inline O3DGCErrorCode Transform(long * const data, const unsigned long size)
+    {   
+        unsigned long n = size;
+        while(n > 1)
+        {
+            Predict(data, n);
+            Update (data, n);
+            Split(data, n);
+            n = (n >> 1) + (n & 1);
+        }
+        return O3DGC_OK;
+    }
+    DynamicVectorEncoder::DynamicVectorEncoder(void)
+    {
+        m_maxNumVectors = 0;
+        m_numVectors    = 0;
+        m_dimVectors    = 0;
+        m_quantVectors  = 0;
+        m_sizeBufferAC  = 0;
+        m_bufferAC      = 0;
+        m_posSize       = 0;
+        m_streamType    = O3DGC_STREAM_TYPE_UNKOWN;
+    }
+    DynamicVectorEncoder::~DynamicVectorEncoder()
+    {
+        delete [] m_quantVectors;
+        delete [] m_bufferAC;
+    }
+    O3DGCErrorCode DynamicVectorEncoder::Encode(const DVEncodeParams & params,
+                                                const DynamicVector & dynamicVector,
+                                                BinaryStream & bstream)
+    {
+        assert(params.GetQuantBits() > 0);
+        assert(dynamicVector.GetNVector()   > 0);
+        assert(dynamicVector.GetDimVector() > 0);
+        assert(dynamicVector.GetStride()    >= dynamicVector.GetDimVector());
+        assert(dynamicVector.GetVectors() && dynamicVector.GetMin() && dynamicVector.GetMax());
+        assert(m_streamType != O3DGC_STREAM_TYPE_UNKOWN);
+        // Encode header
+        unsigned long start = bstream.GetSize();
+        EncodeHeader(params, dynamicVector, bstream);
+        // Encode payload
+        EncodePayload(params, dynamicVector, bstream);
+        bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType);
+        return O3DGC_OK;
+
+    }
+    O3DGCErrorCode DynamicVectorEncoder::EncodeHeader(const DVEncodeParams & params,
+                                                      const DynamicVector & dynamicVector,
+                                                      BinaryStream & bstream)
+    {
+        m_streamType = params.GetStreamType();
+        bstream.WriteUInt32(O3DGC_DV_START_CODE, m_streamType);
+        m_posSize = bstream.GetSize();
+        bstream.WriteUInt32(0, m_streamType); // to be filled later
+        bstream.WriteUChar((unsigned char) params.GetEncodeMode(), m_streamType);
+        bstream.WriteUInt32(dynamicVector.GetNVector() , m_streamType);
+        if (dynamicVector.GetNVector() > 0)
+        {
+            bstream.WriteUInt32(dynamicVector.GetDimVector(), m_streamType);
+            bstream.WriteUChar ((unsigned char) params.GetQuantBits(), m_streamType);
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode DynamicVectorEncoder::EncodeAC(unsigned long num, 
+                                                  unsigned long dim, 
+                                                  unsigned long M, 
+                                                  unsigned long & encodedBytes)
+    {
+        Arithmetic_Codec ace;
+        Static_Bit_Model bModel0;
+        Adaptive_Bit_Model bModel1;
+        Adaptive_Data_Model mModelValues(M+2);
+        const unsigned int NMAX = num * dim * 8 + 100;
+        if ( m_sizeBufferAC < NMAX )
+        {
+            delete [] m_bufferAC;
+            m_sizeBufferAC = NMAX;
+            m_bufferAC     = new unsigned char [m_sizeBufferAC];
+        }
+        ace.set_buffer(NMAX, m_bufferAC);
+        ace.start_encoder();
+        ace.ExpGolombEncode(0, 0, bModel0, bModel1);
+        ace.ExpGolombEncode(M, 0, bModel0, bModel1);
+        for(unsigned long v = 0; v < num; ++v)
+        {
+            for(unsigned long d = 0; d < dim; ++d)
+            {
+                EncodeIntACEGC(m_quantVectors[d * num + v], ace, mModelValues, bModel0, bModel1, M);
+            }
+        }
+        encodedBytes = ace.stop_encoder();
+        return O3DGC_OK;
+    }
+
+    O3DGCErrorCode DynamicVectorEncoder::EncodePayload(const DVEncodeParams & params,
+                                                       const DynamicVector & dynamicVector,
+                                                       BinaryStream & bstream)
+    {
+#ifdef DEBUG_VERBOSE
+        g_fileDebugDVEnc = fopen("dv_enc.txt", "w");
+#endif //DEBUG_VERBOSE
+        unsigned long      start = bstream.GetSize();
+        const unsigned long dim  = dynamicVector.GetDimVector();
+        const unsigned long num  = dynamicVector.GetNVector();
+
+        bstream.WriteUInt32(0, m_streamType);
+
+        for(unsigned long j=0 ; j<dynamicVector.GetDimVector() ; ++j)
+        {
+            bstream.WriteFloat32((float) dynamicVector.GetMin(j), m_streamType);
+            bstream.WriteFloat32((float) dynamicVector.GetMax(j), m_streamType);
+        }
+        Quantize(dynamicVector.GetVectors(), 
+                 num, 
+                 dim,
+                 dynamicVector.GetStride(),
+                 dynamicVector.GetMin(),
+                 dynamicVector.GetMax(),
+                 params.GetQuantBits());
+        for(unsigned long d = 0; d < dim; ++d)
+        {
+            Transform(m_quantVectors + d * num, num);
+        }
+        #ifdef DEBUG_VERBOSE
+        printf("IntArray (%i, %i)\n", num, dim);
+        fprintf(g_fileDebugDVEnc, "IntArray (%i, %i)\n", num, dim);
+        for(unsigned long v = 0; v < num; ++v)
+        {
+            for(unsigned long d = 0; d < dim; ++d)
+            {
+                printf("%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
+                fprintf(g_fileDebugDVEnc, "%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
+            }
+        }
+        #endif //DEBUG_VERBOSE
+
+        if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            for(unsigned long v = 0; v < num; ++v)
+            {
+                for(unsigned long d = 0; d < dim; ++d)
+                {
+                    bstream.WriteIntASCII(m_quantVectors[d * num + v]);
+                }
+            }
+        }
+        else
+        {
+            unsigned long encodedBytes = 0;
+            unsigned long bestEncodedBytes = O3DGC_MAX_ULONG;
+            unsigned long M = 1;
+            unsigned long bestM = 1;
+            while (M < 1024)
+            {
+                EncodeAC(num, dim, M, encodedBytes);
+                if (encodedBytes > bestEncodedBytes)
+                {
+                    break;
+                }
+                bestM = M;
+                bestEncodedBytes = encodedBytes;
+                M *= 2;
+            }
+            EncodeAC(num, dim, bestM, encodedBytes);
+            for(unsigned long i = 0; i < encodedBytes; ++i)
+            {
+                bstream.WriteUChar8Bin(m_bufferAC[i]);
+            }
+        }
+        bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
+#ifdef DEBUG_VERBOSE
+        fclose(g_fileDebugDVEnc);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode DynamicVectorEncoder::Quantize(const Real * const floatArray, 
+                                                  unsigned long numFloatArray,
+                                                  unsigned long dimFloatArray,
+                                                  unsigned long stride,
+                                                  const Real * const minFloatArray,
+                                                  const Real * const maxFloatArray,
+                                                  unsigned long nQBits)
+    {
+        const unsigned long size = numFloatArray * dimFloatArray;
+        Real r;
+        if (m_maxNumVectors < size)
+        {
+            delete [] m_quantVectors;
+            m_maxNumVectors = size;
+            m_quantVectors = new long [m_maxNumVectors];
+        }
+        Real delta;
+        for(unsigned long d = 0; d < dimFloatArray; ++d)
+        {
+            r = maxFloatArray[d] - minFloatArray[d];
+            if (r > 0.0f)
+            {
+                delta = (float)((1 << nQBits) - 1) / r;
+            }
+            else
+            {
+                delta = 1.0f;
+            }
+            for(unsigned long v = 0; v < numFloatArray; ++v)
+            {
+                m_quantVectors[v + d * numFloatArray] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta + 0.5f);
+            }
+        }
+        return O3DGC_OK;
+    }
+}

+ 79 - 0
contrib/Open3DGC/o3dgcDynamicVectorEncoder.h

@@ -0,0 +1,79 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_DYNAMIC_VECTOR_ENCODER_H
+#define O3DGC_DYNAMIC_VECTOR_ENCODER_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcBinaryStream.h"
+#include "o3dgcDynamicVector.h"
+
+namespace o3dgc
+{
+    //! 
+    class DynamicVectorEncoder
+    {
+    public:    
+        //! Constructor.
+                                    DynamicVectorEncoder(void);
+        //! Destructor.
+                                    ~DynamicVectorEncoder(void);
+        //! 
+        O3DGCErrorCode              Encode(const DVEncodeParams & params,
+                                           const DynamicVector & dynamicVector,
+                                           BinaryStream & bstream);
+        O3DGCStreamType             GetStreamType() const { return m_streamType; }
+        void                        SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
+
+        private:
+        O3DGCErrorCode              EncodeHeader(const DVEncodeParams & params,
+                                                 const DynamicVector & dynamicVector,
+                                                 BinaryStream & bstream);
+        O3DGCErrorCode              EncodePayload(const DVEncodeParams & params, 
+                                                  const DynamicVector & dynamicVector,
+                                                  BinaryStream & bstream);
+        O3DGCErrorCode              Quantize(const Real * const floatArray, 
+                                             unsigned long numFloatArray,
+                                             unsigned long dimFloatArray,
+                                             unsigned long stride,
+                                             const Real * const minFloatArray,
+                                             const Real * const maxFloatArray,
+                                             unsigned long nQBits);
+        O3DGCErrorCode              EncodeAC(unsigned long num, 
+                                             unsigned long dim, 
+                                             unsigned long M, 
+                                             unsigned long & encodedBytes);
+
+        unsigned long               m_posSize;
+        unsigned long               m_sizeBufferAC;
+        unsigned long               m_maxNumVectors;
+        unsigned long               m_numVectors;
+        unsigned long               m_dimVectors;
+        unsigned char *             m_bufferAC;
+        long *                      m_quantVectors;
+        O3DGCStreamType             m_streamType;
+    };
+}
+#endif // O3DGC_DYNAMIC_VECTOR_ENCODER_H
+

+ 97 - 0
contrib/Open3DGC/o3dgcFIFO.h

@@ -0,0 +1,97 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_FIFO_H
+#define O3DGC_FIFO_H
+
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    //! 
+    template < typename T > class FIFO
+    {
+    public:
+        //! Constructor.
+                                FIFO()
+                                {
+                                    m_buffer    = 0;
+                                    m_allocated = 0;
+                                    m_size      = 0;
+                                    m_start     = 0;
+                                    m_end       = 0;
+                                };
+        //! Destructor.
+                                ~FIFO(void)
+                                {
+                                    delete [] m_buffer;
+                                };
+        O3DGCErrorCode          Allocate(unsigned long size)
+                                {
+                                    assert(size > 0);
+                                    if (size > m_allocated)
+                                    {
+                                        delete [] m_buffer;
+                                        m_allocated = size;
+                                        m_buffer = new T [m_allocated];
+                                    }
+                                    Clear();
+                                    return O3DGC_OK;
+                                }
+        const T &               PopFirst()
+                                {
+                                    assert(m_size > 0);
+                                    --m_size;
+                                    unsigned long current = m_start++;
+                                    if (m_start == m_allocated) 
+                                    {
+                                        m_end = 0;
+                                    }
+                                    return m_buffer[current];
+                                };
+        void                    PushBack(const T & value)
+                                {
+                                    assert( m_size < m_allocated);
+                                    m_buffer[m_end] = value;
+                                    ++m_size;
+                                    ++m_end;
+                                    if (m_end == m_allocated) 
+                                    {
+                                        m_end = 0;
+                                    }
+                                }
+        const unsigned long     GetSize()          const { return m_size;};
+        const unsigned long     GetAllocatedSize() const { return m_allocated;};
+        void                    Clear() { m_start = m_end = m_size = 0;};
+
+    private:
+        T *                     m_buffer;
+        unsigned long           m_allocated;
+        unsigned long           m_size;
+        unsigned long           m_start;
+        unsigned long           m_end;
+    };
+}
+#endif // O3DGC_FIFO_H
+

+ 263 - 0
contrib/Open3DGC/o3dgcIndexedFaceSet.h

@@ -0,0 +1,263 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_INDEXED_FACE_SET_H
+#define O3DGC_INDEXED_FACE_SET_H
+
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    template<class T>
+    class IndexedFaceSet
+    {
+    public:    
+        //! Constructor.
+                                         IndexedFaceSet(void)
+                                         {
+                                             memset(this, 0, sizeof(IndexedFaceSet));
+                                             m_ccw              = true;
+                                             m_solid            = true;
+                                             m_convex           = true;
+                                             m_isTriangularMesh = true;
+                                             m_creaseAngle      = 30;
+                                         };
+        //! Destructor.
+                                         ~IndexedFaceSet(void) {};
+        
+        unsigned long                    GetNCoordIndex() const { return m_nCoordIndex     ;}
+        // only coordIndex is supported
+        unsigned long                    GetNCoord()           const { return m_nCoord         ;}
+        unsigned long                    GetNNormal()          const { return m_nNormal        ;}
+        unsigned long                    GetNFloatAttribute(unsigned long a)  const 
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             return m_nFloatAttribute[a];
+                                         }
+        unsigned long                    GetNIntAttribute(unsigned long a)  const 
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             return m_nIntAttribute[a];
+                                         }
+        unsigned long                    GetNumFloatAttributes()  const { return m_numFloatAttributes;}
+        unsigned long                    GetNumIntAttributes()    const { return m_numIntAttributes  ;}
+        const Real * const               GetCoordMin   () const { return m_coordMin;}
+        const Real * const               GetCoordMax   () const { return m_coordMax;}
+        const Real * const               GetNormalMin  () const { return m_normalMin;}
+        const Real * const               GetNormalMax  () const { return m_normalMax;}
+        Real                             GetCoordMin   (int j)  const { return m_coordMin[j]       ;}
+        Real                             GetCoordMax   (int j)  const { return m_coordMax[j]       ;}
+        Real                             GetNormalMin  (int j)  const { return m_normalMin[j]      ;}
+        Real                             GetNormalMax  (int j)  const { return m_normalMax[j]      ;}
+
+        const O3DGCIFSFloatAttributeType GetFloatAttributeType(unsigned long a) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             return m_typeFloatAttribute[a];
+                                         }
+        const O3DGCIFSIntAttributeType   GetIntAttributeType(unsigned long a) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             return m_typeIntAttribute[a];
+                                         }
+        const unsigned long              GetFloatAttributeDim(unsigned long a) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             return m_dimFloatAttribute[a];
+                                         }
+        unsigned long                    GetIntAttributeDim(unsigned long a) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             return m_dimIntAttribute[a];
+                                         }
+        const Real * const               GetFloatAttributeMin(unsigned long a) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             return &(m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]);
+                                         }
+        const Real * const               GetFloatAttributeMax(unsigned long a) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             return &(m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]);
+                                         }
+        Real                             GetFloatAttributeMin(unsigned long a, unsigned long dim) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+                                             return m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim];
+                                         }
+        Real                             GetFloatAttributeMax(unsigned long a, unsigned long dim) const
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+                                             return m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim];
+                                         }
+        Real                             GetCreaseAngle()      const { return m_creaseAngle     ;}
+        bool                             GetCCW()              const { return m_ccw             ;}
+        bool                             GetSolid()            const { return m_solid           ;}
+        bool                             GetConvex()           const { return m_convex          ;}
+        bool                             GetIsTriangularMesh() const { return m_isTriangularMesh;}
+        const unsigned long * const      GetIndexBufferID()    const { return m_indexBufferID   ;}
+        const T * const                  GetCoordIndex()       const { return m_coordIndex;}
+        T * const                        GetCoordIndex()             { return m_coordIndex;}
+        Real * const                     GetCoord()            const { return m_coord     ;}
+        Real * const                     GetNormal()           const { return m_normal    ;}
+        Real * const                     GetFloatAttribute(unsigned long a)  const 
+                                         {
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             return m_floatAttribute[a];
+                                         }
+        long * const                     GetIntAttribute(unsigned long a)   const 
+                                         {
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             return m_intAttribute[a]  ;
+                                         }
+        // only coordIndex is supported
+        void                             SetNNormalIndex(unsigned long)      {}
+        void                             SetNTexCoordIndex(unsigned long)    {}
+        void                             SetNFloatAttributeIndex(int, unsigned long) {}
+        void                             SetNIntAttributeIndex (int, unsigned long) {}
+        // per triangle attributes not supported
+        void                             SetNormalPerVertex(bool)   {} 
+        void                             SetColorPerVertex(bool)    {}
+        void                             SetFloatAttributePerVertex(int, bool){}
+        void                             SetIntAttributePerVertex  (int, bool){}
+        void                             SetNCoordIndex     (unsigned long nCoordIndex)     { m_nCoordIndex = nCoordIndex;}
+        void                             SetNCoord          (unsigned long nCoord)          { m_nCoord      = nCoord     ;}
+        void                             SetNNormal         (unsigned long nNormal)         { m_nNormal     = nNormal    ;}
+        void                             SetNumFloatAttributes(unsigned long numFloatAttributes) 
+                                         { 
+                                             assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             m_numFloatAttributes = numFloatAttributes;
+                                         }
+        void                             SetNumIntAttributes  (unsigned long numIntAttributes)
+                                         { 
+                                             assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             m_numIntAttributes = numIntAttributes;
+                                         }
+        void                             SetCreaseAngle      (Real creaseAngle)      { m_creaseAngle      = creaseAngle     ;}
+        void                             SetCCW              (bool ccw)              { m_ccw              = ccw             ;}
+        void                             SetSolid            (bool solid)            { m_solid            = solid           ;}
+        void                             SetConvex           (bool convex)           { m_convex           = convex          ;}
+        void                             SetIsTriangularMesh (bool isTriangularMesh) { m_isTriangularMesh = isTriangularMesh;}
+        void                             SetCoordMin        (int j, Real min) { m_coordMin[j]    = min;}
+        void                             SetCoordMax        (int j, Real max) { m_coordMax[j]    = max;}
+        void                             SetNormalMin       (int j, Real min) { m_normalMin[j]   = min;}
+        void                             SetNormalMax       (int j, Real max) { m_normalMax[j]   = max;}
+        void                             SetNFloatAttribute(unsigned long a, unsigned long nFloatAttribute) 
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             m_nFloatAttribute[a] = nFloatAttribute;
+                                         }
+        void                             SetNIntAttribute(unsigned long a, unsigned long nIntAttribute) 
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             m_nIntAttribute[a] = nIntAttribute;
+                                         }
+        void                             SetFloatAttributeDim(unsigned long a, unsigned long d)
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             m_dimFloatAttribute[a] = d;
+                                         }
+        void                             SetIntAttributeDim(unsigned long a, unsigned long d)
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             m_dimIntAttribute[a] = d;
+                                         }
+        void                             SetFloatAttributeType(unsigned long a, O3DGCIFSFloatAttributeType t)
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             m_typeFloatAttribute[a] = t;
+                                         }
+        void                             SetIntAttributeType(unsigned long a, O3DGCIFSIntAttributeType t)
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             m_typeIntAttribute[a] = t;
+                                         }
+        void                             SetFloatAttributeMin(unsigned long a, unsigned long dim, Real min) 
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+                                             m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = min;
+                                         }
+        void                             SetFloatAttributeMax(unsigned long a, unsigned long dim, Real max) 
+                                         { 
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+                                             m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = max;
+                                         }
+        void                             SetIndexBufferID  (unsigned long * const indexBufferID) { m_indexBufferID = indexBufferID;}
+        void                             SetCoordIndex     (T * const coordIndex)    { m_coordIndex = coordIndex;}
+        void                             SetCoord          (Real * const coord     ) { m_coord      = coord    ;}
+        void                             SetNormal         (Real * const normal    ) { m_normal     = normal   ;}
+        void                             SetFloatAttribute (unsigned long a, Real * const floatAttribute) 
+                                         {
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                             m_floatAttribute[a] = floatAttribute;
+                                         }
+        void                             SetIntAttribute   (unsigned long a, long * const intAttribute)
+                                         {
+                                             assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                             m_intAttribute[a] = intAttribute ;
+                                         }
+        void                             ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode);
+
+    private:
+        // triangles list
+        unsigned long                    m_nCoordIndex;
+        T *                              m_coordIndex;
+        unsigned long *                  m_indexBufferID;
+        // coord, normals, texcoord and color
+        unsigned long                    m_nCoord;
+        unsigned long                    m_nNormal;
+        Real                             m_coordMin   [3];
+        Real                             m_coordMax   [3];
+        Real                             m_normalMin  [3];
+        Real                             m_normalMax  [3];
+        Real *                           m_coord;
+        Real *                           m_normal;
+        // other attributes
+        unsigned long                    m_numFloatAttributes;
+        unsigned long                    m_numIntAttributes;
+        O3DGCIFSFloatAttributeType       m_typeFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        O3DGCIFSIntAttributeType         m_typeIntAttribute   [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES  ];
+        unsigned long                    m_nFloatAttribute    [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        unsigned long                    m_nIntAttribute      [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES  ];
+        unsigned long                    m_dimFloatAttribute  [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        unsigned long                    m_dimIntAttribute    [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES  ];
+        Real                             m_minFloatAttribute  [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
+        Real                             m_maxFloatAttribute  [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
+        Real *                           m_floatAttribute     [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        long *                           m_intAttribute       [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        // mesh info                     
+        Real                             m_creaseAngle;
+        bool                             m_ccw;
+        bool                             m_solid;
+        bool                             m_convex;
+        bool                             m_isTriangularMesh;
+    };
+}
+#include "o3dgcIndexedFaceSet.inl"    // template implementation
+#endif // O3DGC_INDEXED_FACE_SET_H
+

+ 47 - 0
contrib/Open3DGC/o3dgcIndexedFaceSet.inl

@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_INDEXED_FACE_SET_INL
+#define O3DGC_INDEXED_FACE_SET_INL
+
+#include <math.h>
+namespace o3dgc
+{
+    template <class T>
+    void IndexedFaceSet<T>::ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode)
+    {
+        ComputeVectorMinMax(m_coord   , m_nCoord   , 3, 3, m_coordMin   , m_coordMax   , quantMode);
+        ComputeVectorMinMax(m_normal  , m_nNormal  , 3, 3, m_normalMin  , m_normalMax  , quantMode);
+        unsigned long numFloatAttributes = GetNumFloatAttributes();
+        for(unsigned long a = 0; a < numFloatAttributes; ++a)
+        {
+            ComputeVectorMinMax(m_floatAttribute[a], 
+                                m_nFloatAttribute[a],
+                                m_dimFloatAttribute[a], 
+                                m_dimFloatAttribute[a], // stride
+                                m_minFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES), 
+                                m_maxFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES), quantMode);
+        }
+    }
+}
+#endif // O3DGC_INDEXED_FACE_SET_INL

+ 111 - 0
contrib/Open3DGC/o3dgcSC3DMCDecoder.h

@@ -0,0 +1,111 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_SC3DMC_DECODER_H
+#define O3DGC_SC3DMC_DECODER_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcBinaryStream.h"
+#include "o3dgcIndexedFaceSet.h"
+#include "o3dgcSC3DMCEncodeParams.h"
+#include "o3dgcTriangleListDecoder.h"
+
+namespace o3dgc
+{    
+    //! 
+    template <class T>
+    class SC3DMCDecoder
+    {
+    public:    
+        //! Constructor.
+                                    SC3DMCDecoder(void)
+                                    {
+                                        m_iterator            = 0;
+                                        m_streamSize          = 0;
+                                        m_quantFloatArray     = 0;
+                                        m_quantFloatArraySize = 0;
+                                        m_normals             = 0;
+                                        m_normalsSize         = 0;
+                                        m_streamType          = O3DGC_STREAM_TYPE_UNKOWN;
+                                    };
+        //! Destructor.
+                                    ~SC3DMCDecoder(void)
+                                    {
+                                        delete [] m_normals;
+                                        delete [] m_quantFloatArray;
+                                    }
+        //!
+        O3DGCErrorCode              DecodeHeader(IndexedFaceSet<T> & ifs,
+                                                 const BinaryStream & bstream);
+        //!                         
+		O3DGCErrorCode              DecodePayload(IndexedFaceSet<T> & ifs,
+                                                  const BinaryStream & bstream);
+        const SC3DMCStats &         GetStats()    const { return m_stats;}
+        unsigned long               GetIterator() const { return m_iterator;}
+		O3DGCErrorCode              SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; }
+        
+
+    private:                        
+        O3DGCErrorCode              DecodeFloatArray(Real * const floatArray,
+                                                     unsigned long numfloatArraySize,
+                                                     unsigned long dimfloatArraySize,
+                                                     unsigned long stride,
+                                                     const Real * const minfloatArray,
+                                                     const Real * const maxfloatArray,
+                                                     unsigned long nQBits,
+                                                     const IndexedFaceSet<T> & ifs,
+                                                     O3DGCSC3DMCPredictionMode & predMode,
+                                                     const BinaryStream & bstream);
+        O3DGCErrorCode              IQuantizeFloatArray(Real * const floatArray,
+                                                       unsigned long numfloatArraySize,
+                                                       unsigned long dimfloatArraySize,
+                                                       unsigned long stride,
+                                                       const Real * const minfloatArray,
+                                                       const Real * const maxfloatArray,
+                                                       unsigned long nQBits);
+        O3DGCErrorCode              DecodeIntArray(long * const intArray, 
+                                                   unsigned long numIntArraySize,
+                                                   unsigned long dimIntArraySize,
+                                                   unsigned long stride,
+                                                   const IndexedFaceSet<T> & ifs,
+                                                   O3DGCSC3DMCPredictionMode & predMode,
+                                                   const BinaryStream & bstream);
+        O3DGCErrorCode              ProcessNormals(const IndexedFaceSet<T> & ifs);
+
+        unsigned long               m_iterator;
+        unsigned long               m_streamSize;
+        SC3DMCEncodeParams          m_params;
+        TriangleListDecoder<T>      m_triangleListDecoder;
+        long *                      m_quantFloatArray;
+        unsigned long               m_quantFloatArraySize;
+        Vector<char>                m_orientation;
+        Real *                      m_normals;
+        unsigned long               m_normalsSize;
+        SC3DMCStats                 m_stats;
+        O3DGCStreamType             m_streamType;
+    };
+}
+#include "o3dgcSC3DMCDecoder.inl"    // template implementation
+#endif // O3DGC_SC3DMC_DECODER_H
+

+ 850 - 0
contrib/Open3DGC/o3dgcSC3DMCDecoder.inl

@@ -0,0 +1,850 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_SC3DMC_DECODER_INL
+#define O3DGC_SC3DMC_DECODER_INL
+
+#include "o3dgcArithmeticCodec.h"
+#include "o3dgcTimer.h"
+
+//#define DEBUG_VERBOSE
+
+namespace o3dgc
+{
+#ifdef DEBUG_VERBOSE
+        FILE * g_fileDebugSC3DMCDec = NULL;
+#endif //DEBUG_VERBOSE
+
+    template<class T>
+    O3DGCErrorCode SC3DMCDecoder<T>::DecodeHeader(IndexedFaceSet<T> & ifs, 
+                                                  const BinaryStream & bstream)
+    {
+        unsigned long iterator0 = m_iterator;
+        unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY);
+        if (start_code != O3DGC_SC3DMC_START_CODE)
+        {
+            m_iterator = iterator0;
+            start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII);
+            if (start_code != O3DGC_SC3DMC_START_CODE)
+            {
+                return O3DGC_ERROR_CORRUPTED_STREAM;
+            }
+            else
+            {
+                m_streamType = O3DGC_STREAM_TYPE_ASCII;
+            }
+        }
+        else
+        {
+            m_streamType = O3DGC_STREAM_TYPE_BINARY;
+        }
+            
+        m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType);
+        m_params.SetEncodeMode( (O3DGCSC3DMCEncodingMode) bstream.ReadUChar(m_iterator, m_streamType));
+
+        ifs.SetCreaseAngle((Real) bstream.ReadFloat32(m_iterator, m_streamType));
+          
+        unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType);
+
+        ifs.SetCCW             ((mask & 1) == 1);
+        ifs.SetSolid           ((mask & 2) == 1);
+        ifs.SetConvex          ((mask & 4) == 1);
+        ifs.SetIsTriangularMesh((mask & 8) == 1);
+        //bool markerBit0 = (mask & 16 ) == 1;
+        //bool markerBit1 = (mask & 32 ) == 1;
+        //bool markerBit2 = (mask & 64 ) == 1;
+        //bool markerBit3 = (mask & 128) == 1;
+       
+        ifs.SetNCoord         (bstream.ReadUInt32(m_iterator, m_streamType));
+        ifs.SetNNormal        (bstream.ReadUInt32(m_iterator, m_streamType));
+
+
+        ifs.SetNumFloatAttributes(bstream.ReadUInt32(m_iterator, m_streamType));
+        ifs.SetNumIntAttributes  (bstream.ReadUInt32(m_iterator, m_streamType));
+                              
+        if (ifs.GetNCoord() > 0)
+        {
+            ifs.SetNCoordIndex(bstream.ReadUInt32(m_iterator, m_streamType));
+            for(int j=0 ; j<3 ; ++j)
+            {
+                ifs.SetCoordMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+                ifs.SetCoordMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+            }
+            m_params.SetCoordQuantBits( bstream.ReadUChar(m_iterator, m_streamType) );
+        }
+        if (ifs.GetNNormal() > 0)
+        {
+            ifs.SetNNormalIndex(bstream.ReadUInt32(m_iterator, m_streamType));
+            for(int j=0 ; j<3 ; ++j)
+            {
+                ifs.SetNormalMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+                ifs.SetNormalMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+            }
+            ifs.SetNormalPerVertex(bstream.ReadUChar(m_iterator, m_streamType) == 1);
+            m_params.SetNormalQuantBits(bstream.ReadUChar(m_iterator, m_streamType));
+        }
+
+        for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
+        {
+            ifs.SetNFloatAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType));    
+            if (ifs.GetNFloatAttribute(a) > 0)
+            {
+                ifs.SetNFloatAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType));
+                unsigned char d = bstream.ReadUChar(m_iterator, m_streamType);
+                ifs.SetFloatAttributeDim(a, d);
+                for(unsigned char j = 0 ; j < d ; ++j)
+                {
+                    ifs.SetFloatAttributeMin(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+                    ifs.SetFloatAttributeMax(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
+                }
+                ifs.SetFloatAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1);
+                ifs.SetFloatAttributeType(a, (O3DGCIFSFloatAttributeType) bstream.ReadUChar(m_iterator, m_streamType));
+                m_params.SetFloatAttributeQuantBits(a, bstream.ReadUChar(m_iterator, m_streamType));
+            }
+        }
+        for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
+        {
+            ifs.SetNIntAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType));
+            if (ifs.GetNIntAttribute(a) > 0)
+            {
+                ifs.SetNIntAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType));
+                ifs.SetIntAttributeDim(a, bstream.ReadUChar(m_iterator, m_streamType));
+                ifs.SetIntAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1);
+                ifs.SetIntAttributeType(a, (O3DGCIFSIntAttributeType) bstream.ReadUChar(m_iterator, m_streamType));
+            }
+        }    
+        return O3DGC_OK;
+    }
+    template<class T>
+	O3DGCErrorCode SC3DMCDecoder<T>::DecodePayload(IndexedFaceSet<T> & ifs,
+                                                    const BinaryStream & bstream)
+    {
+        O3DGCErrorCode ret = O3DGC_OK;
+#ifdef DEBUG_VERBOSE
+        g_fileDebugSC3DMCDec = fopen("tfans_dec_main.txt", "w");
+#endif //DEBUG_VERBOSE
+
+        m_triangleListDecoder.SetStreamType(m_streamType);
+        m_stats.m_streamSizeCoordIndex = m_iterator;
+        Timer timer;
+        timer.Tic();
+        m_triangleListDecoder.Decode(ifs.GetCoordIndex(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream, m_iterator);
+        timer.Toc();
+        m_stats.m_timeCoordIndex       = timer.GetElapsedTime();
+        m_stats.m_streamSizeCoordIndex = m_iterator - m_stats.m_streamSizeCoordIndex;
+
+        // decode coord
+        m_stats.m_streamSizeCoord = m_iterator;
+        timer.Tic();
+        if (ifs.GetNCoord() > 0)
+        {
+            ret = DecodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(),
+                                   m_params.GetCoordQuantBits(), ifs, m_params.GetCoordPredMode(), bstream);
+        }
+        if (ret != O3DGC_OK)
+        {
+            return ret;
+        }
+        timer.Toc();
+        m_stats.m_timeCoord       = timer.GetElapsedTime();
+        m_stats.m_streamSizeCoord = m_iterator - m_stats.m_streamSizeCoord;
+
+        // decode Normal
+        m_stats.m_streamSizeNormal = m_iterator;
+        timer.Tic();
+        if (ifs.GetNNormal() > 0)
+        {
+            DecodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(),
+                                m_params.GetNormalQuantBits(), ifs, m_params.GetNormalPredMode(), bstream);
+        }
+        if (ret != O3DGC_OK)
+        {
+            return ret;
+        }
+        timer.Toc();
+        m_stats.m_timeNormal       = timer.GetElapsedTime();
+        m_stats.m_streamSizeNormal = m_iterator - m_stats.m_streamSizeNormal;
+
+        // decode FloatAttributes
+        for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
+        {
+            m_stats.m_streamSizeFloatAttribute[a] = m_iterator;
+            timer.Tic();
+            DecodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a), 
+                                ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a), 
+                                m_params.GetFloatAttributeQuantBits(a), ifs, m_params.GetFloatAttributePredMode(a), bstream);
+            timer.Toc();
+            m_stats.m_timeFloatAttribute[a]       = timer.GetElapsedTime();
+            m_stats.m_streamSizeFloatAttribute[a] = m_iterator - m_stats.m_streamSizeFloatAttribute[a];
+        }
+        if (ret != O3DGC_OK)
+        {
+            return ret;
+        }
+
+        // decode IntAttributes
+        for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
+        {
+            m_stats.m_streamSizeIntAttribute[a] = m_iterator;
+            timer.Tic();
+            DecodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), ifs.GetIntAttributeDim(a), 
+                           ifs, m_params.GetIntAttributePredMode(a), bstream);
+            timer.Toc();
+            m_stats.m_timeIntAttribute[a]       = timer.GetElapsedTime();
+            m_stats.m_streamSizeIntAttribute[a] = m_iterator - m_stats.m_streamSizeIntAttribute[a];
+        }
+        if (ret != O3DGC_OK)
+        {
+            return ret;
+        }
+
+        timer.Tic();
+        m_triangleListDecoder.Reorder();
+        timer.Toc();
+        m_stats.m_timeReorder       = timer.GetElapsedTime();
+
+#ifdef DEBUG_VERBOSE
+        fclose(g_fileDebugSC3DMCDec);
+#endif //DEBUG_VERBOSE
+        return ret;
+    }
+    template<class T>
+    O3DGCErrorCode SC3DMCDecoder<T>::DecodeIntArray(long * const intArray, 
+                                                    unsigned long numIntArray,
+                                                    unsigned long dimIntArray,
+                                                    unsigned long stride,
+                                                    const IndexedFaceSet<T> & ifs,
+                                                    O3DGCSC3DMCPredictionMode & predMode,
+                                                    const BinaryStream & bstream)
+    {
+        assert(dimIntArray <  O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+        long predResidual;
+        SC3DMCPredictor m_neighbors  [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
+        Arithmetic_Codec acd;
+        Static_Bit_Model bModel0;
+        Adaptive_Bit_Model bModel1;
+        Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
+        unsigned long nPred;
+
+        const AdjacencyInfo & v2T            = m_triangleListDecoder.GetVertexToTriangle();
+        const T * const     triangles        = ifs.GetCoordIndex();
+        const long          nvert            = (long) numIntArray;
+        unsigned char *     buffer           = 0;
+        unsigned long       start            = m_iterator;
+        unsigned long       streamSize       = bstream.ReadUInt32(m_iterator, m_streamType);        // bitsream size
+        unsigned char mask                   = bstream.ReadUChar(m_iterator, m_streamType);
+        O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7);
+        predMode                             = (O3DGCSC3DMCPredictionMode)(mask & 7);
+        streamSize                          -= (m_iterator - start);
+        unsigned long       iteratorPred     = m_iterator + streamSize;
+        unsigned int        exp_k            = 0;
+        unsigned int        M                = 0;
+        if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
+        {
+            if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC)
+            {
+                return O3DGC_ERROR_CORRUPTED_STREAM;
+            }
+            bstream.GetBuffer(m_iterator, buffer);
+            m_iterator += streamSize;
+            acd.set_buffer(streamSize, buffer);
+            acd.start_decoder();
+            exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
+            M     = acd.ExpGolombDecode(0, bModel0, bModel1);
+        }
+        else
+        {
+            if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII)
+            {
+                return O3DGC_ERROR_CORRUPTED_STREAM;
+            }
+            bstream.ReadUInt32(iteratorPred, m_streamType);        // predictors bitsream size
+        }
+        Adaptive_Data_Model mModelValues(M+2);
+
+#ifdef DEBUG_VERBOSE
+        printf("IntArray (%i, %i)\n", numIntArray, dimIntArray);
+        fprintf(g_fileDebugSC3DMCDec, "IntArray (%i, %i)\n", numIntArray, dimIntArray);
+#endif //DEBUG_VERBOSE
+
+        for (long v=0; v < nvert; ++v) 
+        {
+            nPred = 0;
+            if ( v2T.GetNumNeighbors(v) > 0 && 
+                 predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                int u0 = v2T.Begin(v);
+                int u1 = v2T.End(v);
+                for (long u = u0; u < u1; u++) 
+                {
+                    long ta = v2T.GetNeighbor(u);
+                    if (ta < 0)
+                    {
+                        break;
+                    }
+                    for(long k = 0; k < 3; ++k)
+                    {
+                        long w = triangles[ta*3 + k];
+                        if ( w < v )
+                        {
+                            SC3DMCTriplet id = {-1, -1, w};
+                            unsigned long p = Insert(id, nPred, m_neighbors);
+                            if (p != 0xFFFFFFFF)
+                            {
+                                for (unsigned long i = 0; i < dimIntArray; i++) 
+                                {
+                                    m_neighbors[p].m_pred[i] = intArray[w*stride+i];
+                                } 
+                            }
+                        }
+                    }
+                }
+            }
+            if (nPred > 1)
+            {
+#ifdef DEBUG_VERBOSE1
+                printf("\t\t vm %i\n", v);
+                fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v);
+                for (unsigned long p = 0; p < nPred; ++p)
+                {
+                    printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+                    fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+                    for (unsigned long i = 0; i < dimIntArray; ++i) 
+                    {
+                        printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+                        fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+                    }
+                }
+#endif //DEBUG_VERBOSE
+                unsigned long bestPred;
+                if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                {
+                    bestPred = bstream.ReadUCharASCII(iteratorPred);
+                }
+                else
+                {
+                    bestPred = acd.decode(mModelPreds);
+                }
+#ifdef DEBUG_VERBOSE1
+                    printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+                    fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+#endif //DEBUG_VERBOSE
+                for (unsigned long i = 0; i < dimIntArray; i++) 
+                {
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        predResidual = bstream.ReadIntASCII(m_iterator);
+                    }
+                    else
+                    {
+                        predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
+                    }
+                    intArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i];
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+                    fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+#endif //DEBUG_VERBOSE
+                }
+            }
+            else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                for (unsigned long i = 0; i < dimIntArray; i++) 
+                {
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        predResidual = bstream.ReadIntASCII(m_iterator);
+                    }
+                    else
+                    {
+                        predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
+                    }
+                    intArray[v*stride+i] = predResidual + intArray[(v-1)*stride+i];
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", v*dimIntArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+            else
+            {
+                for (unsigned long i = 0; i < dimIntArray; i++) 
+                {
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        predResidual = bstream.ReadUIntASCII(m_iterator);
+                    }
+                    else
+                    {
+                        predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
+                    }
+                    intArray[v*stride+i] = predResidual;
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", v*dimIntArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+        }
+        m_iterator  = iteratorPred;
+#ifdef DEBUG_VERBOSE
+        fflush(g_fileDebugSC3DMCDec);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode SC3DMCDecoder<T>::ProcessNormals(const IndexedFaceSet<T> & ifs)
+    {
+        const long nvert               = (long) ifs.GetNNormal();
+        const unsigned long normalSize = ifs.GetNNormal() * 2;
+        if (m_normalsSize < normalSize)
+        {
+            delete [] m_normals;
+            m_normalsSize = normalSize;
+            m_normals     = new Real [normalSize];
+        }                                  
+        const AdjacencyInfo & v2T          = m_triangleListDecoder.GetVertexToTriangle();
+        const T * const       triangles    = ifs.GetCoordIndex();        
+        Vec3<long> p1, p2, p3, n0, nt;
+        long na0, nb0;
+        Real rna0, rnb0, norm0;
+        char ni0 = 0, ni1 = 0;
+        long a, b, c;
+        for (long v=0; v < nvert; ++v) 
+        {
+            n0.X() = 0;
+            n0.Y() = 0;
+            n0.Z() = 0;
+            int u0 = v2T.Begin(v);
+            int u1 = v2T.End(v);
+            for (long u = u0; u < u1; u++) 
+            {
+                long ta = v2T.GetNeighbor(u);
+                if (ta == -1)
+                {
+                    break;
+                }
+                a = triangles[ta*3 + 0];
+                b = triangles[ta*3 + 1];
+                c = triangles[ta*3 + 2];
+                p1.X() = m_quantFloatArray[3*a];
+                p1.Y() = m_quantFloatArray[3*a+1];
+                p1.Z() = m_quantFloatArray[3*a+2];
+                p2.X() = m_quantFloatArray[3*b];
+                p2.Y() = m_quantFloatArray[3*b+1];
+                p2.Z() = m_quantFloatArray[3*b+2];
+                p3.X() = m_quantFloatArray[3*c];
+                p3.Y() = m_quantFloatArray[3*c+1];
+                p3.Z() = m_quantFloatArray[3*c+2];
+                nt  = (p2-p1)^(p3-p1);
+                n0 += nt;
+            }
+            norm0 = (Real) n0.GetNorm();
+            if (norm0 == 0.0)
+            {
+                norm0 = 1.0;
+            }
+            SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0);
+
+
+            rna0 = na0 / norm0;
+            rnb0 = nb0 / norm0;
+            ni1  = ni0 + m_orientation[v];
+            m_orientation[v] = ni1;
+            if ( (ni1 >> 1) != (ni0 >> 1) )
+            {
+                rna0 = Real(0.0);
+                rnb0 = Real(0.0);
+            }
+            m_normals[2*v]   = rna0;
+            m_normals[2*v+1] = rnb0;
+
+#ifdef DEBUG_VERBOSE1
+            printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
+            fprintf(g_fileDebugSC3DMCDec, "n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
+#endif //DEBUG_VERBOSE
+
+        }
+        return O3DGC_OK;
+    }
+    template<class T>
+    O3DGCErrorCode SC3DMCDecoder<T>::DecodeFloatArray(Real * const floatArray, 
+                                                   unsigned long numFloatArray,
+                                                   unsigned long dimFloatArray,
+                                                   unsigned long stride,
+                                                   const Real * const minFloatArray,
+                                                   const Real * const maxFloatArray,
+                                                   unsigned long nQBits,
+                                                   const IndexedFaceSet<T> & ifs,
+                                                   O3DGCSC3DMCPredictionMode & predMode,
+                                                   const BinaryStream & bstream)
+    {
+        assert(dimFloatArray <  O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+        long predResidual;
+        SC3DMCPredictor m_neighbors  [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
+        Arithmetic_Codec acd;
+        Static_Bit_Model bModel0;
+        Adaptive_Bit_Model bModel1;
+        Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
+        unsigned long nPred;
+
+        const AdjacencyInfo & v2T            = m_triangleListDecoder.GetVertexToTriangle();
+        const T * const     triangles        = ifs.GetCoordIndex();       
+        const long          nvert            = (long) numFloatArray;
+        const unsigned long size             = numFloatArray * dimFloatArray;
+        unsigned char *     buffer           = 0;
+        unsigned long       start            = m_iterator;
+        unsigned long       streamSize       = bstream.ReadUInt32(m_iterator, m_streamType);        // bitsream size
+        unsigned char mask                   = bstream.ReadUChar(m_iterator, m_streamType);
+        O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7);
+        predMode                             = (O3DGCSC3DMCPredictionMode)(mask & 7);
+        streamSize                          -= (m_iterator - start);
+        unsigned long       iteratorPred     = m_iterator + streamSize;
+        unsigned int        exp_k            = 0;
+        unsigned int        M                = 0;
+        if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
+        {
+            if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC)
+            {
+                return O3DGC_ERROR_CORRUPTED_STREAM;
+            }
+            bstream.GetBuffer(m_iterator, buffer);
+            m_iterator += streamSize;
+            acd.set_buffer(streamSize, buffer);
+            acd.start_decoder();
+            exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
+            M     = acd.ExpGolombDecode(0, bModel0, bModel1);
+        }
+        else
+        {
+            if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII)
+            {
+                return O3DGC_ERROR_CORRUPTED_STREAM;
+            }
+            bstream.ReadUInt32(iteratorPred, m_streamType);        // predictors bitsream size
+        }
+        Adaptive_Data_Model mModelValues(M+2);
+
+
+        if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
+        {
+            m_orientation.Allocate(size);
+            m_orientation.Clear();
+            if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+            {
+                for(unsigned long i = 0; i < numFloatArray; ++i)
+                {
+                    m_orientation.PushBack((unsigned char) bstream.ReadIntASCII(m_iterator));
+                }
+            }
+            else
+            {
+                Adaptive_Data_Model dModel(12);
+                for(unsigned long i = 0; i < numFloatArray; ++i)
+                {
+                    m_orientation.PushBack((unsigned char) UIntToInt(acd.decode(dModel)));
+                }
+            }
+            ProcessNormals(ifs);
+            dimFloatArray = 2;
+        }
+#ifdef DEBUG_VERBOSE
+        printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
+        fprintf(g_fileDebugSC3DMCDec, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
+#endif //DEBUG_VERBOSE
+
+        if (m_quantFloatArraySize < size)
+        {
+            delete [] m_quantFloatArray;
+            m_quantFloatArraySize = size;
+            m_quantFloatArray     = new long [size];
+        }
+        for (long v=0; v < nvert; ++v) 
+        {
+            nPred = 0;
+            if ( v2T.GetNumNeighbors(v) > 0 && 
+                 predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                int u0 = v2T.Begin(v);
+                int u1 = v2T.End(v);
+                for (long u = u0; u < u1; u++) 
+                {
+                    long ta = v2T.GetNeighbor(u);
+                    if (ta < 0)
+                    {
+                        break;
+                    }
+                    if (predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION)
+                    {
+                        long a,b;
+                        if ((long) triangles[ta*3] == v)
+                        {
+                            a = triangles[ta*3 + 1];
+                            b = triangles[ta*3 + 2];
+                        }
+                        else if ((long)triangles[ta*3 + 1] == v)
+                        {
+                            a = triangles[ta*3 + 0];
+                            b = triangles[ta*3 + 2];
+                        }
+                        else
+                        {
+                            a = triangles[ta*3 + 0];
+                            b = triangles[ta*3 + 1];
+                        }
+                        if ( a < v && b < v)
+                        {
+                            int u0 = v2T.Begin(a);
+                            int u1 = v2T.End(a);
+                            for (long u = u0; u < u1; u++) 
+                            {
+                                long tb = v2T.GetNeighbor(u);
+                                if (tb < 0)
+                                {
+                                    break;
+                                }
+                                long c = -1;
+                                bool foundB = false;
+                                for(long k = 0; k < 3; ++k)
+                                {
+                                    long x = triangles[tb*3 + k];
+                                    if (x == b)
+                                    {
+                                        foundB = true;
+                                    }
+                                    if (x < v && x != a && x != b)
+                                    {
+                                        c = x;
+                                    }
+                                }
+                                if (c != -1 && foundB)
+                                {
+                                    SC3DMCTriplet id = {min(a, b), max(a, b), -c-1};
+                                    unsigned long p = Insert(id, nPred, m_neighbors);
+                                    if (p != 0xFFFFFFFF)
+                                    {
+                                        for (unsigned long i = 0; i < dimFloatArray; i++) 
+                                        {
+                                            m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] + 
+                                                                       m_quantFloatArray[b*stride+i] - 
+                                                                       m_quantFloatArray[c*stride+i];
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION  ||
+                         predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ||
+                         predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION )
+                    {                
+                        for(long k = 0; k < 3; ++k)
+                        {
+                            long w = triangles[ta*3 + k];
+                            if ( w < v )
+                            {
+                                SC3DMCTriplet id = {-1, -1, w};
+                                unsigned long p = Insert(id, nPred, m_neighbors);
+                                if (p != 0xFFFFFFFF)
+                                {
+                                    for (unsigned long i = 0; i < dimFloatArray; i++) 
+                                    {
+                                        m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i];
+                                    } 
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (nPred > 1)
+            {
+#ifdef DEBUG_VERBOSE1
+                printf("\t\t vm %i\n", v);
+                fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v);
+                for (unsigned long p = 0; p < nPred; ++p)
+                {
+                    printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+                    fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+                    for (unsigned long i = 0; i < dimFloatArray; ++i) 
+                    {
+                        printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+                        fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+                    }
+                }
+#endif //DEBUG_VERBOSE
+                unsigned long bestPred;
+                if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                {
+                    bestPred = bstream.ReadUCharASCII(iteratorPred);
+                }
+                else
+                {
+                    bestPred = acd.decode(mModelPreds);
+                }
+#ifdef DEBUG_VERBOSE1
+                    printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+                    fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+#endif //DEBUG_VERBOSE
+                for (unsigned long i = 0; i < dimFloatArray; i++) 
+                {
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        predResidual = bstream.ReadIntASCII(m_iterator);
+                    }
+                    else
+                    {
+                        predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
+                    }
+                    m_quantFloatArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i];
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+                    fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+#endif //DEBUG_VERBOSE
+                }
+            }
+            else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                for (unsigned long i = 0; i < dimFloatArray; i++) 
+                {
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        predResidual = bstream.ReadIntASCII(m_iterator);
+                    }
+                    else
+                    {
+                        predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
+                    }
+                    m_quantFloatArray[v*stride+i] = predResidual + m_quantFloatArray[(v-1)*stride+i];
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", v*dimFloatArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+            else
+            {
+                for (unsigned long i = 0; i < dimFloatArray; i++) 
+                {
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        predResidual = bstream.ReadUIntASCII(m_iterator);
+                    }
+                    else
+                    {
+                        predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
+                    }
+                    m_quantFloatArray[v*stride+i] = predResidual;
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", v*dimFloatArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+        }
+        m_iterator  = iteratorPred;
+        if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
+        {
+            const Real minNormal[2] = {(Real)(-2),(Real)(-2)};
+            const Real maxNormal[2] = {(Real)(2),(Real)(2)};
+            Real na1, nb1;
+            Real na0, nb0;
+            char ni1;
+            IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minNormal, maxNormal, nQBits+1);
+            for (long v=0; v < nvert; ++v) 
+            {
+                na0 = m_normals[2*v];
+                nb0 = m_normals[2*v+1];
+                na1 = floatArray[stride*v]   + na0;
+                nb1 = floatArray[stride*v+1] + nb0;
+                ni1 = m_orientation[v];
+
+                CubeToSphere(na1, nb1, ni1,
+                             floatArray[stride*v], 
+                             floatArray[stride*v+1], 
+                             floatArray[stride*v+2]);
+
+#ifdef DEBUG_VERBOSE1
+                printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", 
+                                               v, 
+                                               floatArray[stride*v], 
+                                               floatArray[stride*v+1], 
+                                               floatArray[stride*v+2], 
+                                               ni1, na1, nb1,
+                                               na0, nb0);
+                fprintf(g_fileDebugSC3DMCDec, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", 
+                                               v, 
+                                               floatArray[stride*v], 
+                                               floatArray[stride*v+1], 
+                                               floatArray[stride*v+2], 
+                                               ni1, na1, nb1,
+                                               na0, nb0);
+#endif //DEBUG_VERBOSE
+            }
+        }
+        else
+        {
+            IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits);
+        }
+#ifdef DEBUG_VERBOSE
+        fflush(g_fileDebugSC3DMCDec);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+    template<class T>
+    O3DGCErrorCode SC3DMCDecoder<T>::IQuantizeFloatArray(Real * const floatArray, 
+                                                      unsigned long numFloatArray,
+                                                      unsigned long dimFloatArray,
+                                                      unsigned long stride,
+                                                      const Real * const minFloatArray,
+                                                      const Real * const maxFloatArray,
+                                                      unsigned long nQBits)
+    {
+        
+        Real idelta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
+        Real r;
+        for(unsigned long d = 0; d < dimFloatArray; d++)
+        {
+            r = maxFloatArray[d] - minFloatArray[d];
+            if (r > 0.0f)
+            {
+                idelta[d] = r/(float)((1 << nQBits) - 1);
+            }
+            else 
+            {
+                idelta[d] = 1.0f;
+            }
+        }        
+        for(unsigned long v = 0; v < numFloatArray; ++v)
+        {
+            for(unsigned long d = 0; d < dimFloatArray; ++d)
+            {
+//                floatArray[v * stride + d] = m_quantFloatArray[v * stride + d];
+                floatArray[v * stride + d] = m_quantFloatArray[v * stride + d] * idelta[d] + minFloatArray[d];
+            }
+        }
+        return O3DGC_OK;
+    }
+}
+#endif // O3DGC_SC3DMC_DECODER_INL
+
+

+ 140 - 0
contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h

@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_SC3DMC_ENCODE_PARAMS_H
+#define O3DGC_SC3DMC_ENCODE_PARAMS_H
+
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    class SC3DMCEncodeParams
+    {
+    public:
+        //! Constructor.
+                                    SC3DMCEncodeParams(void)
+                                    {
+                                        memset(this, 0, sizeof(SC3DMCEncodeParams));
+                                        m_encodeMode        = O3DGC_SC3DMC_ENCODE_MODE_TFAN;
+                                        m_streamTypeMode    = O3DGC_STREAM_TYPE_ASCII;
+                                        m_coordQuantBits    = 14;
+                                        m_normalQuantBits   = 8;
+                                        m_coordPredMode     = O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
+                                        m_normalPredMode    = O3DGC_SC3DMC_SURF_NORMALS_PREDICTION;
+                                        for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES; ++a)
+                                        {
+                                            m_floatAttributePredMode[a] = O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION;
+                                        }
+                                        for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES; ++a)
+                                        {
+                                            m_intAttributePredMode[a] = O3DGC_SC3DMC_NO_PREDICTION;
+                                        }
+                                    };
+        //! Destructor.
+                                    ~SC3DMCEncodeParams(void) {};
+
+        O3DGCStreamType             GetStreamType()    const { return m_streamTypeMode;}
+        O3DGCSC3DMCEncodingMode     GetEncodeMode()    const { return m_encodeMode;}
+
+        unsigned long               GetNumFloatAttributes() const { return m_numFloatAttributes;}
+        unsigned long               GetNumIntAttributes()   const { return m_numIntAttributes;}
+        unsigned long               GetCoordQuantBits()     const { return m_coordQuantBits;}
+        unsigned long               GetNormalQuantBits()    const { return m_normalQuantBits;}
+        unsigned long               GetFloatAttributeQuantBits(unsigned long a) const
+                                    {
+                                       assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                       return m_floatAttributeQuantBits[a];
+                                    }
+        O3DGCSC3DMCPredictionMode   GetCoordPredMode()    const { return m_coordPredMode; }
+        O3DGCSC3DMCPredictionMode   GetNormalPredMode()   const { return m_normalPredMode; }
+        O3DGCSC3DMCPredictionMode   GetFloatAttributePredMode(unsigned long a) const
+                                    {
+                                       assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                       return m_floatAttributePredMode[a];
+                                    }
+        O3DGCSC3DMCPredictionMode   GetIntAttributePredMode(unsigned long a) const
+                                    { 
+                                        assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                        return m_intAttributePredMode[a];
+                                    }
+        O3DGCSC3DMCPredictionMode & GetCoordPredMode()    { return m_coordPredMode; }
+        O3DGCSC3DMCPredictionMode & GetNormalPredMode()   { return m_normalPredMode; }
+        O3DGCSC3DMCPredictionMode & GetFloatAttributePredMode(unsigned long a)
+                                    {
+                                       assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                       return m_floatAttributePredMode[a];
+                                    }
+        O3DGCSC3DMCPredictionMode & GetIntAttributePredMode(unsigned long a)
+                                    {
+                                        assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                        return m_intAttributePredMode[a];
+                                    }
+        void                        SetStreamType(O3DGCStreamType streamTypeMode)  { m_streamTypeMode = streamTypeMode;}
+        void                        SetEncodeMode(O3DGCSC3DMCEncodingMode encodeMode)  { m_encodeMode = encodeMode;}
+        void                        SetNumFloatAttributes(unsigned long numFloatAttributes) 
+                                    { 
+                                        assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                        m_numFloatAttributes = numFloatAttributes;
+                                    }
+        void                        SetNumIntAttributes  (unsigned long numIntAttributes)
+                                    { 
+                                        assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                        m_numIntAttributes   = numIntAttributes;
+                                    }
+        void                        SetCoordQuantBits   (unsigned int coordQuantBits   ) { m_coordQuantBits    = coordQuantBits   ; }
+        void                        SetNormalQuantBits  (unsigned int normalQuantBits  ) { m_normalQuantBits   = normalQuantBits  ; }
+        void                        SetFloatAttributeQuantBits(unsigned long a, unsigned long q) 
+                                    { 
+                                       assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                       m_floatAttributeQuantBits[a] = q;
+                                    }
+        void                        SetCoordPredMode   (O3DGCSC3DMCPredictionMode coordPredMode   ) { m_coordPredMode    = coordPredMode   ; }
+        void                        SetNormalPredMode  (O3DGCSC3DMCPredictionMode normalPredMode  ) { m_normalPredMode   = normalPredMode  ; }
+        void                        SetFloatAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p) 
+                                    {
+                                       assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
+                                       m_floatAttributePredMode[a] = p;
+                                    }                       
+        void                        SetIntAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p) 
+                                    { 
+                                        assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
+                                        m_intAttributePredMode[a] = p;
+                                    }
+    private:
+        unsigned long               m_numFloatAttributes;
+        unsigned long               m_numIntAttributes;
+        unsigned long               m_coordQuantBits;
+        unsigned long               m_normalQuantBits;
+        unsigned long               m_floatAttributeQuantBits[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        
+        O3DGCSC3DMCPredictionMode   m_coordPredMode;
+        O3DGCSC3DMCPredictionMode   m_normalPredMode; 
+        O3DGCSC3DMCPredictionMode   m_floatAttributePredMode[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
+        O3DGCSC3DMCPredictionMode   m_intAttributePredMode  [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES];
+        O3DGCStreamType             m_streamTypeMode;
+        O3DGCSC3DMCEncodingMode     m_encodeMode;
+    };
+}
+#endif // O3DGC_SC3DMC_ENCODE_PARAMS_H
+

+ 116 - 0
contrib/Open3DGC/o3dgcSC3DMCEncoder.h

@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_SC3DMC_ENCODER_H
+#define O3DGC_SC3DMC_ENCODER_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcBinaryStream.h"
+#include "o3dgcIndexedFaceSet.h"
+#include "o3dgcSC3DMCEncodeParams.h"
+#include "o3dgcTriangleListEncoder.h"
+
+namespace o3dgc
+{    
+    //! 
+    template<class T>
+    class SC3DMCEncoder
+    {
+    public:    
+        //! Constructor.
+                                    SC3DMCEncoder(void)
+                                    {
+                                        m_posSize             = 0;
+                                        m_quantFloatArray     = 0;
+                                        m_quantFloatArraySize = 0;
+                                        m_sizeBufferAC        = 0;
+                                        m_bufferAC            = 0;
+                                        m_normals             = 0;
+                                        m_normalsSize         = 0;
+                                        m_streamType          = O3DGC_STREAM_TYPE_UNKOWN;
+                                    };
+        //! Destructor.
+                                    ~SC3DMCEncoder(void)
+                                    {
+                                        delete [] m_normals;
+                                        delete [] m_quantFloatArray;
+                                        delete [] m_bufferAC;
+                                    }
+        //! 
+        O3DGCErrorCode              Encode(const SC3DMCEncodeParams & params, 
+                                           const IndexedFaceSet<T> & ifs, 
+                                           BinaryStream & bstream);
+        const SC3DMCStats &         GetStats() const { return m_stats;}
+
+        private:
+        O3DGCErrorCode              EncodeHeader(const SC3DMCEncodeParams & params, 
+                                                 const IndexedFaceSet<T> & ifs, 
+                                                 BinaryStream & bstream);
+        O3DGCErrorCode              EncodePayload(const SC3DMCEncodeParams & params, 
+                                                  const IndexedFaceSet<T> & ifs, 
+                                                  BinaryStream & bstream);
+        O3DGCErrorCode              EncodeFloatArray(const Real * const floatArray, 
+                                                     unsigned long numfloatArray,
+                                                     unsigned long dimfloatArray,
+                                                     unsigned long stride,
+                                                     const Real * const minfloatArray,
+                                                     const Real * const maxfloatArray,
+                                                     unsigned long nQBits,
+                                                     const IndexedFaceSet<T> & ifs,
+                                                     O3DGCSC3DMCPredictionMode predMode,
+                                                     BinaryStream & bstream);
+        O3DGCErrorCode              QuantizeFloatArray(const Real * const floatArray, 
+                                                       unsigned long numFloatArray,
+                                                       unsigned long dimFloatArray,
+                                                       unsigned long stride,
+                                                       const Real * const minfloatArray,
+                                                       const Real * const maxfloatArray,
+                                                       unsigned long nQBits);
+        O3DGCErrorCode              EncodeIntArray(const long * const intArray, 
+                                                   unsigned long numIntArray,
+                                                   unsigned long dimIntArray,
+                                                   unsigned long stride,
+                                                   const IndexedFaceSet<T> & ifs,
+                                                   O3DGCSC3DMCPredictionMode predMode,
+                                                   BinaryStream & bstream);
+        O3DGCErrorCode              ProcessNormals(const IndexedFaceSet<T> & ifs);
+        TriangleListEncoder<T>      m_triangleListEncoder;
+        long *                      m_quantFloatArray;
+        unsigned long               m_posSize;
+        unsigned long               m_quantFloatArraySize;
+        unsigned char *             m_bufferAC;
+        unsigned long               m_sizeBufferAC;
+        SC3DMCPredictor             m_neighbors  [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
+        unsigned long               m_freqSymbols[O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS];
+        unsigned long               m_freqPreds  [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
+        Vector<long>                m_predictors;
+        Real *                      m_normals;
+        unsigned long               m_normalsSize;
+        SC3DMCStats                 m_stats;
+        O3DGCStreamType       m_streamType;
+    };
+}
+#include "o3dgcSC3DMCEncoder.inl"    // template implementation
+#endif // O3DGC_SC3DMC_ENCODER_H
+

+ 927 - 0
contrib/Open3DGC/o3dgcSC3DMCEncoder.inl

@@ -0,0 +1,927 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_SC3DMC_ENCODER_INL
+#define O3DGC_SC3DMC_ENCODER_INL
+
+
+#include "o3dgcArithmeticCodec.h"
+#include "o3dgcTimer.h"
+#include "o3dgcVector.h"
+#include "o3dgcBinaryStream.h"
+#include "o3dgcCommon.h"
+
+//#define DEBUG_VERBOSE
+
+namespace o3dgc
+{
+#ifdef DEBUG_VERBOSE
+        FILE * g_fileDebugSC3DMCEnc = NULL;
+#endif //DEBUG_VERBOSE
+
+    template <class T>
+    O3DGCErrorCode SC3DMCEncoder<T>::Encode(const SC3DMCEncodeParams & params, 
+                                            const IndexedFaceSet<T> & ifs, 
+                                            BinaryStream & bstream)
+    {
+        // Encode header
+        unsigned long start = bstream.GetSize();
+        EncodeHeader(params, ifs, bstream);
+        // Encode payload
+        EncodePayload(params, ifs, bstream);
+        bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType);
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode SC3DMCEncoder<T>::EncodeHeader(const SC3DMCEncodeParams & params, 
+                                               const IndexedFaceSet<T> & ifs, 
+                                               BinaryStream & bstream)
+    {
+        m_streamType = params.GetStreamType();
+        bstream.WriteUInt32(O3DGC_SC3DMC_START_CODE, m_streamType);
+        m_posSize = bstream.GetSize();
+        bstream.WriteUInt32(0, m_streamType); // to be filled later
+
+        bstream.WriteUChar(O3DGC_SC3DMC_ENCODE_MODE_TFAN, m_streamType);
+        bstream.WriteFloat32((float)ifs.GetCreaseAngle(), m_streamType);
+          
+        unsigned char mask = 0;
+        bool markerBit0 = false;
+        bool markerBit1 = false;
+        bool markerBit2 = false;
+        bool markerBit3 = false;
+
+        mask += (ifs.GetCCW()                  );
+        mask += (ifs.GetSolid()            << 1);
+        mask += (ifs.GetConvex()           << 2);
+        mask += (ifs.GetIsTriangularMesh() << 3);
+        mask += (markerBit0                << 4);
+        mask += (markerBit1                << 5);
+        mask += (markerBit2                << 6);
+        mask += (markerBit3                << 7);
+
+        bstream.WriteUChar(mask, m_streamType);
+
+        bstream.WriteUInt32(ifs.GetNCoord(), m_streamType);
+        bstream.WriteUInt32(ifs.GetNNormal(), m_streamType);
+        bstream.WriteUInt32(ifs.GetNumFloatAttributes(), m_streamType);
+        bstream.WriteUInt32(ifs.GetNumIntAttributes(), m_streamType);
+
+        if (ifs.GetNCoord() > 0)
+        {
+            bstream.WriteUInt32(ifs.GetNCoordIndex(), m_streamType);
+            for(int j=0 ; j<3 ; ++j)
+            {
+                bstream.WriteFloat32((float) ifs.GetCoordMin(j), m_streamType);
+                bstream.WriteFloat32((float) ifs.GetCoordMax(j), m_streamType);
+            }            
+            bstream.WriteUChar((unsigned char) params.GetCoordQuantBits(), m_streamType);
+        }
+        if (ifs.GetNNormal() > 0)
+        {
+            bstream.WriteUInt32(0, m_streamType);
+             for(int j=0 ; j<3 ; ++j)
+            {
+                bstream.WriteFloat32((float) ifs.GetNormalMin(j), m_streamType);
+                bstream.WriteFloat32((float) ifs.GetNormalMax(j), m_streamType);
+            }
+            bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetNormalPerVertex()
+            bstream.WriteUChar((unsigned char) params.GetNormalQuantBits(), m_streamType);
+        }
+        for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
+        {
+            bstream.WriteUInt32(ifs.GetNFloatAttribute(a), m_streamType);
+            if (ifs.GetNFloatAttribute(a) > 0)
+            {
+                assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8);
+                bstream.WriteUInt32(0, m_streamType);
+                unsigned char d = (unsigned char) ifs.GetFloatAttributeDim(a);
+                bstream.WriteUChar(d, m_streamType);
+                for(unsigned char j = 0 ; j < d ; ++j)
+                {
+                    bstream.WriteFloat32((float) ifs.GetFloatAttributeMin(a, j), m_streamType);
+                    bstream.WriteFloat32((float) ifs.GetFloatAttributeMax(a, j), m_streamType);
+                }
+                bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetFloatAttributePerVertex(a)
+                bstream.WriteUChar((unsigned char) ifs.GetFloatAttributeType(a), m_streamType);
+                bstream.WriteUChar((unsigned char) params.GetFloatAttributeQuantBits(a), m_streamType);
+            }
+        }
+        for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
+        {
+            bstream.WriteUInt32(ifs.GetNIntAttribute(a), m_streamType);
+            if (ifs.GetNIntAttribute(a) > 0)
+            {
+                assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8);
+                bstream.WriteUInt32(0, m_streamType);
+                bstream.WriteUChar((unsigned char) ifs.GetIntAttributeDim(a), m_streamType);
+                bstream.WriteUChar(true, m_streamType); // (unsigned char) ifs.GetIntAttributePerVertex(a)
+                bstream.WriteUChar((unsigned char) ifs.GetIntAttributeType(a), m_streamType);
+            }
+        }    
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode SC3DMCEncoder<T>::QuantizeFloatArray(const Real * const floatArray, 
+                                                   unsigned long numFloatArray,
+                                                   unsigned long dimFloatArray,
+                                                   unsigned long stride,
+                                                   const Real * const minFloatArray,
+                                                   const Real * const maxFloatArray,
+                                                   unsigned long nQBits)
+    {
+        const unsigned long size = numFloatArray * dimFloatArray;
+        Real delta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
+        Real r;
+        for(unsigned long d = 0; d < dimFloatArray; d++)
+        {
+            r = maxFloatArray[d] - minFloatArray[d];
+            if (r > 0.0f)
+            {
+                delta[d] = (float)((1 << nQBits) - 1) / r;
+            }
+            else
+            {
+                delta[d] = 1.0f;
+            }
+        }        
+        if (m_quantFloatArraySize < size)
+        {
+            delete [] m_quantFloatArray;
+            m_quantFloatArraySize = size;
+            m_quantFloatArray     = new long [size];
+        }                                  
+        for(unsigned long v = 0; v < numFloatArray; ++v)
+        {
+            for(unsigned long d = 0; d < dimFloatArray; ++d)
+            {
+                m_quantFloatArray[v * stride + d] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta[d] + 0.5f);
+            }
+        }
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode SC3DMCEncoder<T>::EncodeFloatArray(const Real * const floatArray, 
+                                                      unsigned long numFloatArray,
+                                                      unsigned long dimFloatArray,
+                                                      unsigned long stride,
+                                                      const Real * const minFloatArray,
+                                                      const Real * const maxFloatArray,
+                                                      unsigned long nQBits,
+                                                      const IndexedFaceSet<T> & ifs,
+                                                      O3DGCSC3DMCPredictionMode predMode,
+                                                      BinaryStream & bstream)
+    {
+        assert(dimFloatArray <  O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+        long predResidual, v, uPredResidual;
+        unsigned long nPred;
+        Arithmetic_Codec ace;
+        Static_Bit_Model bModel0;
+        Adaptive_Bit_Model bModel1;
+
+        const AdjacencyInfo & v2T         = m_triangleListEncoder.GetVertexToTriangle();
+        const long * const    vmap        = m_triangleListEncoder.GetVMap();
+        const long * const    invVMap     = m_triangleListEncoder.GetInvVMap();
+        const T * const       triangles   = ifs.GetCoordIndex();
+        const long            nvert       = (long) numFloatArray;
+        unsigned long         start       = bstream.GetSize();
+        unsigned char         mask        = predMode & 7;
+        const unsigned long   M           = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1;
+        unsigned long         nSymbols    = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS;
+        unsigned long         nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS;
+        
+
+        Adaptive_Data_Model mModelValues(M+2);
+        Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
+
+        memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS);
+        memset(m_freqPreds  , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS);
+        if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4;
+            m_predictors.Allocate(nvert);
+            m_predictors.Clear();
+        }
+        else
+        {
+            mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4;
+            const unsigned int NMAX = numFloatArray * dimFloatArray * 8 + 100;
+            if ( m_sizeBufferAC < NMAX )
+            {
+                delete [] m_bufferAC;
+                m_sizeBufferAC = NMAX;
+                m_bufferAC     = new unsigned char [m_sizeBufferAC];
+            }
+            ace.set_buffer(NMAX, m_bufferAC);
+            ace.start_encoder();
+            ace.ExpGolombEncode(0, 0, bModel0, bModel1);
+            ace.ExpGolombEncode(M, 0, bModel0, bModel1);
+        }
+        bstream.WriteUInt32(0, m_streamType);
+        bstream.WriteUChar(mask, m_streamType);
+
+#ifdef DEBUG_VERBOSE
+        printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
+        fprintf(g_fileDebugSC3DMCEnc, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
+#endif //DEBUG_VERBOSE
+
+        if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
+        {
+            const Real minFloatArray[2] = {(Real)(-2.0),(Real)(-2.0)};
+            const Real maxFloatArray[2] = {(Real)(2.0),(Real)(2.0)};
+            if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+            {
+                for(unsigned long i = 0; i < numFloatArray; ++i)
+                {
+                    bstream.WriteIntASCII(m_predictors[i]);
+                }
+            }
+            else
+            {
+                Adaptive_Data_Model dModel(12);
+                for(unsigned long i = 0; i < numFloatArray; ++i)
+                {
+                    ace.encode(IntToUInt(m_predictors[i]), dModel);
+                }
+            }
+            QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits+1);
+        }
+        else
+        {
+            QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits);
+        }
+
+        for (long vm=0; vm < nvert; ++vm) 
+        {
+            nPred = 0;
+            v     = invVMap[vm];
+            assert( v >= 0 && v < nvert);
+            if ( v2T.GetNumNeighbors(v) > 0 && 
+                 predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                int u0 = v2T.Begin(v);
+                int u1 = v2T.End(v);
+                for (long u = u0; u < u1; u++) 
+                {
+                    long ta = v2T.GetNeighbor(u);
+                    if ( predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION )
+                    {
+                        long a,b;
+                        if ((long) triangles[ta*3] == v)
+                        {
+                            a = triangles[ta*3 + 1];
+                            b = triangles[ta*3 + 2];
+                        }
+                        else if ((long) triangles[ta*3 + 1] == v)
+                        {
+                            a = triangles[ta*3 + 0];
+                            b = triangles[ta*3 + 2];
+                        }
+                        else
+                        {
+                            a = triangles[ta*3 + 0];
+                            b = triangles[ta*3 + 1];
+                        }
+                        if ( vmap[a] < vm && vmap[b] < vm)
+                        {
+                            int u0 = v2T.Begin(a);
+                            int u1 = v2T.End(a);
+                            for (long u = u0; u < u1; u++) 
+                            {
+                                long tb = v2T.GetNeighbor(u);
+                                long c = -1;
+                                bool foundB = false;
+                                for(long k = 0; k < 3; ++k)
+                                {
+                                    long x = triangles[tb*3 + k];
+                                    if (x == b)
+                                    {
+                                        foundB = true;
+                                    }
+                                    if (vmap[x] < vm && x != a && x != b)
+                                    {
+                                        c = x;
+                                    }
+                                }
+                                if (c != -1 && foundB)
+                                {
+                                    SC3DMCTriplet id = {min(vmap[a], vmap[b]), max(vmap[a], vmap[b]), -vmap[c]-1};
+                                    unsigned long p = Insert(id, nPred, m_neighbors);
+                                    if (p != 0xFFFFFFFF)
+                                    {
+                                        for (unsigned long i = 0; i < dimFloatArray; i++) 
+                                        {
+                                            m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] + 
+                                                                       m_quantFloatArray[b*stride+i] - 
+                                                                       m_quantFloatArray[c*stride+i];
+                                        } 
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION  ||
+                         predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ||
+                         predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION )
+                    {
+                        for(long k = 0; k < 3; ++k)
+                        {
+                            long w = triangles[ta*3 + k];
+                            if ( vmap[w] < vm )
+                            {
+                                SC3DMCTriplet id = {-1, -1, vmap[w]};
+                                unsigned long p = Insert(id, nPred, m_neighbors);
+                                if (p != 0xFFFFFFFF)
+                                {
+                                    for (unsigned long i = 0; i < dimFloatArray; i++) 
+                                    {
+                                        m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i];
+                                    } 
+                                }
+                            }
+                        }
+                    }        
+                }
+            }
+            if (nPred > 1)
+            {
+                // find best predictor
+                unsigned long bestPred = 0xFFFFFFFF;
+                double bestCost = O3DGC_MAX_DOUBLE;
+                double cost;
+#ifdef DEBUG_VERBOSE1
+                    printf("\t\t vm %i\n", vm);
+                    fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm);
+#endif //DEBUG_VERBOSE
+
+                for (unsigned long p = 0; p < nPred; ++p)
+                {
+#ifdef DEBUG_VERBOSE1
+                    printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+                    fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+#endif //DEBUG_VERBOSE
+                    cost = -log2((m_freqPreds[p]+1.0) / nPredictors );
+                    for (unsigned long i = 0; i < dimFloatArray; ++i) 
+                    {
+#ifdef DEBUG_VERBOSE1
+                        printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+                        fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+#endif //DEBUG_VERBOSE
+
+                        predResidual = (long) IntToUInt(m_quantFloatArray[v*stride+i] - m_neighbors[p].m_pred[i]);
+                        if (predResidual < (long) M) 
+                        {
+                            cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols );
+                        }
+                        else 
+                        {
+                            cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M));
+                        }
+                    }
+                    if (cost < bestCost)
+                    {
+                        bestCost = cost;
+                        bestPred = p;
+                    }
+                }
+                if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                {
+                    m_predictors.PushBack((unsigned char) bestPred);
+                }
+                else
+                {
+                    ace.encode(bestPred, mModelPreds);
+                }
+#ifdef DEBUG_VERBOSE1
+                    printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+                    fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+#endif //DEBUG_VERBOSE
+                // use best predictor
+                for (unsigned long i = 0; i < dimFloatArray; ++i) 
+                {
+                    predResidual  = m_quantFloatArray[v*stride+i] - m_neighbors[bestPred].m_pred[i];
+                    uPredResidual = IntToUInt(predResidual);
+                    ++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M];
+
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+                    fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+#endif //DEBUG_VERBOSE
+
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        bstream.WriteIntASCII(predResidual);
+                    }
+                    else
+                    {
+                        EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
+                    }
+                }
+                ++m_freqPreds[bestPred];
+                nSymbols += dimFloatArray;
+                ++nPredictors;
+            }
+            else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                long prev = invVMap[vm-1];
+                for (unsigned long i = 0; i < dimFloatArray; i++) 
+                {
+                    predResidual = m_quantFloatArray[v*stride+i] - m_quantFloatArray[prev*stride+i];
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        bstream.WriteIntASCII(predResidual);
+                    }
+                    else
+                    {
+                        EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
+                    }
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", vm*dimFloatArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+            else
+            {
+                for (unsigned long i = 0; i < dimFloatArray; i++) 
+                {
+                    predResidual = m_quantFloatArray[v*stride+i];
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        bstream.WriteUIntASCII(predResidual);
+                    }
+                    else
+                    {
+                        EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
+                    }
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", vm*dimFloatArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+        }
+        if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
+        {
+            unsigned long encodedBytes = ace.stop_encoder();
+            for(unsigned long i = 0; i < encodedBytes; ++i)
+            {
+                bstream.WriteUChar8Bin(m_bufferAC[i]);
+            }
+        }
+        bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
+
+        if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            unsigned long start = bstream.GetSize();
+            bstream.WriteUInt32ASCII(0);
+            const unsigned long size       = m_predictors.GetSize();
+            for(unsigned long i = 0; i < size; ++i)
+            {
+                bstream.WriteUCharASCII((unsigned char) m_predictors[i]);
+            }
+            bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
+        }
+#ifdef DEBUG_VERBOSE
+        fflush(g_fileDebugSC3DMCEnc);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+
+    template <class T>
+    O3DGCErrorCode SC3DMCEncoder<T>::EncodeIntArray(const long * const intArray, 
+                                                    unsigned long numIntArray,
+                                                    unsigned long dimIntArray,
+                                                    unsigned long stride,
+                                                    const IndexedFaceSet<T> & ifs,
+                                                    O3DGCSC3DMCPredictionMode predMode,
+                                                    BinaryStream & bstream)
+    {
+        assert(dimIntArray <  O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
+        long predResidual, v, uPredResidual;
+        unsigned long nPred;
+        Arithmetic_Codec ace;
+        Static_Bit_Model bModel0;
+        Adaptive_Bit_Model bModel1;
+
+        const AdjacencyInfo & v2T         = m_triangleListEncoder.GetVertexToTriangle();
+        const long * const    vmap        = m_triangleListEncoder.GetVMap();
+        const long * const    invVMap     = m_triangleListEncoder.GetInvVMap();
+        const T * const       triangles   = ifs.GetCoordIndex();
+        const long            nvert       = (long) numIntArray;
+        unsigned long         start       = bstream.GetSize();
+        unsigned char         mask        = predMode & 7;
+        const unsigned long   M           = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1;
+        unsigned long         nSymbols    = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS;
+        unsigned long         nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS;
+        
+
+        Adaptive_Data_Model mModelValues(M+2);
+        Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
+
+        memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS);
+        memset(m_freqPreds  , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS);
+        if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4;
+            m_predictors.Allocate(nvert);
+            m_predictors.Clear();
+        }
+        else
+        {
+            mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4;
+            const unsigned int NMAX = numIntArray * dimIntArray * 8 + 100;
+            if ( m_sizeBufferAC < NMAX )
+            {
+                delete [] m_bufferAC;
+                m_sizeBufferAC = NMAX;
+                m_bufferAC     = new unsigned char [m_sizeBufferAC];
+            }
+            ace.set_buffer(NMAX, m_bufferAC);
+            ace.start_encoder();
+            ace.ExpGolombEncode(0, 0, bModel0, bModel1);
+            ace.ExpGolombEncode(M, 0, bModel0, bModel1);
+        }
+        bstream.WriteUInt32(0, m_streamType);
+        bstream.WriteUChar(mask, m_streamType);
+
+#ifdef DEBUG_VERBOSE
+        printf("IntArray (%i, %i)\n", numIntArray, dimIntArray);
+        fprintf(g_fileDebugSC3DMCEnc, "IntArray (%i, %i)\n", numIntArray, dimIntArray);
+#endif //DEBUG_VERBOSE
+
+        for (long vm=0; vm < nvert; ++vm) 
+        {
+            nPred = 0;
+            v     = invVMap[vm];
+            assert( v >= 0 && v < nvert);
+            if ( v2T.GetNumNeighbors(v) > 0 && 
+                 predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                int u0 = v2T.Begin(v);
+                int u1 = v2T.End(v);
+                for (long u = u0; u < u1; u++) 
+                {
+                    long ta = v2T.GetNeighbor(u);
+                    for(long k = 0; k < 3; ++k)
+                    {
+                        long w = triangles[ta*3 + k];
+                        if ( vmap[w] < vm )
+                        {
+                            SC3DMCTriplet id = {-1, -1, vmap[w]};
+                            unsigned long p = Insert(id, nPred, m_neighbors);
+                            if (p != 0xFFFFFFFF)
+                            {
+                                for (unsigned long i = 0; i < dimIntArray; i++) 
+                                {
+                                    m_neighbors[p].m_pred[i] = intArray[w*stride+i];
+                                } 
+                            }
+                        }
+                    }
+                }
+            }
+            if (nPred > 1)
+            {
+                // find best predictor
+                unsigned long bestPred = 0xFFFFFFFF;
+                double bestCost = O3DGC_MAX_DOUBLE;
+                double cost;
+#ifdef DEBUG_VERBOSE1
+                    printf("\t\t vm %i\n", vm);
+                    fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm);
+#endif //DEBUG_VERBOSE
+
+                for (unsigned long p = 0; p < nPred; ++p)
+                {
+#ifdef DEBUG_VERBOSE1
+                    printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+                    fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
+#endif //DEBUG_VERBOSE
+                    cost = -log2((m_freqPreds[p]+1.0) / nPredictors );
+                    for (unsigned long i = 0; i < dimIntArray; ++i) 
+                    {
+#ifdef DEBUG_VERBOSE1
+                        printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+                        fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
+#endif //DEBUG_VERBOSE
+
+                        predResidual = (long) IntToUInt(intArray[v*stride+i] - m_neighbors[p].m_pred[i]);
+                        if (predResidual < (long) M) 
+                        {
+                            cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols );
+                        }
+                        else 
+                        {
+                            cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M));
+                        }
+                    }
+                    if (cost < bestCost)
+                    {
+                        bestCost = cost;
+                        bestPred = p;
+                    }
+                }
+                if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                {
+                    m_predictors.PushBack((unsigned char) bestPred);
+                }
+                else
+                {
+                    ace.encode(bestPred, mModelPreds);
+                }
+#ifdef DEBUG_VERBOSE1
+                    printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+                    fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
+#endif //DEBUG_VERBOSE
+                // use best predictor
+                for (unsigned long i = 0; i < dimIntArray; ++i) 
+                {
+                    predResidual  = intArray[v*stride+i] - m_neighbors[bestPred].m_pred[i];
+                    uPredResidual = IntToUInt(predResidual);
+                    ++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M];
+
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+                    fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
+#endif //DEBUG_VERBOSE
+
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        bstream.WriteIntASCII(predResidual);
+                    }
+                    else
+                    {
+                        EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
+                    }
+                }
+                ++m_freqPreds[bestPred];
+                nSymbols += dimIntArray;
+                ++nPredictors;
+            }
+            else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
+            {
+                long prev = invVMap[vm-1];
+                for (unsigned long i = 0; i < dimIntArray; i++) 
+                {
+                    predResidual = intArray[v*stride+i] - intArray[prev*stride+i];
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        bstream.WriteIntASCII(predResidual);
+                    }
+                    else
+                    {
+                        EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
+                    }
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", vm*dimIntArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+            else
+            {
+                for (unsigned long i = 0; i < dimIntArray; i++) 
+                {
+                    predResidual = intArray[v*stride+i];
+                    if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+                    {
+                        bstream.WriteUIntASCII(predResidual);
+                    }
+                    else
+                    {
+                        EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
+                    }
+#ifdef DEBUG_VERBOSE
+                    printf("%i \t %i\n", vm*dimIntArray+i, predResidual);
+                    fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual);
+#endif //DEBUG_VERBOSE
+                }
+            }
+        }
+        if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
+        {
+            unsigned long encodedBytes = ace.stop_encoder();
+            for(unsigned long i = 0; i < encodedBytes; ++i)
+            {
+                bstream.WriteUChar8Bin(m_bufferAC[i]);
+            }
+        }
+        bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
+
+        if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            unsigned long start = bstream.GetSize();
+            bstream.WriteUInt32ASCII(0);
+            const unsigned long size       = m_predictors.GetSize();
+            for(unsigned long i = 0; i < size; ++i)
+            {
+                bstream.WriteUCharASCII((unsigned char) m_predictors[i]);
+            }
+            bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
+        }
+#ifdef DEBUG_VERBOSE
+        fflush(g_fileDebugSC3DMCEnc);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode SC3DMCEncoder<T>::ProcessNormals(const IndexedFaceSet<T> & ifs)
+    {
+        const long nvert               = (long) ifs.GetNNormal();
+        const unsigned long normalSize = ifs.GetNNormal() * 2;
+        if (m_normalsSize < normalSize)
+        {
+            delete [] m_normals;
+            m_normalsSize = normalSize;
+            m_normals     = new Real [normalSize];
+        }                                  
+        const AdjacencyInfo & v2T          = m_triangleListEncoder.GetVertexToTriangle();
+        const long * const    invVMap      = m_triangleListEncoder.GetInvVMap();
+        const T * const       triangles    = ifs.GetCoordIndex();
+        const Real * const originalNormals = ifs.GetNormal();
+        Vec3<long> p1, p2, p3, n0, nt;
+        Vec3<Real> n1;
+        long na0, nb0;
+        Real rna0, rnb0, na1, nb1, norm0, norm1;
+        char ni0 = 0, ni1 = 0;
+        long a, b, c, v;
+        m_predictors.Clear();
+        for (long i=0; i < nvert; ++i) 
+        {
+            v = invVMap[i];
+            n0.X() = 0;
+            n0.Y() = 0;
+            n0.Z() = 0;
+            int u0 = v2T.Begin(v);
+            int u1 = v2T.End(v);
+            for (long u = u0; u < u1; u++) 
+            {
+                long ta = v2T.GetNeighbor(u);
+                a = triangles[ta*3 + 0];
+                b = triangles[ta*3 + 1];
+                c = triangles[ta*3 + 2];
+                p1.X() = m_quantFloatArray[3*a];
+                p1.Y() = m_quantFloatArray[3*a+1];
+                p1.Z() = m_quantFloatArray[3*a+2];
+                p2.X() = m_quantFloatArray[3*b];
+                p2.Y() = m_quantFloatArray[3*b+1];
+                p2.Z() = m_quantFloatArray[3*b+2];
+                p3.X() = m_quantFloatArray[3*c];
+                p3.Y() = m_quantFloatArray[3*c+1];
+                p3.Z() = m_quantFloatArray[3*c+2];
+                nt  = (p2-p1)^(p3-p1);
+                n0 += nt;
+            }
+            norm0 = (Real) n0.GetNorm();
+            if (norm0 == 0.0)
+            {
+                norm0 = 1.0;
+            }
+            SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0);
+            rna0 = na0 / norm0;
+            rnb0 = nb0 / norm0;
+
+            n1.X() = originalNormals[3*v];
+            n1.Y() = originalNormals[3*v+1];
+            n1.Z() = originalNormals[3*v+2];
+            norm1 = (Real) n1.GetNorm();
+            if (norm1 != 0.0)
+            {
+                n1.X() /= norm1;
+                n1.Y() /= norm1;
+                n1.Z() /= norm1;
+            }
+            SphereToCube(n1.X(), n1.Y(), n1.Z(), na1, nb1, ni1);
+            m_predictors.PushBack(ni1 - ni0);
+            if ( (ni1 >> 1) != (ni0 >> 1) )
+            {
+                rna0 = (Real)0.0;
+                rnb0 = (Real)0.0;
+            }
+            m_normals[2*v]   = na1 - rna0;
+            m_normals[2*v+1] = nb1 - rnb0;
+
+#ifdef DEBUG_VERBOSE1
+            printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
+            fprintf(g_fileDebugSC3DMCEnc,"n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
+#endif //DEBUG_VERBOSE
+
+#ifdef DEBUG_VERBOSE1
+            printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0);
+            fprintf(g_fileDebugSC3DMCEnc, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0);
+#endif //DEBUG_VERBOSE
+
+        }
+        return O3DGC_OK;
+    }
+
+    template <class T>
+    O3DGCErrorCode SC3DMCEncoder<T>::EncodePayload(const SC3DMCEncodeParams & params, 
+                                                   const IndexedFaceSet<T> & ifs, 
+                                                   BinaryStream & bstream)
+    {
+#ifdef DEBUG_VERBOSE
+        g_fileDebugSC3DMCEnc = fopen("tfans_enc_main.txt", "w");
+#endif //DEBUG_VERBOSE
+
+        // encode triangle list        
+        m_triangleListEncoder.SetStreamType(params.GetStreamType());
+        m_stats.m_streamSizeCoordIndex = bstream.GetSize();
+        Timer timer;
+        timer.Tic();
+        m_triangleListEncoder.Encode(ifs.GetCoordIndex(), ifs.GetIndexBufferID(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream);
+        timer.Toc();
+        m_stats.m_timeCoordIndex       = timer.GetElapsedTime();
+        m_stats.m_streamSizeCoordIndex = bstream.GetSize() - m_stats.m_streamSizeCoordIndex;
+
+        // encode coord
+        m_stats.m_streamSizeCoord = bstream.GetSize();
+        timer.Tic();
+        if (ifs.GetNCoord() > 0)
+        {
+            EncodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(), 
+                                params.GetCoordQuantBits(), ifs, params.GetCoordPredMode(), bstream);
+        }
+        timer.Toc();
+        m_stats.m_timeCoord       = timer.GetElapsedTime();
+        m_stats.m_streamSizeCoord = bstream.GetSize() - m_stats.m_streamSizeCoord;
+
+
+        // encode Normal
+        m_stats.m_streamSizeNormal = bstream.GetSize();
+        timer.Tic();
+        if (ifs.GetNNormal() > 0)
+        {
+            if (params.GetNormalPredMode() == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
+            {
+                ProcessNormals(ifs);
+                EncodeFloatArray(m_normals, ifs.GetNNormal(), 2, 2, ifs.GetNormalMin(), ifs.GetNormalMax(), 
+                params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream);
+            }
+            else
+            {
+                EncodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(), 
+                params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream);
+            }
+        }
+        timer.Toc();
+        m_stats.m_timeNormal       = timer.GetElapsedTime();
+        m_stats.m_streamSizeNormal = bstream.GetSize() - m_stats.m_streamSizeNormal;
+
+
+        // encode FloatAttribute
+        for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
+        {
+            m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize();
+            timer.Tic();
+            EncodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), 
+                             ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a),
+                             ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a), 
+                             params.GetFloatAttributeQuantBits(a), ifs, 
+                             params.GetFloatAttributePredMode(a), bstream);
+            timer.Toc();
+            m_stats.m_timeFloatAttribute[a]       = timer.GetElapsedTime();
+            m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeFloatAttribute[a];
+        }
+
+        // encode IntAttribute
+        for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
+        {
+            m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize();
+            timer.Tic();
+            EncodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), 
+                           ifs.GetIntAttributeDim(a), ifs, params.GetIntAttributePredMode(a), bstream);
+            timer.Toc();
+            m_stats.m_timeIntAttribute[a]       = timer.GetElapsedTime();
+            m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeIntAttribute[a];
+        }
+#ifdef DEBUG_VERBOSE
+        fclose(g_fileDebugSC3DMCEnc);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+}
+#endif // O3DGC_SC3DMC_ENCODER_INL
+
+

+ 134 - 0
contrib/Open3DGC/o3dgcTimer.h

@@ -0,0 +1,134 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_TIMER_H
+#define O3DGC_TIMER_H
+
+#include "o3dgcCommon.h"
+
+#ifdef WIN32
+/* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */
+#define NOMINMAX
+#include <windows.h>
+#elif __MACH__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#else
+#include <time.h>
+#include <sys/time.h>
+#endif
+
+
+
+namespace o3dgc
+{
+#ifdef WIN32
+    class Timer
+    {
+    public: 
+        Timer(void)
+        {
+            m_start.QuadPart = 0;
+            m_stop.QuadPart  = 0;
+            QueryPerformanceFrequency( &m_freq ) ;
+        };
+        ~Timer(void){};
+        void Tic() 
+        {
+            QueryPerformanceCounter(&m_start) ;
+        }
+        void Toc() 
+        {
+            QueryPerformanceCounter(&m_stop);
+        }
+        double GetElapsedTime() // in ms
+        {
+            LARGE_INTEGER delta;
+            delta.QuadPart = m_stop.QuadPart - m_start.QuadPart;
+            return (1000.0 * delta.QuadPart) / (double)m_freq.QuadPart;
+        }
+    private:
+        LARGE_INTEGER m_start;
+        LARGE_INTEGER m_stop;
+        LARGE_INTEGER m_freq;
+
+    };
+#elif __MACH__
+    class Timer
+    {
+    public: 
+        Timer(void)
+        {
+            memset(this, 0, sizeof(Timer));
+            host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, & m_cclock);
+        };
+        ~Timer(void)
+        {
+            mach_port_deallocate(mach_task_self(),  m_cclock);
+        };
+        void Tic() 
+        {
+            clock_get_time( m_cclock, &m_start);
+        }
+        void Toc() 
+        {
+            clock_get_time( m_cclock, &m_stop);
+        }
+        double GetElapsedTime() // in ms
+        {
+            return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec));
+        }
+    private:
+        clock_serv_t    m_cclock;
+        mach_timespec_t m_start;
+        mach_timespec_t m_stop;
+    };
+#else
+    class Timer
+    {
+    public: 
+        Timer(void)
+        {
+            memset(this, 0, sizeof(Timer));
+        };
+        ~Timer(void){};
+        void Tic() 
+        {
+            clock_gettime(CLOCK_REALTIME, &m_start);
+        }
+        void Toc() 
+        {
+            clock_gettime(CLOCK_REALTIME, &m_stop);
+        }
+        double GetElapsedTime() // in ms
+        {
+            return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec));
+        }
+    private:
+         struct timespec m_start;
+         struct timespec m_stop;
+    };
+#endif
+
+}
+#endif // O3DGC_TIMER_H

+ 22 - 0
contrib/Open3DGC/o3dgcTools.cpp

@@ -0,0 +1,22 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+

+ 475 - 0
contrib/Open3DGC/o3dgcTriangleFans.cpp

@@ -0,0 +1,475 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "o3dgcTriangleFans.h"
+#include "o3dgcArithmeticCodec.h"
+
+//#define DEBUG_VERBOSE
+
+namespace o3dgc
+{
+#ifdef DEBUG_VERBOSE
+        FILE* g_fileDebugTF = NULL;
+#endif //DEBUG_VERBOSE
+
+    O3DGCErrorCode    SaveUIntData(const Vector<long> & data,
+                                   BinaryStream & bstream) 
+    {
+        unsigned long start = bstream.GetSize();
+        bstream.WriteUInt32ASCII(0);
+        const unsigned long size       = data.GetSize();
+        bstream.WriteUInt32ASCII(size);
+        for(unsigned long i = 0; i < size; ++i)
+        {
+            bstream.WriteUIntASCII(data[i]);
+        }
+        bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    SaveIntData(const Vector<long> & data,
+                                  BinaryStream & bstream) 
+    {
+        unsigned long start = bstream.GetSize();
+        bstream.WriteUInt32ASCII(0);
+        const unsigned long size       = data.GetSize();
+        bstream.WriteUInt32ASCII(size);
+        for(unsigned long i = 0; i < size; ++i)
+        {
+            bstream.WriteIntASCII(data[i]);
+        }
+        bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    SaveBinData(const Vector<long> & data,
+                                  BinaryStream & bstream) 
+    {
+        unsigned long start = bstream.GetSize();
+        bstream.WriteUInt32ASCII(0);
+        const unsigned long size = data.GetSize();
+        long symbol;
+        bstream.WriteUInt32ASCII(size);
+        for(unsigned long i = 0; i < size; )
+        {
+            symbol = 0;
+            for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0 && i < size; ++h)
+            {
+                symbol += (data[i] << h);
+                ++i;
+            }
+            bstream.WriteUCharASCII((unsigned char) symbol);
+        }
+        bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    CompressedTriangleFans::SaveUIntAC(const Vector<long> & data,
+                                                         const unsigned long M,
+                                                         BinaryStream & bstream) 
+    {
+        unsigned long start = bstream.GetSize();     
+        const unsigned int NMAX = data.GetSize() * 8 + 100;
+        const unsigned long size       = data.GetSize();
+        long minValue = O3DGC_MAX_LONG;
+        bstream.WriteUInt32Bin(0);
+        bstream.WriteUInt32Bin(size);
+        if (size > 0)
+        {
+    #ifdef DEBUG_VERBOSE
+            printf("-----------\nsize %i, start %i\n", size, start);
+            fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start);
+    #endif //DEBUG_VERBOSE
+
+            for(unsigned long i = 0; i < size; ++i)
+            {
+                if (minValue > data[i]) 
+                {
+                    minValue = data[i];
+                }
+    #ifdef DEBUG_VERBOSE
+                printf("%i\t%i\n", i, data[i]);
+                fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
+    #endif //DEBUG_VERBOSE
+            }
+            bstream.WriteUInt32Bin(minValue);
+            if ( m_sizeBufferAC < NMAX )
+            {
+                delete [] m_bufferAC;
+                m_sizeBufferAC = NMAX;
+                m_bufferAC     = new unsigned char [m_sizeBufferAC];
+            }
+            Arithmetic_Codec ace;
+            ace.set_buffer(NMAX, m_bufferAC);
+            ace.start_encoder();
+            Adaptive_Data_Model mModelValues(M+1);
+            for(unsigned long i = 0; i < size; ++i)
+            {
+                ace.encode(data[i]-minValue, mModelValues);
+            }
+            unsigned long encodedBytes = ace.stop_encoder();
+            for(unsigned long i = 0; i < encodedBytes; ++i)
+            {
+                bstream.WriteUChar8Bin(m_bufferAC[i]);
+            }
+        }
+        bstream.WriteUInt32Bin(start, bstream.GetSize() - start);
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    CompressedTriangleFans::SaveBinAC(const Vector<long> & data,
+                                                         BinaryStream & bstream) 
+    {
+        unsigned long start = bstream.GetSize();     
+        const unsigned int NMAX = data.GetSize() * 8 + 100;
+        const unsigned long size       = data.GetSize();
+        bstream.WriteUInt32Bin(0);
+        bstream.WriteUInt32Bin(size);
+        if (size > 0)
+        {
+            if ( m_sizeBufferAC < NMAX )
+            {
+                delete [] m_bufferAC;
+                m_sizeBufferAC = NMAX;
+                m_bufferAC     = new unsigned char [m_sizeBufferAC];
+            }
+            Arithmetic_Codec ace;
+            ace.set_buffer(NMAX, m_bufferAC);
+            ace.start_encoder();
+            Adaptive_Bit_Model bModel;
+    #ifdef DEBUG_VERBOSE
+            printf("-----------\nsize %i, start %i\n", size, start);
+            fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start);
+    #endif //DEBUG_VERBOSE
+            for(unsigned long i = 0; i < size; ++i)
+            {
+                ace.encode(data[i], bModel);
+    #ifdef DEBUG_VERBOSE
+                printf("%i\t%i\n", i, data[i]);
+                fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
+    #endif //DEBUG_VERBOSE
+            }
+            unsigned long encodedBytes = ace.stop_encoder();
+            for(unsigned long i = 0; i < encodedBytes; ++i)
+            {
+                bstream.WriteUChar8Bin(m_bufferAC[i]);
+            }
+        }
+        bstream.WriteUInt32Bin(start, bstream.GetSize() - start);
+        return O3DGC_OK;
+    }
+
+    O3DGCErrorCode    CompressedTriangleFans::SaveIntACEGC(const Vector<long> & data,
+                                                            const unsigned long M,
+                                                            BinaryStream & bstream) 
+    {
+        unsigned long start = bstream.GetSize();
+        const unsigned int NMAX = data.GetSize() * 8 + 100;
+        const unsigned long size       = data.GetSize();
+        long minValue = 0;
+        bstream.WriteUInt32Bin(0);
+        bstream.WriteUInt32Bin(size);
+        if (size > 0)
+        {
+#ifdef DEBUG_VERBOSE
+            printf("-----------\nsize %i, start %i\n", size, start);
+            fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start);
+#endif //DEBUG_VERBOSE
+            for(unsigned long i = 0; i < size; ++i)
+            {
+                if (minValue > data[i]) 
+                {
+                    minValue = data[i];
+                }
+#ifdef DEBUG_VERBOSE
+                printf("%i\t%i\n", i, data[i]);
+                fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
+#endif //DEBUG_VERBOSE
+            }
+            bstream.WriteUInt32Bin(minValue + O3DGC_MAX_LONG);
+            if ( m_sizeBufferAC < NMAX )
+            {
+                delete [] m_bufferAC;
+                m_sizeBufferAC = NMAX;
+                m_bufferAC     = new unsigned char [m_sizeBufferAC];
+            }
+            Arithmetic_Codec ace;
+            ace.set_buffer(NMAX, m_bufferAC);
+            ace.start_encoder();
+            Adaptive_Data_Model mModelValues(M+2);
+            Static_Bit_Model bModel0;
+            Adaptive_Bit_Model bModel1;
+            unsigned long value;
+            for(unsigned long i = 0; i < size; ++i)
+            {
+                value = data[i]-minValue;
+                if (value < M) 
+                {
+                    ace.encode(value, mModelValues);
+                }
+                else 
+                {
+                    ace.encode(M, mModelValues);
+                    ace.ExpGolombEncode(value-M, 0, bModel0, bModel1);
+                }
+            }
+            unsigned long encodedBytes = ace.stop_encoder();
+            for(unsigned long i = 0; i < encodedBytes; ++i)
+            {
+                bstream.WriteUChar8Bin(m_bufferAC[i]);
+            }
+        }
+        bstream.WriteUInt32Bin(start, bstream.GetSize() - start);
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    CompressedTriangleFans::Save(BinaryStream & bstream, bool encodeTrianglesOrder, O3DGCStreamType streamType) 
+    {
+#ifdef DEBUG_VERBOSE
+        g_fileDebugTF = fopen("SaveIntACEGC_new.txt", "w");
+#endif //DEBUG_VERBOSE
+
+        if (streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            SaveUIntData(m_numTFANs  , bstream);
+            SaveUIntData(m_degrees   , bstream);
+            SaveUIntData(m_configs   , bstream);
+            SaveBinData (m_operations, bstream);
+            SaveIntData (m_indices   , bstream);
+            if (encodeTrianglesOrder)
+            {
+                SaveUIntData(m_trianglesOrder, bstream);
+            }
+        }
+        else
+        {
+            SaveIntACEGC(m_numTFANs  , 4 , bstream);
+            SaveIntACEGC(m_degrees   , 16, bstream);
+            SaveUIntAC  (m_configs   , 10, bstream);
+            SaveBinAC   (m_operations,     bstream);
+            SaveIntACEGC(m_indices   , 8 , bstream);
+            if (encodeTrianglesOrder)
+            {
+                SaveIntACEGC(m_trianglesOrder , 16, bstream);
+            }
+        }
+#ifdef DEBUG_VERBOSE
+        fclose(g_fileDebugTF);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    LoadUIntData(Vector<long> & data,
+                                  const BinaryStream & bstream,
+                                  unsigned long & iterator) 
+    {
+        bstream.ReadUInt32ASCII(iterator);
+        const unsigned long size = bstream.ReadUInt32ASCII(iterator);
+        data.Allocate(size);
+        data.Clear();
+        for(unsigned long i = 0; i < size; ++i)
+        {
+            data.PushBack(bstream.ReadUIntASCII(iterator));
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    LoadIntData(Vector<long> & data,
+                                  const BinaryStream & bstream,
+                                  unsigned long & iterator) 
+    {
+        bstream.ReadUInt32ASCII(iterator);
+        const unsigned long size = bstream.ReadUInt32ASCII(iterator);
+        data.Allocate(size);
+        data.Clear();
+        for(unsigned long i = 0; i < size; ++i)
+        {
+            data.PushBack(bstream.ReadIntASCII(iterator));
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    LoadBinData(Vector<long> & data,
+                                  const BinaryStream & bstream,
+                                  unsigned long & iterator) 
+    {
+        bstream.ReadUInt32ASCII(iterator);
+        const unsigned long size = bstream.ReadUInt32ASCII(iterator);
+        long symbol;
+        data.Allocate(size * O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0);
+        data.Clear();
+        for(unsigned long i = 0; i < size;)
+        {
+            symbol = bstream.ReadUCharASCII(iterator);
+            for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; ++h)
+            {
+                data.PushBack(symbol & 1);
+                symbol >>= 1;
+                ++i;
+            }
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    LoadUIntAC(Vector<long> & data,
+                                 const unsigned long M,
+                                 const BinaryStream & bstream,
+                                 unsigned long & iterator) 
+    {
+        unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12;
+        unsigned long size     = bstream.ReadUInt32Bin(iterator);
+        if (size == 0)
+        {
+            return O3DGC_OK;
+        }
+        long minValue   = bstream.ReadUInt32Bin(iterator);
+        unsigned char * buffer = 0;
+        bstream.GetBuffer(iterator, buffer);
+        iterator += sizeSize;
+        data.Allocate(size);
+        Arithmetic_Codec acd;
+        acd.set_buffer(sizeSize, buffer);
+        acd.start_decoder();
+        Adaptive_Data_Model mModelValues(M+1);
+#ifdef DEBUG_VERBOSE
+        printf("-----------\nsize %i\n", size);
+        fprintf(g_fileDebugTF, "size %i\n", size);
+#endif //DEBUG_VERBOSE
+        for(unsigned long i = 0; i < size; ++i)
+        {
+            data.PushBack(acd.decode(mModelValues)+minValue);
+#ifdef DEBUG_VERBOSE
+            printf("%i\t%i\n", i, data[i]);
+            fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
+#endif //DEBUG_VERBOSE
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    LoadIntACEGC(Vector<long> & data,
+                                   const unsigned long M,
+                                   const BinaryStream & bstream,
+                                   unsigned long & iterator) 
+    {
+        unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12;
+        unsigned long size     = bstream.ReadUInt32Bin(iterator);
+        if (size == 0)
+        {
+            return O3DGC_OK;
+        }
+        long minValue   = bstream.ReadUInt32Bin(iterator) - O3DGC_MAX_LONG;
+        unsigned char * buffer = 0;
+        bstream.GetBuffer(iterator, buffer);
+        iterator += sizeSize;
+        data.Allocate(size);
+        Arithmetic_Codec acd;
+        acd.set_buffer(sizeSize, buffer);
+        acd.start_decoder();
+        Adaptive_Data_Model mModelValues(M+2);
+        Static_Bit_Model bModel0;
+        Adaptive_Bit_Model bModel1;
+        unsigned long value;
+
+#ifdef DEBUG_VERBOSE
+        printf("-----------\nsize %i\n", size);
+        fprintf(g_fileDebugTF, "size %i\n", size);
+#endif //DEBUG_VERBOSE
+        for(unsigned long i = 0; i < size; ++i)
+        {
+            value = acd.decode(mModelValues);
+            if ( value == M)
+            {
+                value += acd.ExpGolombDecode(0, bModel0, bModel1);
+            }
+            data.PushBack(value + minValue);
+#ifdef DEBUG_VERBOSE
+            printf("%i\t%i\n", i, data[i]);
+            fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
+#endif //DEBUG_VERBOSE
+        }
+#ifdef DEBUG_VERBOSE
+        fflush(g_fileDebugTF);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    LoadBinAC(Vector<long> & data,
+                                const BinaryStream & bstream,
+                                unsigned long & iterator) 
+    {
+        unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 8;
+        unsigned long size     = bstream.ReadUInt32Bin(iterator);
+        if (size == 0)
+        {
+            return O3DGC_OK;
+        }
+        unsigned char * buffer = 0;
+        bstream.GetBuffer(iterator, buffer);
+        iterator += sizeSize;
+        data.Allocate(size);
+        Arithmetic_Codec acd;
+        acd.set_buffer(sizeSize, buffer);
+        acd.start_decoder();
+        Adaptive_Bit_Model bModel;
+#ifdef DEBUG_VERBOSE
+        printf("-----------\nsize %i\n", size);
+        fprintf(g_fileDebugTF, "size %i\n", size);
+#endif //DEBUG_VERBOSE
+        for(unsigned long i = 0; i < size; ++i)
+        {
+            data.PushBack(acd.decode(bModel));
+#ifdef DEBUG_VERBOSE
+            printf("%i\t%i\n", i, data[i]);
+            fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
+#endif //DEBUG_VERBOSE
+        }
+        return O3DGC_OK;
+    }
+    O3DGCErrorCode    CompressedTriangleFans::Load(const BinaryStream & bstream,
+                                                   unsigned long & iterator, 
+                                                   bool decodeTrianglesOrder,
+                                                   O3DGCStreamType streamType) 
+    {
+#ifdef DEBUG_VERBOSE
+        g_fileDebugTF = fopen("Load_new.txt", "w");
+#endif //DEBUG_VERBOSE
+        if (streamType == O3DGC_STREAM_TYPE_ASCII)
+        {
+            LoadUIntData(m_numTFANs  , bstream, iterator);
+            LoadUIntData(m_degrees   , bstream, iterator);
+            LoadUIntData(m_configs   , bstream, iterator);
+            LoadBinData (m_operations, bstream, iterator);
+            LoadIntData (m_indices   , bstream, iterator);
+            if (decodeTrianglesOrder)
+            {
+                LoadUIntData(m_trianglesOrder , bstream, iterator);
+            }
+        }
+        else
+        {
+            LoadIntACEGC(m_numTFANs  , 4 , bstream, iterator);
+            LoadIntACEGC(m_degrees   , 16, bstream, iterator);
+            LoadUIntAC  (m_configs   , 10, bstream, iterator);
+            LoadBinAC   (m_operations,     bstream, iterator);
+            LoadIntACEGC(m_indices   , 8 , bstream, iterator);
+            if (decodeTrianglesOrder)
+            {
+                LoadIntACEGC(m_trianglesOrder , 16, bstream, iterator);
+            }
+        }
+
+#ifdef DEBUG_VERBOSE
+        fclose(g_fileDebugTF);
+#endif //DEBUG_VERBOSE
+        return O3DGC_OK;
+    }
+}
+

+ 291 - 0
contrib/Open3DGC/o3dgcTriangleFans.h

@@ -0,0 +1,291 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_TRIANGLE_FANS_H
+#define O3DGC_TRIANGLE_FANS_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcVector.h"
+#include "o3dgcBinaryStream.h"
+
+
+namespace o3dgc
+{
+    const long O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER = 128;
+    const long O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER          = 8;
+
+    class CompressedTriangleFans
+    {
+    public:    
+        //! Constructor.
+                                    CompressedTriangleFans(void)
+                                    {
+                                        m_streamType   = O3DGC_STREAM_TYPE_UNKOWN;
+                                        m_bufferAC     = 0;
+                                        m_sizeBufferAC = 0;
+                                    };
+        //! Destructor.
+                                    ~CompressedTriangleFans(void) 
+                                    {
+                                        delete [] m_bufferAC;
+                                    };
+        O3DGCStreamType       GetStreamType() const { return m_streamType; }
+        void                        SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
+
+        O3DGCErrorCode              Allocate(long numVertices, long numTriangles)
+                                    {
+                                        assert(numVertices > 0);
+                                        m_numTFANs.Allocate(numVertices);
+                                        m_degrees.Allocate(2*numVertices);
+                                        m_configs.Allocate(2*numVertices);
+                                        m_operations.Allocate(2*numVertices);
+                                        m_indices.Allocate(2*numVertices);
+                                        m_trianglesOrder.Allocate(numTriangles);
+                                        Clear();
+                                        return O3DGC_OK;
+                                    }
+        O3DGCErrorCode              PushNumTFans(long numTFans)
+                                    {
+                                         m_numTFANs.PushBack(numTFans);
+                                        return O3DGC_OK;
+                                    }
+        long                        ReadNumTFans(unsigned long & iterator) const
+                                    {
+                                        assert(iterator < m_numTFANs.GetSize());
+                                        return m_numTFANs[iterator++];
+                                    }
+        O3DGCErrorCode              PushDegree(long degree)
+                                    {
+                                        m_degrees.PushBack(degree);
+                                        return O3DGC_OK;
+                                    }
+        long                        ReadDegree(unsigned long & iterator) const
+                                    {
+                                        assert(iterator < m_degrees.GetSize());
+                                        return m_degrees[iterator++];
+                                    }
+        O3DGCErrorCode              PushConfig(long config)
+                                    {
+                                        m_configs.PushBack(config);
+                                        return O3DGC_OK;
+                                    }
+        long                        ReadConfig(unsigned long & iterator) const
+                                    {
+                                        assert(iterator < m_configs.GetSize());
+                                        return m_configs[iterator++];
+                                    }
+        O3DGCErrorCode              PushOperation(long op)
+                                    {
+                                        m_operations.PushBack(op);
+                                        return O3DGC_OK;
+                                    }
+        long                        ReadOperation(unsigned long & iterator) const
+                                    {
+                                        assert(iterator < m_operations.GetSize());
+                                        return m_operations[iterator++];
+                                    }
+        O3DGCErrorCode              PushIndex(long index)
+                                    {
+                                        m_indices.PushBack(index);
+                                        return O3DGC_OK;
+                                    }
+        long                        ReadIndex(unsigned long & iterator) const
+                                    {
+                                        assert(iterator < m_indices.GetSize());
+                                        return m_indices[iterator++];
+                                    }
+        O3DGCErrorCode              PushTriangleIndex(long index)
+                                    {
+                                        m_trianglesOrder.PushBack(IntToUInt(index));
+                                        return O3DGC_OK;
+                                    }
+        long                        ReadTriangleIndex(unsigned long & iterator) const
+                                    {
+                                        assert(iterator < m_trianglesOrder.GetSize());
+                                        return UIntToInt(m_trianglesOrder[iterator++]);
+                                    }
+        O3DGCErrorCode              Clear()
+                                    {
+                                        m_numTFANs.Clear();
+                                        m_degrees.Clear();
+                                        m_configs.Clear();
+                                        m_operations.Clear();
+                                        m_indices.Clear();
+                                        return O3DGC_OK;
+                                    }
+        O3DGCErrorCode              Save(BinaryStream & bstream,
+                                         bool encodeTrianglesOrder,
+                                         O3DGCStreamType streamType);
+        O3DGCErrorCode              Load(const BinaryStream & bstream, 
+                                         unsigned long & iterator, 
+                                         bool decodeTrianglesOrder,
+                                         O3DGCStreamType streamType);
+
+    private:
+        O3DGCErrorCode              SaveBinAC(const Vector<long> & data,
+                                            BinaryStream & bstream);
+        O3DGCErrorCode              SaveUIntAC(const Vector<long> & data,
+                                             const unsigned long M,
+                                               BinaryStream & bstream);
+        O3DGCErrorCode              SaveIntACEGC(const Vector<long> & data,
+                                                 const unsigned long M,
+                                                 BinaryStream & bstream);
+
+        Vector<long>                m_numTFANs;
+        Vector<long>                m_degrees;
+        Vector<long>                m_configs;
+        Vector<long>                m_operations;
+        Vector<long>                m_indices;
+        Vector<long>                m_trianglesOrder;
+        unsigned char *             m_bufferAC;
+        unsigned long               m_sizeBufferAC;
+        O3DGCStreamType       m_streamType;
+    };
+
+    //! 
+    class TriangleFans
+    {
+    public:    
+        //! Constructor.
+                                    TriangleFans(long sizeTFAN     = O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER, 
+                                                 long verticesSize = O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER)
+                                    {
+                                        assert(sizeTFAN     > 0);
+                                        assert(verticesSize > 0);
+                                        m_numTFANs              = 0;
+                                        m_numVertices           = 0;
+                                        m_verticesAllocatedSize = verticesSize;
+                                        m_sizeTFANAllocatedSize = sizeTFAN;
+                                        m_sizeTFAN              = new long [m_sizeTFANAllocatedSize];
+                                        m_vertices              = new long [m_verticesAllocatedSize];
+                                    };
+        //! Destructor.
+                                    ~TriangleFans(void)
+                                    {
+                                        delete [] m_vertices;
+                                        delete [] m_sizeTFAN;
+                                    };
+
+        O3DGCErrorCode                Allocate(long sizeTFAN, long verticesSize)
+                                    {
+                                        assert(sizeTFAN     > 0);
+                                        assert(verticesSize > 0);
+                                        m_numTFANs    = 0;
+                                        m_numVertices = 0;
+                                        if (m_verticesAllocatedSize < verticesSize)
+                                        {
+                                            delete [] m_vertices;
+                                            m_verticesAllocatedSize = verticesSize;
+                                            m_vertices              = new long [m_verticesAllocatedSize];
+                                        }
+                                        if (m_sizeTFANAllocatedSize < sizeTFAN)
+                                        {
+                                            delete [] m_sizeTFAN;
+                                            m_sizeTFANAllocatedSize = sizeTFAN;
+                                            m_sizeTFAN              = new long [m_sizeTFANAllocatedSize];
+                                        }
+                                        return O3DGC_OK;
+                                    };
+        O3DGCErrorCode                Clear()
+                                    {
+                                        m_numTFANs    = 0;
+                                        m_numVertices = 0;
+                                        return O3DGC_OK;
+                                    }
+        O3DGCErrorCode                AddVertex(long vertex) 
+                                    {
+                                        assert(m_numTFANs    >= 0);
+                                        assert(m_numTFANs    <  m_sizeTFANAllocatedSize);
+                                        assert(m_numVertices >= 0);
+                                        ++m_numVertices;
+                                        if (m_numVertices == m_verticesAllocatedSize)
+                                        {
+                                            m_verticesAllocatedSize *= 2;
+                                            long * tmp = m_vertices;
+                                            m_vertices = new long [m_verticesAllocatedSize];
+                                            memcpy(m_vertices, tmp, sizeof(long) * m_numVertices);
+                                            delete [] tmp;
+                                        }
+                                        m_vertices[m_numVertices-1] = vertex;
+                                        ++m_sizeTFAN[m_numTFANs-1];
+                                        return O3DGC_OK;
+                                    }
+        O3DGCErrorCode                AddTFAN()
+                                    {
+                                        assert(m_numTFANs >= 0);
+                                        ++m_numTFANs;
+                                        if (m_numTFANs == m_sizeTFANAllocatedSize)
+                                        {
+                                            m_sizeTFANAllocatedSize *= 2;
+                                            long * tmp = m_sizeTFAN;
+                                            m_sizeTFAN = new long [m_sizeTFANAllocatedSize];
+                                            memcpy(m_sizeTFAN, tmp, sizeof(long) * m_numTFANs);
+                                            delete [] tmp;
+                                        }
+                                        m_sizeTFAN[m_numTFANs-1] = (m_numTFANs > 1) ? m_sizeTFAN[m_numTFANs-2] : 0;
+                                        return O3DGC_OK;
+                                    }
+        long                        Begin(long tfan) const 
+                                    {
+                                        assert(tfan < m_numTFANs);
+                                        assert(tfan >= 0);
+                                        return (tfan>0)?m_sizeTFAN[tfan-1]:0;
+                                    }
+        long                        End(long tfan) const
+                                    {
+                                        assert(tfan < m_numTFANs);
+                                        assert(tfan >= 0);
+                                        return m_sizeTFAN[tfan];
+                                    }
+        long                        GetVertex(long vertex) const
+                                    {
+                                        assert(vertex < m_numVertices);
+                                        assert(vertex >= 0);
+                                        return m_vertices[vertex];
+                                    }
+        long                        GetTFANSize(long tfan)  const 
+                                    { 
+                                        return End(tfan) - Begin(tfan);
+                                    }
+        long                        GetNumTFANs()  const 
+                                    { 
+                                        return m_numTFANs;
+                                    }
+        long                        GetNumVertices()  const 
+                                    { 
+                                        return m_numVertices;
+                                    }
+
+    private:
+        long                        m_verticesAllocatedSize;
+        long                        m_sizeTFANAllocatedSize;
+        long                        m_numTFANs;
+        long                        m_numVertices;
+        long *                      m_vertices;
+        long *                      m_sizeTFAN;
+    
+    };
+}
+#endif // O3DGC_TRIANGLE_FANS_H
+

+ 133 - 0
contrib/Open3DGC/o3dgcTriangleListDecoder.h

@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_TRIANGLE_LIST_DECODER_H
+#define O3DGC_TRIANGLE_LIST_DECODER_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcTriangleFans.h"
+#include "o3dgcBinaryStream.h"
+#include "o3dgcAdjacencyInfo.h"
+
+namespace o3dgc
+{
+    
+    //! 
+    template <class T>
+    class TriangleListDecoder
+    {
+    public:    
+        //! Constructor.
+                                    TriangleListDecoder(void)
+                                    {
+                                        m_vertexCount            = 0;
+                                        m_triangleCount          = 0;
+                                        m_numTriangles           = 0;
+                                        m_numVertices            = 0;
+                                        m_triangles              = 0;
+                                        m_numConqueredTriangles  = 0;
+                                        m_numVisitedVertices     = 0;
+                                        m_visitedVertices        = 0;
+                                        m_visitedVerticesValence = 0;
+                                        m_maxNumVertices         = 0;
+                                        m_maxNumTriangles        = 0;
+                                        m_itNumTFans             = 0;
+                                        m_itDegree               = 0;
+                                        m_itConfig               = 0;
+                                        m_itOperation            = 0;
+                                        m_itIndex                = 0;
+                                        m_tempTriangles          = 0;
+                                        m_tempTrianglesSize      = 0;
+                                        m_decodeTrianglesOrder   = false;
+                                        m_decodeVerticesOrder    = false;
+                                    };
+        //! Destructor.
+                                    ~TriangleListDecoder(void)
+                                    {
+                                        delete [] m_tempTriangles;
+                                    };
+
+        O3DGCStreamType       GetStreamType()       const { return m_streamType; }
+        bool                        GetReorderTriangles() const { return m_decodeTrianglesOrder; }        
+        bool                        GetReorderVertices()  const { return m_decodeVerticesOrder; }        
+        void                        SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
+        const AdjacencyInfo &       GetVertexToTriangle() const { return m_vertexToTriangle;}
+        O3DGCErrorCode              Decode(T * const triangles,
+                                           const long numTriangles,
+                                           const long numVertices,
+                                           const BinaryStream & bstream,
+                                           unsigned long & iterator)
+                                    {
+                                        unsigned char compressionMask = bstream.ReadUChar(iterator, m_streamType); 
+                                        m_decodeTrianglesOrder = ( (compressionMask&2) != 0);
+                                        m_decodeVerticesOrder = ( (compressionMask&1) != 0); 
+                                        if (m_decodeVerticesOrder)  // vertices reordering not supported
+                                        {
+                                            return O3DGC_ERROR_NON_SUPPORTED_FEATURE;
+                                        }
+                                        unsigned long maxSizeV2T = bstream.ReadUInt32(iterator, m_streamType);
+                                        Init(triangles, numTriangles, numVertices, maxSizeV2T);
+                                        m_ctfans.Load(bstream, iterator, m_decodeTrianglesOrder, m_streamType);
+                                        Decompress();
+                                        return O3DGC_OK;
+                                    }
+        O3DGCErrorCode              Reorder();
+
+        private:
+        O3DGCErrorCode              Init(T * const triangles, 
+                                         const long numTriangles,
+                                         const long numVertices,
+                                         const long maxSizeV2T);
+        O3DGCErrorCode              Decompress();
+        O3DGCErrorCode              CompueLocalConnectivityInfo(const long focusVertex);
+        O3DGCErrorCode              DecompressTFAN(const long focusVertex);
+
+        unsigned long               m_itNumTFans;
+        unsigned long               m_itDegree;
+        unsigned long               m_itConfig;
+        unsigned long               m_itOperation;
+        unsigned long               m_itIndex;
+        long                        m_maxNumVertices;
+        long                        m_maxNumTriangles;
+        long                        m_numTriangles;
+        long                        m_numVertices;
+        long                        m_tempTrianglesSize;
+        T *                         m_triangles;
+        T *                         m_tempTriangles;
+        long                        m_vertexCount;
+        long                        m_triangleCount;
+        long                        m_numConqueredTriangles;
+        long                        m_numVisitedVertices;
+        long *                      m_visitedVertices;
+        long *                      m_visitedVerticesValence;
+        AdjacencyInfo               m_vertexToTriangle;
+        CompressedTriangleFans      m_ctfans;
+        TriangleFans                m_tfans;
+        O3DGCStreamType       m_streamType;
+        bool                        m_decodeTrianglesOrder;
+        bool                        m_decodeVerticesOrder;
+    };
+}
+#include "o3dgcTriangleListDecoder.inl"    // template implementation
+#endif // O3DGC_TRIANGLE_LIST_DECODER_H
+

+ 364 - 0
contrib/Open3DGC/o3dgcTriangleListDecoder.inl

@@ -0,0 +1,364 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_TRIANGLE_LIST_DECODER_INL
+#define O3DGC_TRIANGLE_LIST_DECODER_INL
+
+namespace o3dgc
+{
+    template<class T>
+    O3DGCErrorCode TriangleListDecoder<T>::Init(T * const  triangles,
+                                                const long numTriangles,
+                                                const long numVertices,
+                                                const long maxSizeV2T)
+    {
+        assert(numVertices  > 0);
+        assert(numTriangles > 0);
+        m_numTriangles      = numTriangles;
+        m_numVertices       = numVertices;
+        m_triangles         = triangles;
+        m_vertexCount       = 0;
+        m_triangleCount     = 0;
+        m_itNumTFans        = 0;
+        m_itDegree          = 0;
+        m_itConfig          = 0;
+        m_itOperation       = 0;
+        m_itIndex           = 0;        
+        if  (m_numVertices > m_maxNumVertices)
+        {
+            m_maxNumVertices         = m_numVertices;
+            delete [] m_visitedVerticesValence;
+            delete [] m_visitedVertices;
+            m_visitedVerticesValence = new long [m_numVertices];
+            m_visitedVertices        = new long [m_numVertices];
+        }
+        
+        if (m_decodeTrianglesOrder && m_tempTrianglesSize < m_numTriangles)
+        {
+            delete [] m_tempTriangles;
+            m_tempTrianglesSize      = m_numTriangles;
+            m_tempTriangles          = new T [3*m_tempTrianglesSize];
+        }
+
+        m_ctfans.SetStreamType(m_streamType);
+        m_ctfans.Allocate(m_numVertices, m_numTriangles);
+        m_tfans.Allocate(2 * m_numVertices, 8 * m_numVertices);
+
+         // compute vertex-to-triangle adjacency information
+        m_vertexToTriangle.AllocateNumNeighborsArray(numVertices);
+        long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer();
+        for(long i = 0; i < numVertices; ++i)
+        {
+            numNeighbors[i] = maxSizeV2T;
+        }
+        m_vertexToTriangle.AllocateNeighborsArray();
+        m_vertexToTriangle.ClearNeighborsArray();
+        return O3DGC_OK;
+    }
+    template<class T>
+    O3DGCErrorCode TriangleListDecoder<T>::Decompress()
+    {
+        for(long focusVertex = 0; focusVertex < m_numVertices; ++focusVertex)
+        {
+            if (focusVertex == m_vertexCount)
+            {
+                m_vertexCount++; // insert focusVertex
+            }
+            CompueLocalConnectivityInfo(focusVertex);
+            DecompressTFAN(focusVertex);
+        }
+        return O3DGC_OK;
+    }
+    template<class T>
+    O3DGCErrorCode TriangleListDecoder<T>::Reorder()
+    {
+        if (m_decodeTrianglesOrder)
+        {
+            unsigned long itTriangleIndex = 0;
+            long prevTriangleIndex = 0;
+            long t;
+            memcpy(m_tempTriangles, m_triangles, m_numTriangles * 3 * sizeof(T));
+            for(long i = 0; i < m_numTriangles; ++i)
+            {
+                t  = m_ctfans.ReadTriangleIndex(itTriangleIndex) + prevTriangleIndex;
+                assert( t >= 0 && t < m_numTriangles);
+                memcpy(m_triangles + 3 * t, m_tempTriangles + 3 * i, sizeof(T) * 3);
+                prevTriangleIndex = t + 1;
+            }
+        }
+        return O3DGC_OK;
+    }
+    template<class T>
+    O3DGCErrorCode TriangleListDecoder<T>::CompueLocalConnectivityInfo(const long focusVertex)
+    {
+        long t = 0;
+        long p, v;
+        m_numConqueredTriangles    = 0;
+        m_numVisitedVertices       = 0;
+        for(long i = m_vertexToTriangle.Begin(focusVertex); (t >= 0) && (i < m_vertexToTriangle.End(focusVertex)); ++i)
+        {
+            t = m_vertexToTriangle.GetNeighbor(i);
+            if ( t >= 0)
+            {
+                ++m_numConqueredTriangles;
+                p = 3*t;
+                // extract visited vertices
+                for(long k = 0; k < 3; ++k)
+                {
+                    v = m_triangles[p+k];
+                    if (v > focusVertex) // vertices are insertices by increasing traversal order
+                    {
+                        bool foundOrInserted = false;
+                        for (long j = 0; j < m_numVisitedVertices; ++j)
+                        {
+                            if (v == m_visitedVertices[j])
+                            {
+                                m_visitedVerticesValence[j]++;
+                                foundOrInserted = true;
+                                break;
+                            }
+                            else if (v < m_visitedVertices[j])
+                            {
+                                ++m_numVisitedVertices;
+                                for (long h = m_numVisitedVertices-1; h > j; --h)
+                                {
+                                    m_visitedVertices[h]        = m_visitedVertices[h-1];
+                                    m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1];
+                                }
+                                m_visitedVertices[j]        = v;
+                                m_visitedVerticesValence[j] = 1;
+                                foundOrInserted = true;
+                                break;
+                            }
+                        }
+                        if (!foundOrInserted)
+                        {
+                            m_visitedVertices[m_numVisitedVertices]        = v;
+                            m_visitedVerticesValence[m_numVisitedVertices] = 1;
+                            m_numVisitedVertices++;
+                        }
+                    }
+                }
+            }
+        }
+        // re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex)
+        // in order to avoid config. 9
+        if (m_numVisitedVertices > 2)
+        {
+            long y;
+            for(long x = 1; x < m_numVisitedVertices; ++x)
+            {
+
+                if (m_visitedVerticesValence[x] == 1)
+                {
+                    y = x;
+                    while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) )
+                    {
+                        swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]);
+                        swap(m_visitedVertices[y], m_visitedVertices[y-1]);
+                        --y;
+                    }
+                }
+            }
+        }
+        return O3DGC_OK;
+    }
+    template<class T>
+    O3DGCErrorCode TriangleListDecoder<T>::DecompressTFAN(const long focusVertex)
+    {
+        long ntfans; 
+        long degree, config;
+        long op;
+        long index;
+        long k0, k1;
+        long b, c, t;
+
+        ntfans = m_ctfans.ReadNumTFans(m_itNumTFans);
+        if (ntfans > 0) 
+        {
+            for(long f = 0; f != ntfans; f++) 
+            {
+                m_tfans.AddTFAN();
+                degree     = m_ctfans.ReadDegree(m_itDegree) +2 - m_numConqueredTriangles;
+                config     = m_ctfans.ReadConfig(m_itConfig);
+                k0         = m_tfans.GetNumVertices();
+                m_tfans.AddVertex(focusVertex);
+                switch(config)
+                {
+                    case 0:// ops: 1000001 vertices: -1 -2
+                        m_tfans.AddVertex(m_visitedVertices[0]);
+                        for(long u = 1; u < degree-1; u++)
+                        {
+                            m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                            m_tfans.AddVertex(m_vertexCount++);
+                        }
+                        m_tfans.AddVertex(m_visitedVertices[1]);
+                        break;
+                    case 1: // ops: 1xxxxxx1 vertices: -1 x x x x x -2
+                        m_tfans.AddVertex(m_visitedVertices[0]);
+                        for(long u = 1; u < degree-1; u++)
+                        {
+                            op = m_ctfans.ReadOperation(m_itOperation);
+                            if (op == 1) 
+                            {
+                                index = m_ctfans.ReadIndex(m_itIndex);
+                                if ( index < 0) 
+                                {
+                                    m_tfans.AddVertex(m_visitedVertices[-index-1]);
+                                }
+                                else 
+                                {
+                                    m_tfans.AddVertex(index + focusVertex);
+                                }
+                            }
+                            else 
+                            {
+                                m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                                m_tfans.AddVertex(m_vertexCount++);
+                            }
+                        }
+                        m_tfans.AddVertex(m_visitedVertices[1]);
+                        break;
+                    case 2: // ops: 00000001 vertices: -1
+                        for(long u = 0; u < degree-1; u++)
+                        {
+                            m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                            m_tfans.AddVertex(m_vertexCount++);
+                        }
+                        m_tfans.AddVertex(m_visitedVertices[0]);
+                        break;
+                    case 3: // ops: 00000001 vertices: -2
+                        for(long u=0; u < degree-1; u++)
+                        {
+                            m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                            m_tfans.AddVertex(m_vertexCount++);
+                        }
+                        m_tfans.AddVertex(m_visitedVertices[1]);
+                        break;
+                    case 4: // ops: 10000000 vertices: -1
+                        m_tfans.AddVertex(m_visitedVertices[0]);
+                        for(long u = 1; u < degree; u++)
+                        {
+                            m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                            m_tfans.AddVertex(m_vertexCount++);
+                        }
+                        break;
+                    case 5: // ops: 10000000 vertices: -2
+                        m_tfans.AddVertex(m_visitedVertices[1]);
+                        for(long u = 1; u < degree; u++)
+                        {
+                            m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                            m_tfans.AddVertex(m_vertexCount++);
+                        }
+                        break;
+                    case 6:// ops: 00000000 vertices:
+                        for(long u = 0; u < degree; u++)
+                        {
+                            m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                            m_tfans.AddVertex(m_vertexCount++);
+                        }
+                        break;
+                    case 7: // ops: 1000001 vertices: -2 -1
+                        m_tfans.AddVertex(m_visitedVertices[1]);
+                        for(long u = 1; u < degree-1; u++)
+                        {
+                            m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                            m_tfans.AddVertex(m_vertexCount++);
+                        }
+                        m_tfans.AddVertex(m_visitedVertices[0]);
+                        break;
+                    case 8: // ops: 1xxxxxx1 vertices: -2 x x x x x -1
+                        m_tfans.AddVertex(m_visitedVertices[1]);
+                        for(long u = 1; u < degree-1; u++)
+                        {
+                            op = m_ctfans.ReadOperation(m_itOperation);
+                            if (op == 1) 
+                            {
+                                index = m_ctfans.ReadIndex(m_itIndex);
+                                if ( index < 0) 
+                                {
+                                    m_tfans.AddVertex(m_visitedVertices[-index-1]);
+                                }
+                                else 
+                                {
+                                    m_tfans.AddVertex(index + focusVertex);
+                                }
+                            }
+                            else 
+                            {
+                                m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                                m_tfans.AddVertex(m_vertexCount++);
+                            }
+                        }
+                        m_tfans.AddVertex(m_visitedVertices[0]);
+                        break;
+                    case 9: // general case
+                        for(long u = 0; u < degree; u++)
+                        {
+                            op = m_ctfans.ReadOperation(m_itOperation);
+                            if (op == 1) 
+                            {
+                                index = m_ctfans.ReadIndex(m_itIndex);
+                                if ( index < 0) 
+                                {
+                                    m_tfans.AddVertex(m_visitedVertices[-index-1]);
+                                }
+                                else 
+                                {
+                                    m_tfans.AddVertex(index + focusVertex);
+                                }
+                            }
+                            else 
+                            {
+                                m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
+                                m_tfans.AddVertex(m_vertexCount++);
+                            }
+                        }
+                        break;
+
+                }
+                //logger.write_2_log("\t degree=%i \t cas = %i\n", degree, cas);
+                k1 = m_tfans.GetNumVertices();
+                b  = m_tfans.GetVertex(k0+1);
+                for (long k = k0+2; k < k1; k++)
+                {
+                    c = m_tfans.GetVertex(k);
+                    t = m_triangleCount*3;
+                 
+                    m_triangles[t++] = (T) focusVertex;
+                    m_triangles[t++] = (T) b;
+                    m_triangles[t  ] = (T) c;
+
+                    m_vertexToTriangle.AddNeighbor(focusVertex, m_triangleCount);
+                    m_vertexToTriangle.AddNeighbor(b          , m_triangleCount);
+                    m_vertexToTriangle.AddNeighbor(c          , m_triangleCount);
+                    b=c;
+                    m_triangleCount++;
+                }
+            }
+        }
+        return O3DGC_OK;
+    }
+}
+#endif //O3DGC_TRIANGLE_LIST_DECODER_INL
+

+ 101 - 0
contrib/Open3DGC/o3dgcTriangleListEncoder.h

@@ -0,0 +1,101 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#pragma once
+#ifndef O3DGC_TRIANGLE_LIST_ENCODER_H
+#define O3DGC_TRIANGLE_LIST_ENCODER_H
+
+#include "o3dgcCommon.h"
+#include "o3dgcAdjacencyInfo.h"
+#include "o3dgcBinaryStream.h"
+#include "o3dgcFIFO.h"
+#include "o3dgcTriangleFans.h"
+
+namespace o3dgc
+{
+    //! 
+    template <class T>
+    class TriangleListEncoder
+    {
+    public:    
+        //! Constructor.
+                                    TriangleListEncoder(void);
+        //! Destructor.
+                                    ~TriangleListEncoder(void);
+        //! 
+        O3DGCErrorCode              Encode(const T * const triangles,
+                                           const unsigned long * const indexBufferIDs,
+                                           const long numTriangles,
+                                           const long numVertices,
+                                           BinaryStream & bstream);
+        O3DGCStreamType       GetStreamType() const { return m_streamType; }
+        void                        SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
+        const long * const          GetInvVMap() const { return m_invVMap;}
+        const long * const          GetInvTMap() const { return m_invTMap;}        
+        const long * const          GetVMap()    const { return m_vmap;}
+        const long * const          GetTMap()    const { return m_tmap;}
+        const AdjacencyInfo &       GetVertexToTriangle() const { return m_vertexToTriangle;}
+
+        private:
+        O3DGCErrorCode              Init(const T * const triangles, 
+                                         long numTriangles, 
+                                         long numVertices);
+        O3DGCErrorCode              CompueLocalConnectivityInfo(const long focusVertex);
+        O3DGCErrorCode              ProcessVertex( long focusVertex);
+        O3DGCErrorCode              ComputeTFANDecomposition(const long focusVertex);
+        O3DGCErrorCode              CompressTFAN(const long focusVertex);
+
+        long                        m_vertexCount;
+        long                        m_triangleCount;
+        long                        m_maxNumVertices;
+        long                        m_maxNumTriangles;
+        long                        m_numNonConqueredTriangles;
+        long                        m_numConqueredTriangles;
+        long                        m_numVisitedVertices;
+        long                        m_numTriangles;
+        long                        m_numVertices;
+        long                        m_maxSizeVertexToTriangle;
+        T const *                   m_triangles;
+        long *                      m_vtags;
+        long *                      m_ttags;
+        long *                      m_vmap;
+        long *                      m_invVMap;
+        long *                      m_tmap;
+        long *                      m_invTMap;
+        long *                      m_count;
+        long *                      m_nonConqueredTriangles;
+        long *                      m_nonConqueredEdges;
+        long *                      m_visitedVertices;
+        long *                      m_visitedVerticesValence;
+        FIFO<long>                  m_vfifo;
+        AdjacencyInfo               m_vertexToTriangle;
+        AdjacencyInfo               m_triangleToTriangle;
+        AdjacencyInfo               m_triangleToTriangleInv;
+        TriangleFans                m_tfans;
+        CompressedTriangleFans      m_ctfans;
+        O3DGCStreamType       m_streamType;
+    };
+}
+#include "o3dgcTriangleListEncoder.inl"    // template implementation
+#endif // O3DGC_TRIANGLE_LIST_ENCODER_H
+

+ 719 - 0
contrib/Open3DGC/o3dgcTriangleListEncoder.inl

@@ -0,0 +1,719 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_TRIANGLE_LIST_ENCODER_INL
+#define O3DGC_TRIANGLE_LIST_ENCODER_INL
+
+namespace o3dgc
+{
+    // extract opposite edge
+    template <class T>
+    inline void CompueOppositeEdge(const long focusVertex, 
+                                   const T * triangle,
+                                   long & a, long & b)
+    {                
+        if ((long) triangle[0] == focusVertex)
+        {
+            a = triangle[1];
+            b = triangle[2];
+        }
+        else if ((long) triangle[1] == focusVertex)
+        {
+            a = triangle[2];
+            b = triangle[0];
+        }
+        else
+        {
+            a = triangle[0];
+            b = triangle[1];
+        }
+    }
+    inline bool IsCase0(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 1000001 vertices: -1 -2
+        if ((numIndices != 2) || (degree < 2)) {
+            return false;
+        }
+        if ((indices[0] != -1) ||(indices[1] != -2) || 
+            (ops[0] != 1)       ||(ops[degree-1] != 1)  ) return false;
+        for (long u = 1; u < degree-1; u++) {
+            if (ops[u] != 0) return false;
+        }
+        return true;
+    }
+    inline bool IsCase1(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 1xxxxxx1 indices: -1 x x x x x -2
+        if ((degree < 2) || (numIndices < 1))
+        {
+            return false;
+        }
+        if ((indices[0] != -1) ||(indices[numIndices-1] != -2) || 
+            (ops[0] != 1)       ||(ops[degree-1] != 1)  ) return false;
+        return true;
+    }
+    inline bool IsCase2(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 00000001 indices: -1
+        if ((degree < 2) || (numIndices!= 1))
+        {
+            return false;
+        }
+        if ((indices[0] != -1) || (ops[degree-1] != 1)  ) return false;
+        for (long u = 0; u < degree-1; u++) {
+            if (ops[u] != 0) return false;
+        }
+        return true;
+    }
+    inline bool IsCase3(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 00000001 indices: -2
+        if ((degree < 2) || (numIndices!= 1))
+        {
+            return false;
+        }
+        if ((indices[0] != -2) || (ops[degree-1] != 1)  ) return false;
+        for (long u = 0; u < degree-1; u++) {
+            if (ops[u] != 0) return false;
+        }
+        return true;
+    }
+    inline bool IsCase4(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 10000000 indices: -1
+        if ((degree < 2) || (numIndices!= 1)) 
+        {
+            return false;
+        }
+        if ((indices[0] != -1) || (ops[0] != 1)  ) return false;
+        for (long u = 1; u < degree; u++) 
+        {
+            if (ops[u] != 0) return false;
+        }
+        return true;
+    }
+    inline bool IsCase5(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 10000000 indices: -2
+        if ((degree < 2) || (numIndices!= 1)) 
+        {
+            return false;
+        }
+        if ((indices[0] != -2) || (ops[0] != 1)  ) return false;
+        for (long u = 1; u < degree; u++) {
+            if (ops[u] != 0) return false;
+        }
+        return true;
+    }
+    inline bool IsCase6(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 0000000 indices: 
+        if (numIndices!= 0) 
+        {
+            return false;
+        }
+        for (long u = 0; u < degree; u++) 
+        {
+            if (ops[u] != 0) return false;
+        }
+        return true;
+    }
+    inline bool IsCase7(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 1000001 indices: -2 -1
+        if ((numIndices!= 2) || (degree < 2)) 
+        {
+            return false;
+        }
+        if ((indices[0] != -2) ||(indices[1] != -1) || 
+            (ops[0] != 1)      ||(ops[degree-1] != 1)  ) return false;
+        for (long u = 1; u < degree-1; u++) 
+        {
+            if (ops[u] != 0) return false;
+        }
+        return true;
+    }
+    inline bool IsCase8(long degree, long numIndices, const long * const ops, const long * const indices)
+    {
+        // ops: 1xxxxxx1 indices: -1 x x x x x -2
+        if ((degree < 2) || (numIndices < 1)) 
+        {
+            return false;
+        }
+        if ((indices[0] != -2) ||(indices[numIndices-1] != -1) || 
+            (ops[0] != 1)      ||(ops[degree-1] != 1)  ) return false;
+        return true;
+    }
+    template <class T>
+    TriangleListEncoder<T>::TriangleListEncoder(void)
+    {
+        m_vtags                   = 0;
+        m_ttags                   = 0;
+        m_tmap                    = 0;
+        m_vmap                    = 0;
+        m_count                   = 0;
+        m_invVMap                 = 0;
+        m_invTMap                 = 0;
+        m_nonConqueredTriangles   = 0;
+        m_nonConqueredEdges       = 0;
+        m_visitedVertices         = 0;
+        m_visitedVerticesValence  = 0;
+        m_vertexCount             = 0;
+        m_triangleCount           = 0;
+        m_maxNumVertices          = 0;
+        m_maxNumTriangles         = 0;
+        m_numTriangles            = 0;
+        m_numVertices             = 0;
+        m_triangles               = 0;
+        m_maxSizeVertexToTriangle = 0;
+        m_streamType              = O3DGC_STREAM_TYPE_UNKOWN;
+    }
+    template <class T>
+    TriangleListEncoder<T>::~TriangleListEncoder()
+    {
+        delete [] m_vtags;
+        delete [] m_vmap;
+        delete [] m_invVMap;
+        delete [] m_invTMap;
+        delete [] m_visitedVerticesValence;
+        delete [] m_visitedVertices;
+        delete [] m_ttags;
+        delete [] m_tmap;
+        delete [] m_count;
+        delete [] m_nonConqueredTriangles;
+        delete [] m_nonConqueredEdges;
+    }
+    template <class T>
+    O3DGCErrorCode TriangleListEncoder<T>::Init(const T * const triangles, 
+                                             long numTriangles, 
+                                             long numVertices)
+    {
+        assert(numVertices  > 0);
+        assert(numTriangles > 0);
+
+        m_numTriangles  = numTriangles;
+        m_numVertices   = numVertices;
+        m_triangles     = triangles;
+        m_vertexCount   = 0;
+        m_triangleCount = 0;
+        
+        if  (m_numVertices > m_maxNumVertices)
+        {
+            delete [] m_vtags;
+            delete [] m_vmap;
+            delete [] m_invVMap;
+            delete [] m_visitedVerticesValence;
+            delete [] m_visitedVertices;
+            m_maxNumVertices         = m_numVertices;
+            m_vtags                  = new long [m_numVertices];
+            m_vmap                   = new long [m_numVertices];
+            m_invVMap                = new long [m_numVertices];
+            m_visitedVerticesValence = new long [m_numVertices];
+            m_visitedVertices        = new long [m_numVertices];
+        }
+        
+        if  (m_numTriangles > m_maxNumTriangles)
+        {
+            delete [] m_ttags;
+            delete [] m_tmap;
+            delete [] m_invTMap;
+            delete [] m_nonConqueredTriangles;
+            delete [] m_nonConqueredEdges;
+            delete [] m_count;
+            m_maxNumTriangles       = m_numTriangles;
+            m_ttags                 = new long [m_numTriangles];
+            m_tmap                  = new long [m_numTriangles];
+            m_invTMap               = new long [m_numTriangles];
+            m_count                 = new long [m_numTriangles+1];
+            m_nonConqueredTriangles = new long [m_numTriangles];
+            m_nonConqueredEdges     = new long [2*m_numTriangles];
+        }
+
+        memset(m_vtags  , 0x00, sizeof(long) * m_numVertices );
+        memset(m_vmap   , 0xFF, sizeof(long) * m_numVertices );
+        memset(m_invVMap, 0xFF, sizeof(long) * m_numVertices );
+        memset(m_ttags  , 0x00, sizeof(long) * m_numTriangles);
+        memset(m_tmap   , 0xFF, sizeof(long) * m_numTriangles);
+        memset(m_invTMap, 0xFF, sizeof(long) * m_numTriangles);
+        memset(m_count  , 0x00, sizeof(long) * (m_numTriangles+1));
+
+        m_vfifo.Allocate(m_numVertices);
+        m_ctfans.SetStreamType(m_streamType);
+        m_ctfans.Allocate(m_numVertices, m_numTriangles);
+
+        // compute vertex-to-triangle adjacency information
+        m_vertexToTriangle.AllocateNumNeighborsArray(numVertices);
+        m_vertexToTriangle.ClearNumNeighborsArray();
+        long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer();
+        for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3)
+        {
+            ++numNeighbors[ triangles[t  ] ];
+            ++numNeighbors[ triangles[t+1] ];
+            ++numNeighbors[ triangles[t+2] ];
+        }
+        m_maxSizeVertexToTriangle = 0;
+        for(long i = 0; i < numVertices; ++i)
+        {
+            if (m_maxSizeVertexToTriangle < numNeighbors[i])
+            {
+                m_maxSizeVertexToTriangle = numNeighbors[i];
+            }
+        }
+        m_vertexToTriangle.AllocateNeighborsArray();
+        m_vertexToTriangle.ClearNeighborsArray();
+        for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3)
+        {
+            m_vertexToTriangle.AddNeighbor(triangles[t  ], i);
+            m_vertexToTriangle.AddNeighbor(triangles[t+1], i);
+            m_vertexToTriangle.AddNeighbor(triangles[t+2], i);
+        }
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode TriangleListEncoder<T>::Encode(const T * const triangles, 
+                                                  const unsigned long * const indexBufferIDs,
+                                                  const long numTriangles,
+                                                  const long numVertices, 
+                                                  BinaryStream & bstream)
+    {
+        assert(numVertices > 0);
+        assert(numTriangles > 0);
+        
+        Init(triangles, numTriangles, numVertices);
+        unsigned char mask = 0;
+        bool encodeTrianglesOrder = (indexBufferIDs != 0);
+
+        
+        if (encodeTrianglesOrder)
+        {
+            long numBufferIDs = 0;
+            for (long t = 0; t < numTriangles; t++)
+            {
+                if (numBufferIDs <= (long) indexBufferIDs[t])
+                {
+                    ++numBufferIDs;
+                    assert(numBufferIDs <= numTriangles);
+                }
+                ++m_count[indexBufferIDs[t]+1];
+            }
+            for (long i = 2; i <= numBufferIDs; i++)
+            {
+                m_count[i] += m_count[i-1];
+            }
+            mask += 2; // preserved triangles order
+        }
+        bstream.WriteUChar(mask, m_streamType); 
+        bstream.WriteUInt32(m_maxSizeVertexToTriangle, m_streamType);
+
+        long v0;
+        for (long v = 0; v < m_numVertices; v++)
+        {
+            if (!m_vtags[v]) 
+            {
+                m_vfifo.PushBack(v);
+                m_vtags[v] = 1; 
+                m_vmap[v] = m_vertexCount++;
+                m_invVMap[m_vmap[v]] = v;
+                while (m_vfifo.GetSize() > 0 )
+                {
+                    v0 = m_vfifo.PopFirst();
+                    ProcessVertex(v0);
+                }
+            }
+        }
+        if (encodeTrianglesOrder)
+        {
+            long t, prev = 0;
+            long pred;
+            for (long i = 0; i < numTriangles; ++i)
+            {
+                t = m_invTMap[i];
+                m_tmap[t] = m_count[ indexBufferIDs[t] ]++;
+                pred = m_tmap[t] - prev;
+                m_ctfans.PushTriangleIndex(pred);
+                prev = m_tmap[t] + 1;
+            }
+            for (long t = 0; t < numTriangles; ++t)
+            {
+                m_invTMap[m_tmap[t]] = t;
+            }
+        }
+        m_ctfans.Save(bstream, encodeTrianglesOrder, m_streamType);
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode TriangleListEncoder<T>::CompueLocalConnectivityInfo(const long focusVertex)
+    {
+        long t, v, p;
+        m_numNonConqueredTriangles = 0;
+        m_numConqueredTriangles    = 0;
+        m_numVisitedVertices       = 0;
+        for(long i = m_vertexToTriangle.Begin(focusVertex); i < m_vertexToTriangle.End(focusVertex); ++i)
+        {
+            t = m_vertexToTriangle.GetNeighbor(i);
+
+            if ( m_ttags[t] == 0) // non-processed triangle
+            {
+                m_nonConqueredTriangles[m_numNonConqueredTriangles] = t;
+                CompueOppositeEdge( focusVertex, 
+                                    m_triangles + (3*t), 
+                                    m_nonConqueredEdges[m_numNonConqueredTriangles*2],
+                                    m_nonConqueredEdges[m_numNonConqueredTriangles*2+1]);
+                ++m_numNonConqueredTriangles;
+            }
+            else                // triangle already processed
+            {
+                m_numConqueredTriangles++;
+                p = 3*t;
+                // extract visited vertices
+                for(long k = 0; k < 3; ++k)
+                {
+                    v = m_triangles[p+k];
+                    if (m_vmap[v] > m_vmap[focusVertex]) // vertices are insertices by increasing traversal order
+                    {
+                        bool foundOrInserted = false;
+                        for (long j = 0; j < m_numVisitedVertices; ++j)
+                        {
+
+                            if (m_vmap[v] == m_visitedVertices[j])
+                            {
+                                m_visitedVerticesValence[j]++;
+                                foundOrInserted = true;
+                                break;
+                            }
+                            else if (m_vmap[v] < m_visitedVertices[j])
+                            {
+                                ++m_numVisitedVertices;
+                                for (long h = m_numVisitedVertices-1; h > j; --h)
+                                {
+                                    m_visitedVertices[h]        = m_visitedVertices[h-1];
+                                    m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1];
+                                }
+                                m_visitedVertices[j]        = m_vmap[v];
+                                m_visitedVerticesValence[j] = 1;
+                                foundOrInserted = true;
+                                break;
+                            }
+                        }
+                        if (!foundOrInserted)
+                        {
+                            m_visitedVertices[m_numVisitedVertices] = m_vmap[v];
+                            m_visitedVerticesValence[m_numVisitedVertices] = 1;
+                            m_numVisitedVertices++;
+                        }
+                    }
+                }
+            }            
+        }
+        // re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex)
+        // in order to avoid config. 9
+        if (m_numVisitedVertices > 2)
+        {
+            long y;
+            for(long x = 1; x < m_numVisitedVertices; ++x)
+            {
+
+                if (m_visitedVerticesValence[x] == 1)
+                {
+                    y = x;
+                    while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) )
+                    {
+                        swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]);
+                        swap(m_visitedVertices[y], m_visitedVertices[y-1]);
+                        --y;
+                    }
+                }
+            }
+        }
+        if (m_numNonConqueredTriangles > 0)
+        {
+            // compute triangle-to-triangle adjacency information
+            m_triangleToTriangle.AllocateNumNeighborsArray(m_numNonConqueredTriangles);
+            m_triangleToTriangle.ClearNumNeighborsArray();
+            m_triangleToTriangleInv.AllocateNumNeighborsArray(m_numNonConqueredTriangles);
+            m_triangleToTriangleInv.ClearNumNeighborsArray();
+            long * const numNeighbors    = m_triangleToTriangle.GetNumNeighborsBuffer();
+            long * const invNumNeighbors = m_triangleToTriangleInv.GetNumNeighborsBuffer();
+            for(long i = 0; i < m_numNonConqueredTriangles; ++i)
+            {
+                for(long j = i+1; j < m_numNonConqueredTriangles; ++j)
+                {
+                    if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j
+                    {
+                        ++numNeighbors[i];
+                        ++invNumNeighbors[j];
+                    }
+                    if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j
+                    {
+                        ++numNeighbors[j];
+                        ++invNumNeighbors[i];
+                    }
+                }
+            }
+            m_triangleToTriangle.AllocateNeighborsArray();
+            m_triangleToTriangle.ClearNeighborsArray();
+            m_triangleToTriangleInv.AllocateNeighborsArray();
+            m_triangleToTriangleInv.ClearNeighborsArray();
+            for(long i = 0; i < m_numNonConqueredTriangles; ++i)
+            {
+                for(long j = 1; j < m_numNonConqueredTriangles; ++j)
+                {
+                    if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j
+                    {
+                        m_triangleToTriangle.AddNeighbor(i, j);
+                        m_triangleToTriangleInv.AddNeighbor(j, i);
+                    }
+                    if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j
+                    {
+                        m_triangleToTriangle.AddNeighbor(j, i);
+                        m_triangleToTriangleInv.AddNeighbor(i, j);
+                    }
+                }
+            }
+        }
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode TriangleListEncoder<T>::ComputeTFANDecomposition(const long focusVertex)
+    {
+        long processedTriangles = 0;
+        long minNumInputEdges;
+        long numInputEdges;
+        long indexSeedTriangle;
+        long seedTriangle;
+        long currentIndex;
+        long currentTriangle;
+        long i0, i1, index;
+
+        m_tfans.Clear();
+        while (processedTriangles != m_numNonConqueredTriangles)
+        {
+            // find non processed triangle with lowest number of inputs
+            minNumInputEdges   = m_numTriangles;
+            indexSeedTriangle = -1;
+            for(long i = 0; i < m_numNonConqueredTriangles; ++i)
+            {
+                numInputEdges = m_triangleToTriangleInv.GetNumNeighbors(i);
+                if ( !m_ttags[m_nonConqueredTriangles[i]] && 
+                      numInputEdges < minNumInputEdges            )
+                {
+                    minNumInputEdges  = numInputEdges;
+                    indexSeedTriangle = i;
+                    if (minNumInputEdges == 0) // found boundary triangle
+                    {
+                        break;
+                    }
+                }
+            }
+            assert(indexSeedTriangle >= 0);
+            seedTriangle = m_nonConqueredTriangles[indexSeedTriangle];
+            m_tfans.AddTFAN();
+            m_tfans.AddVertex( focusVertex );
+            m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2] );
+            m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2 + 1] );
+            m_ttags[ seedTriangle ]         = 1; // mark triangle as processed
+            m_tmap[seedTriangle]            = m_triangleCount++;
+            m_invTMap[m_tmap[seedTriangle]] = seedTriangle;
+            ++processedTriangles;
+            currentIndex                    = indexSeedTriangle;
+            currentTriangle                 = seedTriangle;
+            do
+            {
+                // find next triangle            
+                i0 = m_triangleToTriangle.Begin(currentIndex);
+                i1 = m_triangleToTriangle.End(currentIndex);
+                currentIndex = -1;
+                for(long i = i0; i < i1; ++i)
+                {
+                    index           = m_triangleToTriangle.GetNeighbor(i);
+                    currentTriangle = m_nonConqueredTriangles[index];
+                    if ( !m_ttags[currentTriangle] )
+                    {
+                        currentIndex = index;
+                        m_tfans.AddVertex( m_nonConqueredEdges[currentIndex*2+1] );
+                        m_ttags[currentTriangle]            = 1; // mark triangle as processed
+                        m_tmap [currentTriangle]            = m_triangleCount++;
+                        m_invTMap[m_tmap [currentTriangle]] = currentTriangle;
+                        ++processedTriangles;
+                        break;
+                    }
+                }
+            } while (currentIndex != -1);
+        }
+
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode TriangleListEncoder<T>::CompressTFAN(const long focusVertex)
+    {
+        m_ctfans.PushNumTFans(m_tfans.GetNumTFANs());    
+
+        const long ntfans = m_tfans.GetNumTFANs();
+        long degree;
+        long k0, k1;
+        long v0;
+        long ops[O3DGC_MAX_TFAN_SIZE];
+        long indices[O3DGC_MAX_TFAN_SIZE];
+
+        long numOps;
+        long numIndices;
+        long pos;
+        long found;
+
+        if (m_tfans.GetNumTFANs() > 0) 
+        {
+            for(long f = 0; f != ntfans; f++) 
+            {
+                degree = m_tfans.GetTFANSize(f) - 1;
+                m_ctfans.PushDegree(degree-2+ m_numConqueredTriangles);
+                numOps     = 0;
+                numIndices = 0;
+                k0 = 1 + m_tfans.Begin(f);
+                k1 = m_tfans.End(f);
+                for(long k = k0; k < k1; k++) 
+                {
+                    v0 = m_tfans.GetVertex(k);
+                    if (m_vtags[v0] == 0)
+                    {
+                        ops[numOps++] = 0;
+                        m_vtags[v0] = 1;
+                        m_vmap[v0] = m_vertexCount++;
+                        m_invVMap[m_vmap[v0]] = v0;
+                        m_vfifo.PushBack(v0);
+                        m_visitedVertices[m_numVisitedVertices++] = m_vmap[v0];
+                    }
+                    else 
+                    {
+                        ops[numOps++] = 1;
+                        pos = 0;
+                        found = 0;
+                        for(long u=0; u < m_numVisitedVertices; ++u)
+                        {
+                            pos++;
+                            if (m_visitedVertices[u] == m_vmap[v0]) 
+                            {
+                                found = 1;
+                                break;
+                            }
+                        }    
+                        if (found == 1)
+                        {
+                            indices[numIndices++] = -pos;
+                        }
+                        else 
+                        {
+                            indices[numIndices++] = m_vmap[v0] - m_vmap[focusVertex];
+                        }
+                    }
+                }
+                //-----------------------------------------------
+                if (IsCase0(degree, numIndices, ops, indices))
+                { 
+                    // ops: 1000001 vertices: -1 -2
+                    m_ctfans.PushConfig(0);
+                }
+                else if (IsCase1(degree, numIndices, ops, indices))
+                {
+                    // ops: 1xxxxxx1 vertices: -1 x x x x x -2
+                    long u = 1;
+                    for(u = 1; u < degree-1; u++)
+                    {
+                        m_ctfans.PushOperation(ops[u]);
+                    }
+                    for(u =1; u < numIndices-1; u++)
+                    {
+                        m_ctfans.PushIndex(indices[u]);
+                    }
+                    m_ctfans.PushConfig(1);
+                }
+                else if (IsCase2(degree, numIndices, ops, indices))
+                {
+                    // ops: 00000001 vertices: -1
+                    m_ctfans.PushConfig(2);
+                }
+                else if (IsCase3(degree, numIndices, ops, indices))
+                {
+                    // ops: 00000001 vertices: -2
+                    m_ctfans.PushConfig(3);
+                }            
+                else if (IsCase4(degree, numIndices, ops, indices))
+                {
+                    // ops: 10000000 vertices: -1
+                    m_ctfans.PushConfig(4);
+                }
+                else if (IsCase5(degree, numIndices, ops, indices))
+                {
+                    // ops: 10000000 vertices: -2
+                    m_ctfans.PushConfig(5);
+                }            
+                else if (IsCase6(degree, numIndices, ops, indices))
+                {
+                    // ops: 00000000 vertices:
+                    m_ctfans.PushConfig(6);
+                }
+                else if (IsCase7(degree, numIndices, ops, indices))
+                {
+                    // ops: 1000001 vertices: -1 -2
+                    m_ctfans.PushConfig(7);
+                }
+                else if (IsCase8(degree, numIndices, ops, indices))
+                {
+                    // ops: 1xxxxxx1 vertices: -2 x x x x x -1
+                    long u = 1;
+                    for(u =1; u < degree-1; u++)
+                    {
+                        m_ctfans.PushOperation(ops[u]);
+                    }
+                    for(u =1; u < numIndices-1; u++)
+                    {
+                        m_ctfans.PushIndex(indices[u]);
+                    }
+                    m_ctfans.PushConfig(8);
+                }
+                else 
+                {
+                    long u = 0;
+                    for(u =0; u < degree; u++)
+                    {
+                        m_ctfans.PushOperation(ops[u]);
+                    }
+                    for(u =0; u < numIndices; u++)
+                    {
+                        m_ctfans.PushIndex(indices[u]);
+                    }
+                    m_ctfans.PushConfig(9);
+                }
+            }
+        }
+        return O3DGC_OK;
+    }
+    template <class T>
+    O3DGCErrorCode TriangleListEncoder<T>::ProcessVertex(const long focusVertex)
+    {
+        CompueLocalConnectivityInfo(focusVertex);
+        ComputeTFANDecomposition(focusVertex);
+        CompressTFAN(focusVertex);
+        return O3DGC_OK;
+    }
+}
+#endif //O3DGC_TRIANGLE_LIST_ENCODER_INL

+ 184 - 0
contrib/Open3DGC/o3dgcVector.h

@@ -0,0 +1,184 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_VECTOR_H
+#define O3DGC_VECTOR_H
+
+#include "o3dgcCommon.h"
+
+namespace o3dgc
+{
+    const unsigned long O3DGC_DEFAULT_VECTOR_SIZE = 32;
+
+    //! 
+    template < typename T > class Vector
+    {
+    public:    
+        //! Constructor.
+                                Vector()
+                                {
+                                    m_allocated = 0;
+                                    m_size      = 0;
+                                    m_buffer    = 0;
+                                };
+        //! Destructor.
+                                ~Vector(void)
+                                {
+                                    delete [] m_buffer;
+                                };
+        T &                     operator[](unsigned long i)
+                                { 
+                                    return m_buffer[i];
+                                }
+        const T &               operator[](unsigned long i) const
+                                { 
+                                    return m_buffer[i];
+                                }
+        void                    Allocate(unsigned long size)
+                                {
+                                    if (size > m_allocated)
+                                    {
+                                        m_allocated = size;
+                                        T * tmp     = new T [m_allocated];
+                                        if (m_size > 0)
+                                        {
+                                            memcpy(tmp, m_buffer, m_size * sizeof(T) );
+                                            delete [] m_buffer;
+                                        }
+                                        m_buffer = tmp;
+                                    }
+                                };
+        void                    PushBack(const T & value)
+                                {
+                                    if (m_size == m_allocated)
+                                    {
+                                        m_allocated *= 2;
+                                        if (m_allocated < O3DGC_DEFAULT_VECTOR_SIZE)
+                                        {
+                                            m_allocated = O3DGC_DEFAULT_VECTOR_SIZE;
+                                        }
+                                        T * tmp      = new T [m_allocated];
+                                        if (m_size > 0)
+                                        {
+                                            memcpy(tmp, m_buffer, m_size * sizeof(T) );
+                                            delete [] m_buffer;
+                                        }
+                                        m_buffer = tmp;
+                                    }
+                                    assert(m_size < m_allocated);
+                                    m_buffer[m_size++] = value;
+                                }
+        const T * const         GetBuffer() const { return m_buffer;};
+        T * const               GetBuffer()       { return m_buffer;};
+        unsigned long                  GetSize()   const { return m_size;};
+        void                    SetSize(unsigned long size)
+                                { 
+                                    assert(size <= m_allocated);
+                                    m_size = size;
+                                };
+        unsigned long                  GetAllocatedSize() const { return m_allocated;};
+        void                    Clear(){ m_size = 0;};
+
+    private:
+        T *                     m_buffer;
+        unsigned long                  m_allocated;
+        unsigned long                  m_size;
+    };
+
+
+
+
+    //!    Vector dim 3.
+    template < typename T > class Vec3
+    {
+    public:
+        T &                 operator[](unsigned long i) { return m_data[i];}
+        const T      &      operator[](unsigned long i) const { return m_data[i];}
+        T &                 X();
+        T &                 Y();
+        T &                 Z();
+        const T      &      X() const;
+        const T      &      Y() const;
+        const T      &      Z() const;
+        double              GetNorm() const;
+        void                operator= (const Vec3 & rhs);
+        void                operator+=(const Vec3 & rhs);
+        void                operator-=(const Vec3 & rhs);
+        void                operator-=(T a);
+        void                operator+=(T a);
+        void                operator/=(T a);
+        void                operator*=(T a);
+        Vec3                operator^ (const Vec3 & rhs) const;
+        T                   operator* (const Vec3 & rhs) const;
+        Vec3                operator+ (const Vec3 & rhs) const;
+        Vec3                operator- (const Vec3 & rhs) const;
+        Vec3                operator- () const;
+        Vec3                operator* (T rhs) const;
+        Vec3                operator/ (T rhs) const;
+                            Vec3();
+                            Vec3(T a);
+                            Vec3(T x, T y, T z);
+                            Vec3(const Vec3 & rhs);
+                            ~Vec3(void);
+
+    private:
+        T                    m_data[3];
+    };
+    //!    Vector dim 2.
+    template < typename T > class Vec2
+    {
+    public:
+        T &                 operator[](unsigned long i) { return m_data[i];}
+        const T &           operator[](unsigned long i) const { return m_data[i];}
+        T &                 X();
+        T &                 Y();
+        const T &           X() const;
+        const T &           Y() const;
+        double              GetNorm() const;
+        void                operator= (const Vec2 & rhs);
+        void                operator+=(const Vec2 & rhs);
+        void                operator-=(const Vec2 & rhs);
+        void                operator-=(T a);
+        void                operator+=(T a);
+        void                operator/=(T a);
+        void                operator*=(T a);
+        T                   operator^ (const Vec2 & rhs) const;
+        T                   operator* (const Vec2 & rhs) const;
+        Vec2                operator+ (const Vec2 & rhs) const;
+        Vec2                operator- (const Vec2 & rhs) const;
+        Vec2                operator- () const;
+        Vec2                operator* (T rhs) const;
+        Vec2                operator/ (T rhs) const;
+                            Vec2();
+                            Vec2(T a);
+                            Vec2(T x, T y);
+                            Vec2(const Vec2 & rhs);
+                            ~Vec2(void);
+
+    private:
+        T                   m_data[2];
+    };
+}
+#include "o3dgcVector.inl"    // template implementation
+#endif // O3DGC_VECTOR_H
+

+ 317 - 0
contrib/Open3DGC/o3dgcVector.inl

@@ -0,0 +1,317 @@
+/*
+Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#pragma once
+#ifndef O3DGC_VECTOR_INL
+#define O3DGC_VECTOR_INL
+namespace o3dgc
+{
+    template <typename T> 
+    inline Vec3<T> operator*(T lhs, const Vec3<T> & rhs)
+    {
+        return Vec3<T>(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z());
+    }
+    template <typename T>
+    inline T & Vec3<T>::X()
+    {
+        return m_data[0];
+    }
+    template <typename T>
+    inline  T &    Vec3<T>::Y()
+    {
+        return m_data[1];
+    }
+    template <typename T>
+    inline  T &    Vec3<T>::Z()
+    {
+        return m_data[2];
+    }
+    template <typename T>
+    inline  const T & Vec3<T>::X() const
+    {
+        return m_data[0];
+    }
+    template <typename T>
+    inline  const T & Vec3<T>::Y() const
+    {
+        return m_data[1];
+    }
+    template <typename T>
+    inline  const T & Vec3<T>::Z() const
+    {
+        return m_data[2];
+    }
+    template <typename T>
+    inline  double Vec3<T>::GetNorm() const
+    { 
+        double a = (double) (m_data[0]);
+        double b = (double) (m_data[1]);
+        double c = (double) (m_data[2]);
+        return sqrt(a*a+b*b+c*c);
+    }
+    template <typename T>
+    inline  void Vec3<T>::operator= (const Vec3 & rhs)
+    { 
+        this->m_data[0] = rhs.m_data[0];
+        this->m_data[1] = rhs.m_data[1];
+        this->m_data[2] = rhs.m_data[2];
+    }
+    template <typename T>
+    inline  void Vec3<T>::operator+=(const Vec3 & rhs)
+    { 
+        this->m_data[0] += rhs.m_data[0];
+        this->m_data[1] += rhs.m_data[1];
+        this->m_data[2] += rhs.m_data[2];
+    }     
+    template <typename T>
+    inline void Vec3<T>::operator-=(const Vec3 & rhs)
+    { 
+        this->m_data[0] -= rhs.m_data[0];
+        this->m_data[1] -= rhs.m_data[1];
+        this->m_data[2] -= rhs.m_data[2];
+    }
+    template <typename T>
+    inline void Vec3<T>::operator-=(T a)
+    { 
+        this->m_data[0] -= a;
+        this->m_data[1] -= a;
+        this->m_data[2] -= a;
+    }
+    template <typename T>
+    inline void Vec3<T>::operator+=(T a)
+    { 
+        this->m_data[0] += a;
+        this->m_data[1] += a;
+        this->m_data[2] += a;
+    }
+    template <typename T>  
+    inline void Vec3<T>::operator/=(T a)
+    { 
+        this->m_data[0] /= a;
+        this->m_data[1] /= a;
+        this->m_data[2] /= a;
+    }
+    template <typename T>  
+    inline void Vec3<T>::operator*=(T a)
+    { 
+        this->m_data[0] *= a;
+        this->m_data[1] *= a;
+        this->m_data[2] *= a;
+    }  
+    template <typename T>
+    inline Vec3<T> Vec3<T>::operator^ (const Vec3<T> & rhs) const
+    {
+        return Vec3<T>(m_data[1] * rhs.m_data[2] - m_data[2] * rhs.m_data[1],
+                       m_data[2] * rhs.m_data[0] - m_data[0] * rhs.m_data[2],
+                       m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]);
+    }
+    template <typename T>
+    inline T Vec3<T>::operator*(const Vec3<T> & rhs) const
+    {
+        return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1] + m_data[2] * rhs.m_data[2]);
+    }        
+    template <typename T>
+    inline Vec3<T> Vec3<T>::operator+(const Vec3<T> & rhs) const
+    {
+        return Vec3<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]);
+    }
+    template <typename T> 
+    inline  Vec3<T> Vec3<T>::operator-(const Vec3<T> & rhs) const
+    {
+        return Vec3<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]);
+    }     
+    template <typename T> 
+    inline  Vec3<T> Vec3<T>::operator-() const
+    {
+        return Vec3<T>(-m_data[0],-m_data[1],-m_data[2]);
+    }     
+
+    template <typename T> 
+    inline Vec3<T> Vec3<T>::operator*(T rhs) const
+    {
+        return Vec3<T>(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]);
+    }
+    template <typename T>
+    inline Vec3<T> Vec3<T>::operator/ (T rhs) const
+    {
+        return Vec3<T>(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs);
+    }
+    template <typename T>
+    inline Vec3<T>::Vec3(T a) 
+    { 
+        m_data[0] = m_data[1] = m_data[2] = a;
+    }
+    template <typename T>
+    inline Vec3<T>::Vec3(T x, T y, T z)
+    {
+        m_data[0] = x;
+        m_data[1] = y;
+        m_data[2] = z;
+    }
+    template <typename T>
+    inline Vec3<T>::Vec3(const Vec3 & rhs)
+    {        
+        m_data[0] = rhs.m_data[0];
+        m_data[1] = rhs.m_data[1];
+        m_data[2] = rhs.m_data[2];
+    }
+    template <typename T>
+    inline Vec3<T>::~Vec3(void){};
+
+    template <typename T>
+    inline Vec3<T>::Vec3() {}
+    
+    template <typename T>
+    inline Vec2<T> operator*(T lhs, const Vec2<T> & rhs)
+    {
+        return Vec2<T>(lhs * rhs.X(), lhs * rhs.Y());
+    }
+    template <typename T>
+    inline T & Vec2<T>::X()
+    {
+        return m_data[0];
+    }
+    template <typename T>
+    inline  T &    Vec2<T>::Y()
+    {
+        return m_data[1];
+    }
+    template <typename T>
+    inline  const T & Vec2<T>::X() const
+    {
+        return m_data[0];
+    }
+    template <typename T>
+    inline  const T & Vec2<T>::Y() const
+    {
+        return m_data[1];
+    }
+    template <typename T>
+    inline  double Vec2<T>::GetNorm() const
+    { 
+        double a = (double) (m_data[0]);
+        double b = (double) (m_data[1]);
+        return sqrt(a*a+b*b);
+    }
+    template <typename T>
+    inline  void Vec2<T>::operator= (const Vec2 & rhs)
+    { 
+        this->m_data[0] = rhs.m_data[0]; 
+        this->m_data[1] = rhs.m_data[1]; 
+    }
+    template <typename T>
+    inline  void Vec2<T>::operator+=(const Vec2 & rhs)
+    { 
+        this->m_data[0] += rhs.m_data[0];
+        this->m_data[1] += rhs.m_data[1];
+    }     
+    template <typename T>  
+    inline void Vec2<T>::operator-=(const Vec2 & rhs)
+    { 
+        this->m_data[0] -= rhs.m_data[0];
+        this->m_data[1] -= rhs.m_data[1];
+    }
+    template <typename T>
+    inline void Vec2<T>::operator-=(T a)
+    { 
+        this->m_data[0] -= a;
+        this->m_data[1] -= a;
+    }
+    template <typename T>
+    inline void Vec2<T>::operator+=(T a)
+    { 
+        this->m_data[0] += a;
+        this->m_data[1] += a;
+    }
+    template <typename T>
+    inline void Vec2<T>::operator/=(T a)
+    { 
+        this->m_data[0] /= a;
+        this->m_data[1] /= a;
+    }
+    template <typename T>
+    inline void Vec2<T>::operator*=(T a)
+    { 
+        this->m_data[0] *= a;
+        this->m_data[1] *= a;
+    }  
+    template <typename T>
+    inline T Vec2<T>::operator^ (const Vec2<T> & rhs) const
+    {
+        return m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0];
+    }
+    template <typename T>
+    inline T Vec2<T>::operator*(const Vec2<T> & rhs) const
+    {
+        return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1]);
+    }        
+    template <typename T>
+    inline Vec2<T> Vec2<T>::operator+(const Vec2<T> & rhs) const
+    {
+        return Vec2<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1]);
+    }
+    template <typename T>
+    inline  Vec2<T> Vec2<T>::operator-(const Vec2<T> & rhs) const
+    {
+        return Vec2<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1]);
+    }     
+    template <typename T>
+    inline  Vec2<T> Vec2<T>::operator-() const
+    {
+        return Vec2<T>(-m_data[0],-m_data[1]) ;
+    }     
+
+    template <typename T>
+    inline Vec2<T> Vec2<T>::operator*(T rhs) const
+    {
+        return Vec2<T>(rhs * this->m_data[0], rhs * this->m_data[1]);
+    }
+    template <typename T>
+    inline Vec2<T> Vec2<T>::operator/ (T rhs) const
+    {
+        return Vec2<T>(m_data[0] / rhs, m_data[1] / rhs);
+    }
+    template <typename T>
+    inline Vec2<T>::Vec2(T a)
+    { 
+        m_data[0] = m_data[1] = a;
+    }
+    template <typename T>
+    inline Vec2<T>::Vec2(T x, T y)
+    {
+        m_data[0] = x;
+        m_data[1] = y;
+    }
+    template <typename T>
+    inline Vec2<T>::Vec2(const Vec2 & rhs)
+    {        
+        m_data[0] = rhs.m_data[0];
+        m_data[1] = rhs.m_data[1];
+    }
+    template <typename T>
+    inline Vec2<T>::~Vec2(void){};
+
+    template <typename T>
+    inline Vec2<T>::Vec2() {}
+}
+#endif //O3DGC_VECTOR_INL
+

+ 656 - 0
doc/architecture/Assimp_Arch_Import.class.violet.html

@@ -0,0 +1,656 @@
+<HTML>
+<HEAD>
+<META name="description"
+	content="Violet UML Editor cross format document" />
+<META name="keywords" content="Violet, UML" />
+<META charset="UTF-8" />
+<SCRIPT type="text/javascript">
+	function switchVisibility() {
+		var obj = document.getElementById("content");
+		obj.style.display = (obj.style.display == "block") ? "none" : "block";
+	}
+</SCRIPT>
+</HEAD>
+<BODY>
+	This file was generated with Violet UML Editor 2.1.0.
+	&nbsp;&nbsp;(&nbsp;<A href=# onclick="switchVisibility()">View Source</A>&nbsp;/&nbsp;<A href="http://sourceforge.net/projects/violet/files/violetumleditor/" target="_blank">Download Violet</A>&nbsp;)
+	<BR />
+	<BR />
+	<SCRIPT id="content" type="text/xml"><![CDATA[<ClassDiagramGraph id="1">
+  <nodes id="2">
+    <ClassNode id="3">
+      <children id="4"/>
+      <location class="Point2D.Double" id="5" x="270.0" y="200.0"/>
+      <id id="6" value="8ccad607-14e2-4eec-836e-b25f61cfa2ea"/>
+      <revision>1</revision>
+      <backgroundColor id="7">
+        <red>255</red>
+        <green>255</green>
+        <blue>255</blue>
+        <alpha>255</alpha>
+      </backgroundColor>
+      <borderColor id="8">
+        <red>0</red>
+        <green>0</green>
+        <blue>0</blue>
+        <alpha>255</alpha>
+      </borderColor>
+      <textColor reference="8"/>
+      <name id="9" justification="1" size="3" underlined="false">
+        <text>Assimpo::Exporter</text>
+      </name>
+      <attributes id="10" justification="0" size="4" underlined="false">
+        <text>aiScene* mScene;
+IOSystem* mIOHandler;
+struct ExportFormatEntry {
+        aiExportFormatDesc mDescription;
+        fpExportFunc mExportFunction;
+};
+</text>
+      </attributes>
+      <methods id="11" justification="0" size="4" underlined="false">
+        <text>const aiExportDataBlob* ExportToBlob(  const aiScene* pScene, ... );
+const aiExportDataBlob* ExportToBlob(  const aiScene* pScene, ...);
+aiReturn Export( const aiScene* pScene, ... );
+aiReturn Export( const aiScene* pScene,  ...);
+
+</text>
+      </methods>
+    </ClassNode>
+    <ClassNode id="12">
+      <children id="13"/>
+      <location class="Point2D.Double" id="14" x="760.0" y="120.0"/>
+      <id id="15" value="c2ac589d-2d10-4a82-b77f-df3c3232086a"/>
+      <revision>1</revision>
+      <backgroundColor id="16">
+        <red>255</red>
+        <green>255</green>
+        <blue>255</blue>
+        <alpha>255</alpha>
+      </backgroundColor>
+      <borderColor id="17">
+        <red>0</red>
+        <green>0</green>
+        <blue>0</blue>
+        <alpha>255</alpha>
+      </borderColor>
+      <textColor reference="17"/>
+      <name id="18" justification="1" size="3" underlined="false">
+        <text>IOSystem</text>
+      </name>
+      <attributes id="19" justification="0" size="4" underlined="false">
+        <text></text>
+      </attributes>
+      <methods id="20" justification="0" size="4" underlined="false">
+        <text>bool Exists( const std::string&amp; pFile) const;
+bool Exists( const char* pFile) const;
+virtual char getOsSeparator() const;
+
+virtual IOStream* Open(const char* pFile,
+        const char* pMode = &quot;rb&quot;);
+IOStream* Open(const std::string&amp; pFile, const std::string&amp; pMode = std::string(&quot;rb&quot;));
+void Close( IOStream* pFile);
+
+</text>
+      </methods>
+    </ClassNode>
+    <ClassNode id="21">
+      <children id="22"/>
+      <location class="Point2D.Double" id="23" x="760.0" y="450.0"/>
+      <id id="24" value="543d8402-9358-46ed-abd8-77935414c423"/>
+      <revision>1</revision>
+      <backgroundColor reference="7"/>
+      <borderColor reference="8"/>
+      <textColor reference="8"/>
+      <name id="25" justification="1" size="3" underlined="false">
+        <text>ObjExporter</text>
+      </name>
+      <attributes id="26" justification="0" size="4" underlined="false">
+        <text>File contains function pointer:
+ExportSceneObj</text>
+      </attributes>
+      <methods id="27" justification="0" size="4" underlined="false">
+        <text></text>
+      </methods>
+    </ClassNode>
+  </nodes>
+  <edges id="28">
+    <NoteEdge id="29">
+      <start class="ClassNode" reference="3"/>
+      <end class="ClassNode" reference="12"/>
+      <startLocation class="Point2D.Double" id="30" x="130.0" y="70.0"/>
+      <endLocation class="Point2D.Double" id="31" x="120.0" y="70.0"/>
+      <transitionPoints id="32"/>
+      <id id="33" value="32e48b3f-86c7-427a-9d3b-9fa3af2a79f7"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="34">
+      <start class="ClassNode" reference="12"/>
+      <end class="ClassNode" reference="12"/>
+      <startLocation class="Point2D.Double" id="35" x="20.0" y="70.0"/>
+      <endLocation class="Point2D.Double" reference="35"/>
+      <transitionPoints id="36"/>
+      <id id="37" value="8b7d1b44-5b84-4bdc-b723-096126d300a4"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="38">
+      <start class="ClassNode" reference="3"/>
+      <end class="ClassNode" reference="3"/>
+      <startLocation class="Point2D.Double" id="39" x="190.0" y="80.0"/>
+      <endLocation class="Point2D.Double" reference="39"/>
+      <transitionPoints id="40"/>
+      <id id="41" value="ac092bcb-c3bb-4ac7-bc77-879556396f91"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="42">
+      <start class="ClassNode" reference="12"/>
+      <end class="ClassNode" reference="12"/>
+      <startLocation class="Point2D.Double" id="43" x="370.0" y="80.0"/>
+      <endLocation class="Point2D.Double" reference="43"/>
+      <transitionPoints id="44"/>
+      <id id="45" value="3d0ad2f3-6f05-491d-b8c8-961212d7a0c9"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="46">
+      <start class="ClassNode" reference="3"/>
+      <end class="ClassNode" reference="3"/>
+      <startLocation class="Point2D.Double" id="47" x="50.0" y="40.0"/>
+      <endLocation class="Point2D.Double" reference="47"/>
+      <transitionPoints id="48"/>
+      <id id="49" value="e8d16ba4-8036-4f77-81ad-aee4e11adbfe"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="50">
+      <start class="ClassNode" reference="3"/>
+      <end class="ClassNode" reference="21"/>
+      <startLocation class="Point2D.Double" id="51" x="300.0" y="250.0"/>
+      <endLocation class="Point2D.Double" id="52" x="20.0" y="40.0"/>
+      <transitionPoints id="53"/>
+      <id id="54" value="c9fa9dbf-f219-4363-9f26-aeea21492a1f"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="55">
+      <start class="ClassNode" reference="21"/>
+      <end class="ClassNode" reference="21"/>
+      <startLocation class="Point2D.Double" id="56" x="60.0" y="90.0"/>
+      <endLocation class="Point2D.Double" reference="56"/>
+      <transitionPoints id="57"/>
+      <id id="58" value="a1addbce-8d05-4a56-9289-d885dedc75c2"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="59">
+      <start class="ClassNode" reference="21"/>
+      <end class="ClassNode" reference="21"/>
+      <startLocation class="Point2D.Double" id="60" x="60.0" y="70.0"/>
+      <endLocation class="Point2D.Double" reference="60"/>
+      <transitionPoints id="61"/>
+      <id id="62" value="2155dc70-7a87-4d23-a8f3-7798f7931872"/>
+      <revision>1</revision>
+    </NoteEdge>
+    <NoteEdge id="63">
+      <start class="ClassNode" reference="21"/>
+      <end class="ClassNode" reference="21"/>
+      <startLocation class="Point2D.Double" id="64" x="80.0" y="60.0"/>
+      <endLocation class="Point2D.Double" id="65" x="140.0" y="40.0"/>
+      <transitionPoints id="66"/>
+      <id id="67" value="5473f8fb-4b83-475c-bb59-6c60b45f5948"/>
+      <revision>1</revision>
+    </NoteEdge>
+  </edges>
+</ClassDiagramGraph>]]></SCRIPT>
+	<BR />
+	<BR />
+	<IMG alt="embedded diagram image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA88AAAHHCAIAAAAOJf3QAABkOklEQVR42uydf0hcx964CyIie2Ur
+LCIiRaRixYpXLCISgohgxUoavAFfCaGEIF+xYqUtliDekIY0vFKkSBDfN6SSG2xIkCAiQYQ0pMGK
+LYhXJIhIgwlpsGIRCSKL7PeDw5339PyYPavrqvF5/pDx7JyZz5lZd58zzpl5KwIAAEeQtwAA4LDy
+l49rvrEAAI6obdMIAACH//OZD2sAAGwbAACwbQAAwLYBALBtAADAtgEAjvPn87//A7YNAIBtAwAA
+tg0AANg2AAC2DQAA2DYAALaNbQMAYNsAAIBtAwAAtg0AgG0DAAC2DQAA2DYAALYNAADYNgAAYNsA
+ANg2AABg2wAAgG0DAGDbAACAbQMAALYNAIBtAwDA0bXtt3ZQ6enp6aqqqtQdqqur5+bm1PHV1dXm
+5ua0tLTk5GT52dDQsLCw4L+KycnJyspKOgsAsG0AADi+tv306VOR7NLS0pUdysrKRKzn5+flpfr6
+eskzMzMj6YcPH0o6Ly9vd0IPAIBtAwDAcbTtc+fOSWJiYkIdV1YtByWdnJws6Z6eHuuJxcXFcnBx
+cVHSS0tLkpYj09PTFRUVkl/EvbKycnl5OSUl5a3/IDm3t7c7OjoCO0giHA7rGG7dulVeXi6Kf+XK
+levXr6enp2dlZY2OjtLLAIBtAwDAkbftYDAoCbFhdVwS8qu4r6RFglU28eknT56oDBcvXpQjvb29
+kpafku7u7s7JyZHE2trazMyMJMrKyiJ/Hdvu6uqS9O3bt+/evatO0Rk6OzuVtQuff/75wsKCJLKz
+s+llAMC2AQDgyNt2UlKSrTT5NTk5WRLLy8sFBQV6iPrUqVOvXr169OiRpNWE7KqqKknPzc2JnSsp
+v3Hjxubmpq0KISsrS9JbW1vK5sXOdQaVX6U3NjZUWqKilwEA2wYAgCNv20qUxYPVcUnose3IzlD3
+d999984776j8J06cUKeIDb948UJ+5ubmypE7d+6oMXIhFArdvXvXZtvK6TVKpq0ZvNIAANg2AAAc
+YdtW87YfPHigjo+Pj8uvZ8+etWYOh8N9fX16zLuxsVENdau5HzrPyMjIJ598omXdKs2ZmZnW+Spm
+w8a2AQDbBgCAN8S25+fnRY6Liopevnz56tUrSQQCAbUmiaQlz9jYmKSfPHki6ZqaGkkPDQ3pUeqp
+qanIf2Z4//rrr1KIJPLz8yP/GTVXE0U6OzslffPmzbm5OUmcPHkS2wYAbBsAAN582xZmZ2erq6tT
+dqiqqpJf1fHl5eXGxkY1b0R+nj9/fmVlRY6vra2pmSF6QUCR7IaGhtTU1OTk5BMnTihZHx4elgKV
+WIfDYbUmiRypra2V/Ng2AGDbAADwxtr2rtne3l5fX8/NzZUY9EIlAACAbQMAYNtxIBgMpqSk5Ofn
+3759m44AAMC2AQCwbQAAwLYBAADbBgDAtgEAANsGAABsGwAA2wYAAGwbAACwbQAAbBsAALBtAADA
+tgEAsG0AAMC2AQAA2wYAwLYBAADbBgAAbBsAANsGAABsGwAAsG0AAGwbAACwbQAAwLYBALBtAADA
+tgEAIB6f5gAAcDjBtgEA3gTbphEAAA7n5zO2DQCAbQMAALYNAADYNgAAtg0AANg2AABg2wAA2DYA
+AGDbAACAbQMAYNsAAIBtAwAAtg0AgG0DAAC2DQAA2DYAALYNAADYNgAAYNsAANg2AABg2wAAgG0D
+AGDbAACAbQMAALYNAIBtAwAAtg0AANg2AAC2DQAA2DYAAGDbAADYNgAAYNsAAIBtAwBg2wAAgG0D
+AAC2DQBwXD7NAQDgcIJtAwC8CbZNIwAAHM7PZ2wbAADbBgAAbBsAALBtAABsGwAAsG0AAMC2AQCw
+bQAAwLYBAADbBgDAtgEAANsGAABsGwAA2wYAAGwbAACwbQAAbBsAALBtAADAtgEAsG0AAMC2AQAA
+2wYAwLYBAADbBgAAbBsAANsGAABsGwAAsG0AAGwbAACwbQAAwLYBALDtg2R7e/uoxBCXUA/D9fJ+
+AMC2AQAg/ra9R+12nv6Wg13ofnFxsbneu3fvNjU17WsTRY3BkC3WVo1LIYqJiYns7OxQKDQyMuK/
+E5395ecdIl0wPDycgLerz74AwLYBAOBY2HYcw3MlHA7n5eWtrq4mpol2kS3WRojjvxpEtaenp2dm
+ZrKysuJSu+FV6YKCggLpjoS9XQGOo20DACQYPojjbtuLi4vFxcVVVVUrKyvqoCSqq6uTk5PloJZa
+14M+bbumpmZycjKyM/J65swZa7axsTEpMykpqaio6NGjR9avFtdXhYGBgc8//9xWxdLSUmFhYTAY
+vH//vjngnp6enJwcOf7gwQM/MWjM2aQ6qSg1NfX27duGEWJzISq83Nxc27nOmOWKKisrQ6HQ9evX
+rXGmpKRsb2+/evVKtNu130dHRwOBgJyru9t8w6ATa2trtbW1EoP0pqTVwY6ODumOhPUFnwBwTG2b
+RgGAxDsixNG2W1paxM/Ehpubm9VBSQwODkri1q1bFy5cMBz0aduzs7Pl5eVSS2lp6YsXL6zZRK2k
+QEmMj48ry4z6qjifNm+NSLx4p1Sks3kF3NnZKZGI3knhfmLQmLNJMw4NDUnJ7e3thjequRBJqEJs
+B50xt7W19fb2ykFJWKtramrq7u6W2ycp37XfpSnkLGkZCTgm25b8qu9GRkbkGtVB6Yi6urrE9wUA
+tg0AgG0fGdvWY43p6ek6oYRva2srGAwaDvqft3327Nn6+vpLly7ZThRXE0EUtbJOSDC/GggEJAZb
+vWlpabYpDV4B62w+Y9CYs2VkZKjq1tfXDW9UcyGS0E8EWg86Y87MzFSNsLa2pg8uLy8XFRVlZ2cv
+Li569fvLly+dbeIcy3fadigU0q9K7Soh5UjLJ74vALBtAABs+8jYtj6oxxd3d9DcR9PT03LW5uam
+LZu4vppjIIo2MzPj59WkpCQ/742oAfuMQWPOpquIRJvrbCjE7LtRqzt58uTw8PDDhw9Pnz797Nmz
+zs7OWNvEULtVyq1dYI0kYX0BgG0DACTiMwjiYttzc3ORnUXW9OBlMBhUI5HhcFiPXLoe9G/b7e3t
+FRUV165dc80mJd+8eVM/2Gd+VWr3M7YdNeCYYoiaLTMzUwWwsbER9cvRqxD/tp2RkaEawVqdSKq6
+5N7e3nfeeUeqcPbO+vp6ZGeMWUqIybb1mLQVn2Pb+9QXANg2AAC2fQRsu6qqShKPHz/Wk3HPnz8/
+Ojoa+essW9eDPm17YWGhtLRUzKyoqMg2b7ugoGBsbEwStsm7IpFer9bX1+uH6jQNDQ2Dg4Pz8/N6
+sm/UgH3GoDFnk9ZTzwt++eWXhi9HcyH+bVuqE6WO7DynqEea5X7mu+++k8TQ0FBqampZWZl+nFGf
+rh4wlbaSE2Oy7ZaWluXlZUncuXOnvLxcHRwfH5fuSHxfAGDbAADY9pGx7cXFxcLCwtraWjXqGfnP
+8hqiONXV1dY1SZwHfc7bFiF78uSJkrNTp05ZT5yampLaxRelZKVZStdSUlK8XhWpbW1ttdW7tLSU
+n58fCoW0iEcN2GcMGnM2tWRHZmamiKZhTRJzIf5tW6qTqwsGg319fSLWuhHkrkZKlp/T09NXr17V
+Sq1Pl9aTuqQXdHf7tG1pw5qaGilcbpmePn2qDkpHuK5Jsk99gXUAtg0AgG0fMds+ioTD4dzcXPW0
+H9y5c6eysvJA+l26QDoiAetta/S4OAC2DQCAbWPb+0gC9pI85LS0tKSlpaWkpJw4cUJN8PCDbbR+
+j5w7dy4xe0lquru7+eMFbBsAANvGtgEAANsGAGwb2wYAAGwbAADbxrYBALBtAABsG9sGAABsGwCw
+bVrycH96693Lj3kMRwIaCgDbBgBsGzxte48f4z7X245V94uLi831JmBNkqgx7KX1AoGA/xZ2Nqaf
+7pP2ScyCIX4aCgCwbQDAtrHtuNl2HMNzJRwO5+Xl6U1S9ruJ4mvbtbW17e3toVBIftbU1OyxCsOr
+0j4FBQUJWAwbEwA4GNt+9uyZvhGfn5/fRTUJ+Ov1OQCzFyYnJ/1vOgAA2PaB2Pbi4mJxcXFVVdXK
+yoo6KInq6urk5GQ5aN1L0nnQp22LVsrnoSQmJibOnDljzTY2NiZlJiUlFRUVPXr0yPrh7PpqZGcv
+SbX9uJWlpaXCwsJgMHj//n1zwD09PTk5OXJc73RojsFQhWS4e/duenq6tbSpqamSkhI5kpGRcevW
+LWu9ubm5Gxsbra2tmZmZLS0tthsGyTM6OhoIBOSLQ/eFz40e1U6WUqk0td6tvaOjw3Wjx31qKLQb
+IKG2PTQ0pP8CBwcHD+3F7PdHQ2JuGwCwbdiLbYv2bW9viw03Nzerg5JQH90ii3r3PteDPm17dna2
+vLxcaiktLX3x4oU1m9ibUtLx8XGRUVshrq+KVmrz1ojEX79+XSrS2bwC7uzslEjEIKVwPzEYqnAt
+raCg4OHDh5IYHh4WqdU55ZtRci4vL1dUVMhPaZBnz57Zmk7ilDwStnRKTLYt+VXDjoyMtLe3q4PS
+SnV1dYlvKABIhG2fP39eXqqvr5efZ8+eVQenp6flI0b+VlNTU+XGXe195XrQeqMsyN+2fCqlpaVd
+uXJFPiPS09OzsrJGR0d1hrt378onmuR59eqVquvzzz+X/IFAQD4sbOLrTGjm5+fllr2kpCSy89hH
+cXGx/CoHY62lpqZGvlFSUlKsN/1SYEdHR2AHSaj/7lnz8/YCwLYPxLb1cKZ8uuqEevRta2tL+6Lr
+Qf/ztuW7QL4ULl26ZDtRdLCpqUnszTrnwfyqfIpKDLZ65dPYNmvCK2CdzWcMhipcS/Nq56hPE0oe
+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
+F4lyXafVvJiVfjUSbZ9g57YMkb9O/zMsrqUxZ3Ndq8pJ1IW8DJ0etTq5xRoeHn748OHp06efPXum
+tsWIqU3MN3jOfvFzc0VHxNQRIrWvXr1SDxy7Vm39V4BrkH66aRdtchga1uuKvD6RrIW43vAb8mDb
+AIBtH3fb3sWKUq7fba5rKPlfoMmPbZsXiVpfX1c3BiIZhpBca5QrNYxt65Vq5bir39si91pcy4ZX
+Nte1qrzwKsS/i0hzqWu3Vqen7Mtd1jvvvCNVOJvR2eA+bdu1X5zQEXvsiDNnzpw/f76hocHW+M42
+dL1SQzf52WzkkDes9U/e8PkwNzenYrCO9FuHIRjbBgBsG6Krzy5WlNKrRVm/C1zXUPK/QJMf2zYv
+EqWeeRIF7+joMITkWmN9fb1+pkrsRAqZn5/XU0VFWdS8R9t0YWc55sW1NOZsrmtVOTEX4t9FpDox
+ucjOY156wK+iouK7776TxNDQkHSi3DXZnpNzbXD/87ad/eKEjthjR/T19Ykj9vT0WGtxbUPXK/XZ
+Tbtok8PQsNY/eYNtV1VVSeLx48euDxiMj49LOc40tg0A2Da2bf9SiXVFKb1alLUQ1zWU/C/QFPH3
+IL9hkSj5/paoTp06pYb6IrEs6yTntra2qvTS0lJ+fr5oiv4yVksoSDlyv2FdCsNZjnlxLY05m3mt
+Kp91+XcRqU6uTvWRXgdNGqG0tFRKlp/T09NXr17VJmdocJ+2HbVf6Ii4dMSvv/4qCbVipnVNEmcb
+ul6pazf55PA3rPVP3mDbi4uLEoNEq9vWipSg1yGxphO0JsledvpJ8C5BB7Ip0e4qZWMqwLax7Tja
+NtdlJRwO5+bm6tuJ48mdO3cqKysP6o3EEluHpCOOScPu/U9ezpUS1JQYa3ovb+bYbHsv24w5z/U5
+PWiP1e1fFf4rjWOr3rhxY++z9QGwbaz0qGAbs9wF+7eX5CGnpaUlLS1NGvDEiRNq5kBiGtwGS2wd
+ko44Pg27xz/5c+fO6f0jrem9vJljs+29fJqbn0Hevy+eRH4D7a7SmDLLuyrWtegBsG1sGwAADsk3
+3Vt72enHmrbtFOU6xOv63VBTUzM5OSmJiYkJtbWP63ZKhn2nJCpbqM5azKdHou2IFnHbRy1qpRG3
+zZBcW1WaTq08Lz9tI9+xLtYDgG1j2wAAcBhtexc7/VjTzp2ifI5tyynl5eVScmlpqTJO1+2UvPad
+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
+2hoOh9PS0nYto1KmWUbNY9u7s+1DfoHO/P6DAcC2AQAADsa2P//8c0kMDg52dHQYFG1hYaG0tFQc
+saioSE9rdp57/vz50dHRiGMmsS4nOTlZTfNwrUU92CcGKQWaZbShoUHqnZ+fd523vQvbPvwX6Cw5
+ajDYNmDbAAAAB2zbAwMDKSkpp06dUuO4EY9pzfX19U+ePJHE+Pi4ZPY6d2VlpaqqSrywurraukqG
+rlokUk7xEkH1YF9aWtqNGzfMMrq0tJSfnx8KhZxLGfqx7aN4gc6SowZzGNZbBGwbAADg2Nm2q4wm
+8tyj0u5vzLXokW8AbBsAACBxtq3GShN/7pHgTbrA7u5u/pAA2wYAAEi0bQMAYNsAAMAXH7YNANg2
+AAAAtg0A2DYAAAC2DQCAbQMAAGDbAIBtAwAAJMS2k5OTb926RYsAALYNAAAQf9ve2NgoKSmhRQAA
+2wYAAIi/bUd2hrf1UZoGALBtAACAeNp2UlISLQIA2DYAAMC+2HZ5efmTJ09oFADAtgEAAOJv27/+
++mtaWhqNAgDYNgAAQPxtu7i4mLFtAMC2AQAA9sW2eTgSALBtAACAfbdttBsAsG0AAIB42vbq6mpq
+aqpKX7hwgaYBAGwbAAAgbradkpJy/fp1le7u7qZpAADbBgAAiJttAwBg2wAAANg2AGDbAAAA2DYA
+ALYNAADYNq0AANg2AAAAtg0A2DYAAAC2DQCAbQMAAGDbAIBtAwAAYNsAgG0DAABg2wAA2DYAAAC2
+DQDYNgAAALYNANg2AAAAtg0AgG0DAABg2wCAbQMAACTOtgEAEgm2DQAAx8u2aQUASOSHDrYNAADY
+NgAAtg0AAIBtAwC2DQAAgG0DAGDbAACAbQMAYNsAAADYNgBg2wAAANg2AAC2DQAA2DYAALYNAACA
+bQMAtg0AAIBtAwBg2wAAgG0DAGDbAAAA2DYAYNsAAADYNgAAtg0AAIBtAwC2DQAAgG0DALYNAACA
+bQMAYNsAAADYNgBg2wAAANg2AGDbAAAA2DYAALYNAACAbQMAtg0AAHDEbXt7e/vwXOeugzlUV/Fm
+9xEXi20DAABg2zFQXFzsM4L/C+Wv7Ecw1vKTk5MfPHiwl6uwFlVSUjI9PW27KPMl2wgEAoYq9q9Z
+3nIjMZd89+7dpqamxLzXY31DLi8v19TUpKSkSL+0trZubGzsX2yuXe9KIqOKFenK4eFhbBsAACBB
+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
+e/asdlk9/BwMBqPa9traWkZGRk5OTnp6eiAQePnypc65vr6uygmFQhHLWLU6aB2rdrXtzMxM64wX
+ZwbAtgGwbQAAOHS2PT8/n5aWVlRUJGb86tUrSYglW9ck+fLLL4eGhiTR3Nwc1bbb2trkoOTv7++3
+TfVub2+/c+eOJFpaWuRgd3e3muGt5m1fvXrVWaYad1dLr3R2dkr65s2bc3Nzkjh58iS2jW0DYNsA
+AHDYbVuYnZ2trq5O2aGqqkp+1UUJ9+/fD4VCZWVlKysrEcesDytq+RHJqU4vKSmRX2dmZtSrfX19
+qampUr56ojEcDovHqzVGurq6rDXqwIaHhyUkJdaSX61JIkdqa2uto+Z0OrYNgG0DAMDhtW3/qFkf
+eXl5sYaEE2PbAIBtAwBg21GoqqpKS0sbGxuL6Sw1ak7XYNsAgG0DAGDbgG0DALYNAADYNmDbANg2
+AABg24BtAwC2DQCAbQO2DQDYNgAAYNuAbQNg2wAAgG0Dtg0A2DYAALYN2DYAYNsAAIBtA7YNgG0D
+AAC2Ddg2AGDbAADYNmDbAIBtAwAAtg3YNgC2DQAA2DZg2wCAbQMAYNuAbQMAtg0AALEbFYAX2DYA
+tg0AAHu1bRoBvN4b2DYAtg0AANg2YNsA2DYAAGDbgG0DALYNAIBtA2DbANg2AABg24BtA2DbAACA
+bQO2DQDYNgAAtg2AbQNg2wAAgG0Dtg2AbQMAALYN2DYAYNsAANg2ALYNgG0DAAC2Ddg2ALYNAADY
+NmDbAIBtAwBgVDQCYNsA2DYAAGDbgG0DYNsAAIBtA7YNANg2AABg24BtA2DbAABwLGx7e3v7MDfU
+oQovMcFg2wDYNgAAxM223/orzlf3O5Li4uJ9uisYGxtLSUlpbW2NS3iJuT8x12JuK2wbANsGAIDD
+aNv7JLtx8cu9kJyc/ODBg0Mb3qENBtsGwLYBAGB/bdv56traWm1trfhrTU2NpG35l5aWCgsLg8Hg
+/fv31ZGVlZXq6mrJX1VVtbq6qkvr6enJycnRHmwdU///7d1RZJX/H8DxPzPHzGTMZLr46SZzzExk
+usjMmMkkMzJdJWOSmS4iXSRJdNFFkkhmMt0kmUkiSZJuZv8kMyOTLiaRTGZm/48evh7nnJ3f+Wmt
++v1fr4uf757zPd/nec7Zj3ePZ+e8evWqq6srHmptbZ2amio/kpLnbn6/eh0/1tXVdXR0PHv2rOQU
+0sr5c6y+YMmJVFykxlMrOZiZmZnGxsaenp54evV1anmtKr4d2VP27t37g12utkFtA7DTtT02Nvbh
+w4cYPHz4cHx8vGT+8PDwjRs35ufns9QLo6Ojk5OTMYhuPnnyZFrt7NmzGxsbkY9RiiW7aG9vf/r0
+aQzu378fvVt+JOXPjUHW5Y8fP067rn6O1RcsP5HyRWo/tfxOY2Y8Gk+MV7L6OrW8VhXfjnh0enr6
+x+/tVtugtgHYztouuWm7YmK2tLSkR3fv3l2yWlNT0/r6en5Lc3Nzln1ra2v5dE7T/mnuV3zu4cOH
+R0ZGIrVL9l5jbZcvWH4i5YvUfmr5RT5+/FjylK3WqeW1qvh2xKPb8meUahvUNgDbWds1xm5SV1e3
+1fyKW8ovzVbcxadPny5dunTs2LH29vbqf6+Zf0p2M0ZU8tzc3D+t7VpejepHUv3Uan81yjdWP7yK
+b8d23dWttkFtA7DTtZ0uvlZUfkk45mfXWWN7PFpLQR44cODy5cszMzPv37+vsbYzsaM7d+60tbX9
+7Vmsra1VX7CWa9u1n1p+y5cvX7IDaG1trWWd6q9VxbdDbYPaBuBPre2xsbHl5eUY3Lt3r7u7u2T+
+0NDQ5OTk27dv0+3OJ06ciG7e3OKm5Py4vr7+69evMWhoaFhYWIgeHR8fr7G229vbZ2dnY7DV3dJp
+FzEh0nZiYqL6guUnkg4vzan91PJbzpw5E4NYPI6hlnWqv1YV3w61DWobgD+1tj99+tTf3x+119HR
+8e7du5L5S0tL+/bta2lpSR/HsbKy0tvbG/P7+vrKP3CjJHALhcLm9z/4i3retWvX9evXa6ztV69e
+FYvFurq62FGW3RXPImvxpqam27dvV1+w/ETS4eU/k6TGU8tvuXXrVqxz5MiR7CL3365T/bWq+HZU
+Pwa1DWobgF9Q23i11TaobQDU9h8suyCttgG1DaC28buhtkFtA6C2UdugtgFQ26htQG0DqG1Q26C2
+AfhzantbvkgctQ1qG4A/tbb/U2Yb99LZ2ZkNlpeX+/v7C4VCY2PjqVOnsq9o+UkePXrU0dFRX18f
+e3/69Gn1f2C4xq+2QW0D8HNrewf20t3dffPmzY2NjbW1tfPnz58+ffon7XFubm7Pnj3Pnz+PcaR2
+W1vb/Py8sFbboLYB+I1qu7+//+XLlzF48uTJ8PBwNm1mZqaxsbGnp2dlZSWbFoO+vr76+vre3t78
+tyFevXp17969+YvlMSd/V0lTU1M2WFpaKhaLu3btevDgQbbl8+fPAwMDMT+OIcb5Nf/666/sO9ir
+zDx27Njdu3fTju7cuTMyMpIWWVxc7OzsjKNNpyDB1TaobQB2urbn5+e7u7ujj/fv3//hw4ds2smT
+J2PL5OTk2NhYNm10dDR+jMHU1FQ8mhacnp7O2jotfvTo0XPnzsX2km99j5S/ceNG7C7qPNsSi2d7
+fPjw4fj4eFrz7NmzsWb2HexVZka4f/v2La2/urqayj4WiafEIvEPiThyta22QW0DsBO1XfG+7ePH
+jw8ODl64cCFN+/jxYwzW1taiaLONzc3NWVXnN8bMdBk7rfb58+fI8UOHDtXV1bW3t6e7OyKF19fX
+8wfW0tKSxrt3707rpGlpza1mlpxpqvN4KF2AjyNX22ob1DYAO1HbFSe8fv06OjVdJ85Py/dr9Y3l
+i0eXX7t2rVgsbjUh3/2R5lXWrDgzoj92kSbH8eevbVc/WtQ2qG0Adqi2x8fHDx48eOXKlTTty5cv
+WS63tramtM0uY6+vr1eM2jSOR/P3bRcKhbS95Np2ukZe8Wjz44ozR0ZGpqam0o+Tk5P5+7bfvHmz
++f1zCdN1cbWttkFtA7DTtb2wsLB///4I646OjnTf9pkzZ7J+nZiYyKadOHFiZmZms+y+7bROfX19
+9mF/p0+fvnjxYvR6lG4UfF9fXzZhaGgoFnz79m3+vu3l5eUY3Lt3r7u7u0ptV5wZPd3W1vbixYsY
+x39jPDc3l57Y29sbg+fPn+fvCPfLoLZBbQPwE2u7/L7twcHBLFgfP3585MiRbNqtW7cKhUL8mF3k
+3vz+mSTRr5HUUc/5zyRJe4mYzi5jr66uRnA3NjbGj4cPH85uAd/8/pkk+/bta2lpSZ80Euv09/fH
+mhH66U8qK9Z2xZnh2bNnnZ2dsb2rqyvG+ScuLi4Wi8WBgYF0CmpbbYPaBuAn1vZPmv/7W19fn52d
+TTdwo7ZBbQPwy2o73Wn9r3H37t2GhoZ0TR21DWobgF9W26htQG0DoLZR26C2AVDbqG1AbQOobdQ2
+oLYBUNuobVDbAKht1DagtgHUNmrbqwFqGwC1jdoGtQ2A2kZtA2obQG2jttU2qG0A1DZqG9Q2AGob
+tQ2obQC1DWob1DYAahu1DWobALWN2gbUNsD/YVHBVtQ2qG0AfrS2vQhs9buhtkFtA6C2UdugtgFQ
+26htQG0DqG1Q26C2AVDbqG1Q2wCobdQ2oLYB1DaobVDbAKht1DaobQDUNmobUNsAahvUNqhtANQ2
+ahvUNgBqG7UNqG0AReVFQG2D2gZAbaO2QW0DoLZR24DaBkBto7ZBbQOgtlHboLYBUNuobUBtA6C2
+UdugtgHYiaKCrahtUNsAbJv/whb83wFqGwC1jdoGtQ2A2kZtA2obAAB+E/8DOiU+nN21u+YAAAAA
+SUVORK5C" />
+</BODY>
+</HTML>

+ 107 - 0
doc/architecture/assimp.object.violet.html

@@ -0,0 +1,107 @@
+<HTML>
+<HEAD>
+<META name="description"
+	content="Violet UML Editor cross format document" />
+<META name="keywords" content="Violet, UML" />
+<META charset="UTF-8" />
+<SCRIPT type="text/javascript">
+	function switchVisibility() {
+		var obj = document.getElementById("content");
+		obj.style.display = (obj.style.display == "block") ? "none" : "block";
+	}
+</SCRIPT>
+</HEAD>
+<BODY>
+	This file was generated with Violet UML Editor 2.1.0.
+	&nbsp;&nbsp;(&nbsp;<A href=# onclick="switchVisibility()">View Source</A>&nbsp;/&nbsp;<A href="http://sourceforge.net/projects/violet/files/violetumleditor/" target="_blank">Download Violet</A>&nbsp;)
+	<BR />
+	<BR />
+	<SCRIPT id="content" type="text/xml"><![CDATA[<ObjectDiagramGraph id="1">
+  <nodes id="2">
+    <ObjectNode id="3">
+      <children id="4"/>
+      <location class="Point2D.Double" id="5" x="410.0" y="40.0"/>
+      <id id="6" value="72a7fa39-c47c-4be4-8616-28e53dd941c9"/>
+      <revision>1</revision>
+      <backgroundColor id="7">
+        <red>255</red>
+        <green>255</green>
+        <blue>255</blue>
+        <alpha>255</alpha>
+      </backgroundColor>
+      <borderColor id="8">
+        <red>0</red>
+        <green>0</green>
+        <blue>0</blue>
+        <alpha>255</alpha>
+      </borderColor>
+      <textColor reference="8"/>
+      <name id="9" justification="1" size="3" underlined="true">
+        <text>Importer</text>
+      </name>
+    </ObjectNode>
+    <ObjectNode id="10">
+      <children id="11"/>
+      <location class="Point2D.Double" id="12" x="410.0" y="140.0"/>
+      <id id="13" value="84358792-4b76-43e5-8e54-e861f8d058cf"/>
+      <revision>1</revision>
+      <backgroundColor reference="7"/>
+      <borderColor reference="8"/>
+      <textColor reference="8"/>
+      <name id="14" justification="1" size="3" underlined="true">
+        <text>Raw data format</text>
+      </name>
+    </ObjectNode>
+    <ObjectNode id="15">
+      <children id="16"/>
+      <location class="Point2D.Double" id="17" x="410.0" y="240.0"/>
+      <id id="18" value="00422f37-250b-4969-91a6-48bcd052e792"/>
+      <revision>1</revision>
+      <backgroundColor reference="7"/>
+      <borderColor reference="8"/>
+      <textColor reference="8"/>
+      <name id="19" justification="1" size="3" underlined="true">
+        <text>Postproce</text>
+      </name>
+    </ObjectNode>
+  </nodes>
+  <edges id="20"/>
+</ObjectDiagramGraph>]]></SCRIPT>
+	<BR />
+	<BR />
+	<IMG alt="embedded diagram image" src="data:image/png;base64,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" />
+</BODY>
+</HTML>

+ 2 - 1
include/assimp/IOSystem.hpp

@@ -67,7 +67,8 @@ class IOStream;
  *  to the importer library. If you implement this interface, you also want to
  *  to the importer library. If you implement this interface, you also want to
  *  supply a custom implementation for IOStream.
  *  supply a custom implementation for IOStream.
  *
  *
- *  @see Importer::SetIOHandler() */
+ *  @see Importer::SetIOHandler() 
+ */
 class ASSIMP_API IOSystem
 class ASSIMP_API IOSystem
 #ifndef SWIG
 #ifndef SWIG
     : public Intern::AllocateFromAssimpHeap
     : public Intern::AllocateFromAssimpHeap

+ 0 - 2
include/assimp/anim.h

@@ -255,7 +255,6 @@ struct aiNodeAnim
      * scaling and one position key. */
      * scaling and one position key. */
     C_STRUCT aiQuatKey* mRotationKeys;
     C_STRUCT aiQuatKey* mRotationKeys;
 
 
-
     /** The number of scaling keys */
     /** The number of scaling keys */
     unsigned int mNumScalingKeys;
     unsigned int mNumScalingKeys;
 
 
@@ -266,7 +265,6 @@ struct aiNodeAnim
      * position and one rotation key.*/
      * position and one rotation key.*/
     C_STRUCT aiVectorKey* mScalingKeys;
     C_STRUCT aiVectorKey* mScalingKeys;
 
 
-
     /** Defines how the animation behaves before the first
     /** Defines how the animation behaves before the first
      *  key is encountered.
      *  key is encountered.
      *
      *

+ 20 - 27
include/assimp/scene.h

@@ -60,9 +60,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
-/** A node in the imported hierarchy.
+/** 
+ * A node in the imported hierarchy.
  *
  *
  * Each node has name, a parent node (except for the root node),
  * Each node has name, a parent node (except for the root node),
  * a transformation relative to its parent and possibly several child nodes.
  * a transformation relative to its parent and possibly several child nodes.
@@ -278,7 +278,6 @@ struct aiNode
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct aiScene
 struct aiScene
 {
 {
-
     /** Any combination of the AI_SCENE_FLAGS_XXX flags. By default
     /** Any combination of the AI_SCENE_FLAGS_XXX flags. By default
     * this value is 0, no flags are set. Most applications will
     * this value is 0, no flags are set. Most applications will
     * want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE
     * want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE
@@ -286,7 +285,6 @@ struct aiScene
     */
     */
     unsigned int mFlags;
     unsigned int mFlags;
 
 
-
     /** The root node of the hierarchy.
     /** The root node of the hierarchy.
     *
     *
     * There will always be at least the root node if the import
     * There will always be at least the root node if the import
@@ -296,8 +294,6 @@ struct aiScene
     */
     */
     C_STRUCT aiNode* mRootNode;
     C_STRUCT aiNode* mRootNode;
 
 
-
-
     /** The number of meshes in the scene. */
     /** The number of meshes in the scene. */
     unsigned int mNumMeshes;
     unsigned int mNumMeshes;
 
 
@@ -310,8 +306,6 @@ struct aiScene
     */
     */
     C_STRUCT aiMesh** mMeshes;
     C_STRUCT aiMesh** mMeshes;
 
 
-
-
     /** The number of materials in the scene. */
     /** The number of materials in the scene. */
     unsigned int mNumMaterials;
     unsigned int mNumMaterials;
 
 
@@ -324,8 +318,6 @@ struct aiScene
     */
     */
     C_STRUCT aiMaterial** mMaterials;
     C_STRUCT aiMaterial** mMaterials;
 
 
-
-
     /** The number of animations in the scene. */
     /** The number of animations in the scene. */
     unsigned int mNumAnimations;
     unsigned int mNumAnimations;
 
 
@@ -336,8 +328,6 @@ struct aiScene
     */
     */
     C_STRUCT aiAnimation** mAnimations;
     C_STRUCT aiAnimation** mAnimations;
 
 
-
-
     /** The number of textures embedded into the file */
     /** The number of textures embedded into the file */
     unsigned int mNumTextures;
     unsigned int mNumTextures;
 
 
@@ -349,7 +339,6 @@ struct aiScene
     */
     */
     C_STRUCT aiTexture** mTextures;
     C_STRUCT aiTexture** mTextures;
 
 
-
     /** The number of light sources in the scene. Light sources
     /** The number of light sources in the scene. Light sources
     * are fully optional, in most cases this attribute will be 0
     * are fully optional, in most cases this attribute will be 0
         */
         */
@@ -362,7 +351,6 @@ struct aiScene
     */
     */
     C_STRUCT aiLight** mLights;
     C_STRUCT aiLight** mLights;
 
 
-
     /** The number of cameras in the scene. Cameras
     /** The number of cameras in the scene. Cameras
     * are fully optional, in most cases this attribute will be 0
     * are fully optional, in most cases this attribute will be 0
         */
         */
@@ -387,33 +375,38 @@ struct aiScene
 
 
     //! Check whether the scene contains meshes
     //! Check whether the scene contains meshes
     //! Unless no special scene flags are set this will always be true.
     //! Unless no special scene flags are set this will always be true.
-    inline bool HasMeshes() const
-        { return mMeshes != NULL && mNumMeshes > 0; }
+    inline bool HasMeshes() const { 
+        return mMeshes != NULL && mNumMeshes > 0; 
+    }
 
 
     //! Check whether the scene contains materials
     //! Check whether the scene contains materials
     //! Unless no special scene flags are set this will always be true.
     //! Unless no special scene flags are set this will always be true.
-    inline bool HasMaterials() const
-        { return mMaterials != NULL && mNumMaterials > 0; }
+    inline bool HasMaterials() const { 
+        return mMaterials != NULL && mNumMaterials > 0; 
+    }
 
 
     //! Check whether the scene contains lights
     //! Check whether the scene contains lights
-    inline bool HasLights() const
-        { return mLights != NULL && mNumLights > 0; }
+    inline bool HasLights() const { 
+        return mLights != NULL && mNumLights > 0; 
+    }
 
 
     //! Check whether the scene contains textures
     //! Check whether the scene contains textures
-    inline bool HasTextures() const
-        { return mTextures != NULL && mNumTextures > 0; }
+    inline bool HasTextures() const {
+        return mTextures != NULL && mNumTextures > 0; 
+    }
 
 
     //! Check whether the scene contains cameras
     //! Check whether the scene contains cameras
-    inline bool HasCameras() const
-        { return mCameras != NULL && mNumCameras > 0; }
+    inline bool HasCameras() const {
+        return mCameras != NULL && mNumCameras > 0; 
+    }
 
 
     //! Check whether the scene contains animations
     //! Check whether the scene contains animations
-    inline bool HasAnimations() const
-        { return mAnimations != NULL && mNumAnimations > 0; }
+    inline bool HasAnimations() const { 
+        return mAnimations != NULL && mNumAnimations > 0; 
+    }
 
 
 #endif // __cplusplus
 #endif // __cplusplus
 
 
-
     /**  Internal data, do not touch */
     /**  Internal data, do not touch */
 #ifdef __cplusplus
 #ifdef __cplusplus
     void* mPrivate;
     void* mPrivate;

+ 254 - 0
test/unit/ModelDiffer.cpp

@@ -0,0 +1,254 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "ModelDiffer.h"
+#include <assimp/scene.h>
+#include <sstream>
+
+using namespace Assimp;
+
+ModelDiffer::ModelDiffer() {
+    // empty
+}
+
+ModelDiffer::~ModelDiffer() {
+    // empty
+}
+
+bool ModelDiffer::isEqual( aiScene *expected, aiScene *toCompare ) {
+    if ( expected == toCompare ) {
+        return true;
+    }
+
+    if ( nullptr == expected ) {
+        return false;
+    }
+
+    if ( nullptr == toCompare ) {
+        return false;
+    }
+
+    if ( expected->mNumMeshes != toCompare->mNumMeshes ) {
+        std::stringstream stream;
+        stream << "Number of meshes not equal ( expected: " << expected->mNumMeshes << ", found : " << toCompare->mNumMeshes << " )\n";
+        addDiff( stream.str() );
+    }
+
+    for ( unsigned int i = 0; i < expected->mNumMeshes; i++ ) {
+        aiMesh *expMesh( expected->mMeshes[ i ] );
+        aiMesh *toCompMesh( toCompare->mMeshes[ i ] );
+        compareMesh( expMesh, toCompMesh );
+    }
+}
+
+void ModelDiffer::showReport() {
+    if ( m_diffs.empty() ) {
+        return;
+    }
+    
+    for ( std::vector<std::string>::iterator it = m_diffs.begin(); it != m_diffs.end(); it++ ) {
+        std::cout << *it << "\n";
+    }
+
+    std::cout << std::endl;
+}
+
+void ModelDiffer::reset() {
+    m_diffs.resize( 0 );
+}
+
+void ModelDiffer::addDiff( const std::string &diff ) {
+    if ( diff.empty() ) {
+        return;
+    }
+    m_diffs.push_back( diff );
+}
+
+static std::string dumpVector3( const aiVector3D &toDump ) {
+    std::stringstream stream;
+    stream << "( " << toDump.x << ", " << toDump.y << ", " << toDump.z << ")";
+    return stream.str();
+}
+
+static std::string dumpColor4D( const aiColor4D &toDump ) {
+    std::stringstream stream;
+    stream << "( " << toDump.r << ", " << toDump.g << ", " << toDump.b << ", " << toDump.a << ")";
+    return stream.str();
+}
+
+bool ModelDiffer::compareMesh( aiMesh *expected, aiMesh *toCompare ) {
+    if ( expected == toCompare ) {
+        return true;
+    }
+
+    if ( nullptr == expected || nullptr == toCompare ) {
+        return false;
+    }
+
+    if ( expected->mName != toCompare->mName ) {
+        std::stringstream stream;
+        stream << "Mesh name not equal ( expected: " << expected->mName.C_Str() << ", found : " << toCompare->mName.C_Str() << " )\n";
+        addDiff( stream.str() );
+    }
+
+    if ( expected->mNumVertices != toCompare->mNumVertices ) {
+        std::stringstream stream;
+        stream << "Number of vertices not equal ( expected: " << expected->mNumVertices << ", found : " << toCompare->mNumVertices << " )\n";
+        addDiff( stream.str() );
+        return false;
+    }
+
+    // positions
+    if ( expected->HasPositions() != toCompare->HasPositions() ) {
+        addDiff( "Expected are vertices, toCompare does not have any." );
+        return false;
+    }
+
+    bool vertEqual( true );
+    for ( unsigned int i = 0; i < expected->mNumVertices; i++ ) {
+        aiVector3D &expVert( expected->mVertices[ i ] );
+        aiVector3D &toCompVert( toCompare->mVertices[ i ] );
+        if ( expVert != toCompVert ) {
+            std::stringstream stream;
+            stream << "Vertex not equal ( expected: " << dumpVector3( expVert ) << ", found: " << dumpVector3( toCompVert ) << "\n";
+            addDiff( stream.str() );
+            vertEqual = false;
+        }
+    }
+    if ( !vertEqual ) {
+        return false;
+    }
+
+    // normals
+    if ( expected->HasNormals() != toCompare->HasNormals() ) {
+        addDiff( "Expected are normals, toCompare does not have any." );
+        return false;
+    }
+
+    bool normalEqual( true );
+    for ( unsigned int i = 0; i < expected->mNumVertices; i++ ) {
+        aiVector3D &expNormal( expected->mNormals[ i ] );
+        aiVector3D &toCompNormal( toCompare->mNormals[ i ] );
+        if ( expNormal != toCompNormal ) {
+            std::stringstream stream;
+            stream << "Normal not equal ( expected: " << dumpVector3( expNormal ) << ", found: " << dumpVector3( toCompNormal ) << "\n";
+            addDiff( stream.str() );
+            normalEqual = false;
+        }
+    }
+    if ( !normalEqual ) {
+        return false;
+    }
+
+    // vertex colors
+    bool vertColEqual( true );
+    for ( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++ ) {
+        if ( expected->HasVertexColors(a) != toCompare->HasVertexColors(a) ) {
+            addDiff( "Expected are normals, toCompare does not have any." );
+            return false;
+        }
+        for ( unsigned int i = 0; i < expected->mNumVertices; i++ ) {
+            aiColor4D &expColor4D( expected->mColors[ a ][ i ] );
+            aiColor4D &toCompColor4D( toCompare->mColors[ a ][ i ] );
+            if ( expColor4D != toCompColor4D ) {
+                std::stringstream stream;
+                stream << "Color4D not equal ( expected: " << dumpColor4D( expColor4D ) << ", found: " << dumpColor4D( toCompColor4D ) << "\n";
+                addDiff( stream.str() );
+                vertColEqual = false;
+            }
+        }
+        if ( !vertColEqual ) {
+            return false;
+        }
+    }
+
+    // texture coords
+    bool texCoordsEqual( true );
+    for ( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++ ) {
+        if ( expected->HasTextureCoords( a ) != toCompare->HasTextureCoords( a ) ) {
+            addDiff( "Expected are texture coords, toCompare does not have any." );
+            return false;
+        }
+        for ( unsigned int i = 0; i < expected->mNumVertices; i++ ) {
+            aiVector3D &expTexCoord( expected->mTextureCoords[ a ][ i ] );
+            aiVector3D &toCompTexCoord( toCompare->mTextureCoords[ a ][ i ] );
+            if ( expTexCoord != toCompTexCoord ) {
+                std::stringstream stream;
+                stream << "Texture coords not equal ( expected: " << dumpVector3( expTexCoord ) << ", found: " << dumpVector3( toCompTexCoord ) << "\n";
+                addDiff( stream.str() );
+                vertColEqual = false;
+            }
+        }
+        if ( !vertColEqual ) {
+            return false;
+        }
+    }
+
+    // tangents and bi-tangents
+    if ( expected->HasTangentsAndBitangents() != toCompare->HasTangentsAndBitangents() ) {
+        addDiff( "Expected are tangents and bi-tangents, toCompare does not have any." );
+        return false;
+    }
+    bool tangentsEqual( true );
+    for ( unsigned int i = 0; i < expected->mNumVertices; i++ ) {
+        aiVector3D &expTangents( expected->mTangents[ i ] );
+        aiVector3D &toCompTangents( toCompare->mTangents[ i ] );
+        if ( expTangents != toCompTangents ) {
+            std::stringstream stream;
+            stream << "Tangents not equal ( expected: " << dumpVector3( expTangents ) << ", found: " << dumpVector3( toCompTangents ) << "\n";
+            addDiff( stream.str() );
+            tangentsEqual = false;
+        }
+
+        aiVector3D &expBiTangents( expected->mBitangents[ i ] );
+        aiVector3D &toCompBiTangents( toCompare->mBitangents[ i ] );
+        if ( expBiTangents != toCompBiTangents ) {
+            std::stringstream stream;
+            stream << "Tangents not equal ( expected: " << dumpVector3( expBiTangents ) << ", found: " << dumpVector3( toCompBiTangents ) << "\n";
+            addDiff( stream.str() );
+            tangentsEqual = false;
+        }
+    }
+    if ( !tangentsEqual ) {
+        return false;
+    }
+
+    return true;
+}

+ 65 - 0
test/unit/ModelDiffer.h

@@ -0,0 +1,65 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#pragma once
+
+#include "UnitTestPCH.h"
+#include <fast_atof.h>
+#include <vector>
+#include <string>
+
+struct aiScene;
+struct aiMesh;
+
+class ModelDiffer {
+public:
+    ModelDiffer();
+    ~ModelDiffer();
+    bool isEqual( aiScene *expected, aiScene *toCompare );
+    void showReport();
+    void reset();
+
+private:
+    void addDiff( const std::string &diff );
+    bool compareMesh( aiMesh *expected, aiMesh *toCompare );
+
+private:
+    std::vector<std::string> m_diffs;
+};