diff --git a/cmake-modules/FindRT.cmake b/cmake-modules/FindRT.cmake new file mode 100644 index 000000000..17d5df81d --- /dev/null +++ b/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) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 8b3d23773..b1e0256ca 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -699,7 +699,54 @@ SET ( 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" ) # VC2010 fixes if(MSVC10) @@ -746,6 +793,7 @@ SET( assimp_src ${Poly2Tri_SRCS} ${Clipper_SRCS} ${openddl_parser_SRCS} + ${open3dgc_SRCS} # Necessary to show the headers in the project when using the VC++ generator: ${PUBLIC_HEADERS} @@ -820,6 +868,11 @@ else (UNZIP_FOUND) INCLUDE_DIRECTORIES("../") 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 LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 6d5ac1a71..f09e97902 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -361,8 +362,6 @@ namespace glTF { return id; } }; - - // // Classes for each glTF top-level object type // @@ -451,32 +450,115 @@ namespace glTF //! A buffer points to binary geometry, animation, or skins. struct Buffer : public Object - { - public: + { + /********************* Types *********************/ + public: - enum Type - { - Type_arraybuffer, - Type_text - }; + 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") + /// \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. - Type type; + /// \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) + {} - private: - shared_ptr mData; //!< Pointer to the data - bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) + /// \fn ~SEncodedRegion() + /// Destructor. + ~SEncodedRegion() { delete [] DecodedData; } + }; - public: - Buffer(); + /******************* Variables *******************/ - void Read(Value& obj, Asset& r); + //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 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 EncodedRegion_List; + + /******************* Functions *******************/ + + public: + + Buffer(); + ~Buffer(); + + void Read(Value& obj, Asset& r); 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); void Grow(size_t amount); @@ -492,7 +574,6 @@ namespace glTF static const char* TranslateId(Asset& r, const char* id); }; - //! A view into a buffer generally representing a subset of the buffer. struct BufferView : public Object { @@ -502,11 +583,9 @@ namespace glTF BufferViewTarget target; //! The target that the WebGL buffer should be bound to. - BufferView() {} void Read(Value& obj, Asset& r); }; - struct Camera : public Object { enum Type @@ -631,10 +710,77 @@ namespace glTF Ref 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 primitives; + std::list Extension;///< List of extensions used in mesh. Mesh() {} - void Read(Value& obj, Asset& r); + + /// \fn ~Mesh() + /// Destructor. + ~Mesh() { for(std::list::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 @@ -805,6 +951,7 @@ namespace glTF Ref Get(const char* id); Ref Get(unsigned int i); + Ref Get(const std::string& pID) { return Get(pID.c_str()); } Ref Create(const char* id); Ref Create(const std::string& id) diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 470246c94..b9f3fccd8 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -40,6 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StringUtils.h" +// Header files, Assimp +#include + +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + // Header files, Open3DGC. +# include +#endif + using namespace Assimp; namespace glTF { @@ -243,9 +251,14 @@ Ref LazyDict::Create(const char* id) 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) { // Compatibility with old spec @@ -326,6 +339,79 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO 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) { size_t offset = this->byteLength; @@ -343,6 +429,9 @@ inline void Buffer::Grow(size_t amount) byteLength += amount; } +// +// struct BufferView +// 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); } - +// +// struct Accessor +// inline void Accessor::Read(Value& obj, Asset& r) { @@ -395,7 +486,18 @@ inline uint8_t* Accessor::GetPointer() if (!basePtr) return 0; 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 { @@ -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()); for (unsigned int i = 0; i < primitives->Size(); ++i) { Value& primitive = (*primitives)[i]; @@ -700,22 +803,250 @@ inline void Mesh::Read(Value& obj, Asset& r) if (GetAttribVector(prim, attr, vec, undPos)) { size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0; 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")) { - prim.indices = r.accessors.Get(indices->GetString()); + prim.indices = pAsset_Root.accessors.Get(indices->GetString()); } 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 decoder; +o3dgc::IndexedFaceSet ifs; +o3dgc::BinaryStream bstream; +uint8_t* decoded_data; +size_t decoded_data_size = 0; +Ref 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_floatattr; + std::vector 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& 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) { diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index 415db6714..88a92c440 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -56,11 +56,11 @@ namespace glTF { inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(N, al); - for (int i = 0; i < N; ++i) { + for (decltype(N) i = 0; i < N; ++i) { val.PushBack(r[i], al); } return val; - }; + } template inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref >& v, MemoryPoolAllocator<>& al) { @@ -72,7 +72,7 @@ namespace glTF { lst.PushBack(StringRef(v[i]->id), al); } obj.AddMember(StringRef(fieldId), lst, al); - }; + } } @@ -199,6 +199,60 @@ namespace glTF { 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; primitives.SetArray(); primitives.Reserve(unsigned(m.primitives.size()), w.mAl); diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index eb0070d64..58defed3b 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -58,10 +58,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +// Header files, standart library. #include +#include #include "glTFAssetWriter.h" +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + // Header files, Open3DGC. +# include +#endif + using namespace rapidjson; using namespace Assimp; @@ -267,15 +274,56 @@ void glTFExporter::ExportMaterials() void glTFExporter::ExportMeshes() { - std::string bufferId = mAsset->FindUniqueID("", "buffer"); +// 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; - Ref b = mAsset->GetBodyBuffer(); - if (!b) { - b = mAsset->buffers.Create(bufferId); - } +// 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 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. - for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { - const aiMesh* aim = mScene->mMeshes[i]; + std::string bufferId = mAsset->FindUniqueID("", "buffer"); + + Ref b = mAsset->GetBodyBuffer(); + if (!b) { + b = mAsset->buffers.Create(bufferId); + } + + 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"); Ref m = mAsset->meshes.Create(meshId); @@ -284,12 +332,20 @@ void glTFExporter::ExportMeshes() 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 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); - Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); - if (n) p.attributes.normal.push_back(n); + /******************** Normals ********************/ + if(comp_allow && (aim->mNormals > 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array. + Ref 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) { // Flip UV y coords if (aim -> mNumUVComponents[i] > 1) { @@ -300,22 +356,29 @@ void glTFExporter::ExportMeshes() if (aim->mNumUVComponents[i] > 0) { AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3; - Ref 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 indices; + if(comp_allow) idx_srcdata_tc.push_back(b->byteLength);// Store index of texture coordinates array. + + Ref 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 indices; + unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices; indices.resize(aim->mNumFaces * nIndicesPerFace); for (size_t i = 0; i < aim->mNumFaces; ++i) { for (size_t j = 0; j < nIndicesPerFace; ++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) { case aiPrimitiveType_POLYGON: @@ -327,7 +390,99 @@ void glTFExporter::ExportMeshes() default: // aiPrimitiveType_TRIANGLE 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 encoder; + o3dgc::IndexedFaceSet 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) diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index a1781b04c..288cfd883 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -1,4 +1,4 @@ -/* +/* 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) { 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 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()); 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; - if (attr.position.size() > 0 && attr.position[0]) { + + if (attr.position.size() > 0 && attr.position[0]) { aim->mNumVertices = attr.position[0]->count; 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) { attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); @@ -315,7 +346,7 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) if (prim.indices) { - aiFace* faces = 0; + aiFace* faces = 0; unsigned int nFaces = 0; 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? //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; - Assimp::MakeVerboseFormatProcess process; + MakeVerboseFormatProcess process; process.Execute(pScene); diff --git a/contrib/Open3DGC/o3dgcAdjacencyInfo.h b/contrib/Open3DGC/o3dgcAdjacencyInfo.h new file mode 100644 index 000000000..6b53a242d --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcArithmeticCodec.cpp b/contrib/Open3DGC/o3dgcArithmeticCodec.cpp new file mode 100644 index 000000000..1d160ba95 --- /dev/null +++ b/contrib/Open3DGC/o3dgcArithmeticCodec.cpp @@ -0,0 +1,863 @@ +/* +Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu) +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 (said@ieee.org) & - +// William A. Pearlman (pearlw@ecse.rpi.edu) - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// 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 +#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; + } +} +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/contrib/Open3DGC/o3dgcArithmeticCodec.h b/contrib/Open3DGC/o3dgcArithmeticCodec.h new file mode 100644 index 000000000..d3cf6d14a --- /dev/null +++ b/contrib/Open3DGC/o3dgcArithmeticCodec.h @@ -0,0 +1,339 @@ +/* +Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu) +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 (said@ieee.org) & - +// William A. Pearlman (pearlw@ecse.rpi.edu) - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// 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 +#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)&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<>= 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 m_stream; + O3DGCEndianness m_endianness; + }; + +} +#endif // O3DGC_BINARY_STREAM_H + diff --git a/contrib/Open3DGC/o3dgcCommon.h b/contrib/Open3DGC/o3dgcCommon.h new file mode 100644 index 000000000..a9be4d885 --- /dev/null +++ b/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 +#include +#include +#include + +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 + inline const T absolute(const T& a) + { + return (a < (T)(0)) ? -a : a; + } + template + inline const T min(const T& a, const T& b) + { + return (b < a) ? b : a; + } + template + inline const T max(const T& a, const T& b) + { + return (b > a) ? b : a; + } + template + 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 + 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 + diff --git a/contrib/Open3DGC/o3dgcDVEncodeParams.h b/contrib/Open3DGC/o3dgcDVEncodeParams.h new file mode 100644 index 000000000..6f639f678 --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcDynamicVector.h b/contrib/Open3DGC/o3dgcDynamicVector.h new file mode 100644 index 000000000..edc97d83c --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp b/contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp new file mode 100644 index 000000000..b92452eb6 --- /dev/null +++ b/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; + } +} diff --git a/contrib/Open3DGC/o3dgcDynamicVectorDecoder.h b/contrib/Open3DGC/o3dgcDynamicVectorDecoder.h new file mode 100644 index 000000000..6e21b4fa3 --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp b/contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp new file mode 100644 index 000000000..00ae75e35 --- /dev/null +++ b/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 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; + } +} diff --git a/contrib/Open3DGC/o3dgcDynamicVectorEncoder.h b/contrib/Open3DGC/o3dgcDynamicVectorEncoder.h new file mode 100644 index 000000000..de42a020f --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcFIFO.h b/contrib/Open3DGC/o3dgcFIFO.h new file mode 100644 index 000000000..874c26475 --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcIndexedFaceSet.h b/contrib/Open3DGC/o3dgcIndexedFaceSet.h new file mode 100644 index 000000000..4af9de437 --- /dev/null +++ b/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 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 + diff --git a/contrib/Open3DGC/o3dgcIndexedFaceSet.inl b/contrib/Open3DGC/o3dgcIndexedFaceSet.inl new file mode 100644 index 000000000..ddac26d76 --- /dev/null +++ b/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 +namespace o3dgc +{ + template + void IndexedFaceSet::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 diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.h b/contrib/Open3DGC/o3dgcSC3DMCDecoder.h new file mode 100644 index 000000000..f3f1617c4 --- /dev/null +++ b/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 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 & ifs, + const BinaryStream & bstream); + //! + O3DGCErrorCode DecodePayload(IndexedFaceSet & 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 & 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 & ifs, + O3DGCSC3DMCPredictionMode & predMode, + const BinaryStream & bstream); + O3DGCErrorCode ProcessNormals(const IndexedFaceSet & ifs); + + unsigned long m_iterator; + unsigned long m_streamSize; + SC3DMCEncodeParams m_params; + TriangleListDecoder m_triangleListDecoder; + long * m_quantFloatArray; + unsigned long m_quantFloatArraySize; + Vector 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 + diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl new file mode 100644 index 000000000..d36b62f2b --- /dev/null +++ b/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 + O3DGCErrorCode SC3DMCDecoder::DecodeHeader(IndexedFaceSet & 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 + O3DGCErrorCode SC3DMCDecoder::DecodePayload(IndexedFaceSet & 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 + O3DGCErrorCode SC3DMCDecoder::DecodeIntArray(long * const intArray, + unsigned long numIntArray, + unsigned long dimIntArray, + unsigned long stride, + const IndexedFaceSet & 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 + O3DGCErrorCode SC3DMCDecoder::ProcessNormals(const IndexedFaceSet & 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 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 + O3DGCErrorCode SC3DMCDecoder::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 & 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 + O3DGCErrorCode SC3DMCDecoder::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 + + diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h b/contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h new file mode 100644 index 000000000..5f3db969c --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncoder.h b/contrib/Open3DGC/o3dgcSC3DMCEncoder.h new file mode 100644 index 000000000..9c4e95026 --- /dev/null +++ b/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 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 & ifs, + BinaryStream & bstream); + const SC3DMCStats & GetStats() const { return m_stats;} + + private: + O3DGCErrorCode EncodeHeader(const SC3DMCEncodeParams & params, + const IndexedFaceSet & ifs, + BinaryStream & bstream); + O3DGCErrorCode EncodePayload(const SC3DMCEncodeParams & params, + const IndexedFaceSet & 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 & 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 & ifs, + O3DGCSC3DMCPredictionMode predMode, + BinaryStream & bstream); + O3DGCErrorCode ProcessNormals(const IndexedFaceSet & ifs); + TriangleListEncoder 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 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 + diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl b/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl new file mode 100644 index 000000000..b2c438814 --- /dev/null +++ b/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 + O3DGCErrorCode SC3DMCEncoder::Encode(const SC3DMCEncodeParams & params, + const IndexedFaceSet & 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 + O3DGCErrorCode SC3DMCEncoder::EncodeHeader(const SC3DMCEncodeParams & params, + const IndexedFaceSet & 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 + O3DGCErrorCode SC3DMCEncoder::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 + O3DGCErrorCode SC3DMCEncoder::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 & 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 + O3DGCErrorCode SC3DMCEncoder::EncodeIntArray(const long * const intArray, + unsigned long numIntArray, + unsigned long dimIntArray, + unsigned long stride, + const IndexedFaceSet & 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 + O3DGCErrorCode SC3DMCEncoder::ProcessNormals(const IndexedFaceSet & 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 p1, p2, p3, n0, nt; + Vec3 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 + O3DGCErrorCode SC3DMCEncoder::EncodePayload(const SC3DMCEncodeParams & params, + const IndexedFaceSet & 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 + + diff --git a/contrib/Open3DGC/o3dgcTimer.h b/contrib/Open3DGC/o3dgcTimer.h new file mode 100644 index 000000000..97f575931 --- /dev/null +++ b/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 +#elif __MACH__ +#include +#include +#else +#include +#include +#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 diff --git a/contrib/Open3DGC/o3dgcTools.cpp b/contrib/Open3DGC/o3dgcTools.cpp new file mode 100644 index 000000000..52b552304 --- /dev/null +++ b/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. +*/ + diff --git a/contrib/Open3DGC/o3dgcTriangleFans.cpp b/contrib/Open3DGC/o3dgcTriangleFans.cpp new file mode 100644 index 000000000..078ed16e6 --- /dev/null +++ b/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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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; + } +} + diff --git a/contrib/Open3DGC/o3dgcTriangleFans.h b/contrib/Open3DGC/o3dgcTriangleFans.h new file mode 100644 index 000000000..861836428 --- /dev/null +++ b/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 & data, + BinaryStream & bstream); + O3DGCErrorCode SaveUIntAC(const Vector & data, + const unsigned long M, + BinaryStream & bstream); + O3DGCErrorCode SaveIntACEGC(const Vector & data, + const unsigned long M, + BinaryStream & bstream); + + Vector m_numTFANs; + Vector m_degrees; + Vector m_configs; + Vector m_operations; + Vector m_indices; + Vector 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 + diff --git a/contrib/Open3DGC/o3dgcTriangleListDecoder.h b/contrib/Open3DGC/o3dgcTriangleListDecoder.h new file mode 100644 index 000000000..65df526d1 --- /dev/null +++ b/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 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 + diff --git a/contrib/Open3DGC/o3dgcTriangleListDecoder.inl b/contrib/Open3DGC/o3dgcTriangleListDecoder.inl new file mode 100644 index 000000000..dd3af4aa7 --- /dev/null +++ b/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 + O3DGCErrorCode TriangleListDecoder::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 + O3DGCErrorCode TriangleListDecoder::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 + O3DGCErrorCode TriangleListDecoder::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 + O3DGCErrorCode TriangleListDecoder::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 + O3DGCErrorCode TriangleListDecoder::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 + diff --git a/contrib/Open3DGC/o3dgcTriangleListEncoder.h b/contrib/Open3DGC/o3dgcTriangleListEncoder.h new file mode 100644 index 000000000..cf790ecc3 --- /dev/null +++ b/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 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 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 + diff --git a/contrib/Open3DGC/o3dgcTriangleListEncoder.inl b/contrib/Open3DGC/o3dgcTriangleListEncoder.inl new file mode 100644 index 000000000..d499f6dc9 --- /dev/null +++ b/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 + 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 + TriangleListEncoder::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 + TriangleListEncoder::~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 + O3DGCErrorCode TriangleListEncoder::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 + O3DGCErrorCode TriangleListEncoder::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 + O3DGCErrorCode TriangleListEncoder::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 + O3DGCErrorCode TriangleListEncoder::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 + O3DGCErrorCode TriangleListEncoder::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 + O3DGCErrorCode TriangleListEncoder::ProcessVertex(const long focusVertex) + { + CompueLocalConnectivityInfo(focusVertex); + ComputeTFANDecomposition(focusVertex); + CompressTFAN(focusVertex); + return O3DGC_OK; + } +} +#endif //O3DGC_TRIANGLE_LIST_ENCODER_INL diff --git a/contrib/Open3DGC/o3dgcVector.h b/contrib/Open3DGC/o3dgcVector.h new file mode 100644 index 000000000..e766e2b7f --- /dev/null +++ b/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 + diff --git a/contrib/Open3DGC/o3dgcVector.inl b/contrib/Open3DGC/o3dgcVector.inl new file mode 100644 index 000000000..5549b00ce --- /dev/null +++ b/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 + inline Vec3 operator*(T lhs, const Vec3 & rhs) + { + return Vec3(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z()); + } + template + inline T & Vec3::X() + { + return m_data[0]; + } + template + inline T & Vec3::Y() + { + return m_data[1]; + } + template + inline T & Vec3::Z() + { + return m_data[2]; + } + template + inline const T & Vec3::X() const + { + return m_data[0]; + } + template + inline const T & Vec3::Y() const + { + return m_data[1]; + } + template + inline const T & Vec3::Z() const + { + return m_data[2]; + } + template + inline double Vec3::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 + inline void Vec3::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 + inline void Vec3::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 + inline void Vec3::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 + inline void Vec3::operator-=(T a) + { + this->m_data[0] -= a; + this->m_data[1] -= a; + this->m_data[2] -= a; + } + template + inline void Vec3::operator+=(T a) + { + this->m_data[0] += a; + this->m_data[1] += a; + this->m_data[2] += a; + } + template + inline void Vec3::operator/=(T a) + { + this->m_data[0] /= a; + this->m_data[1] /= a; + this->m_data[2] /= a; + } + template + inline void Vec3::operator*=(T a) + { + this->m_data[0] *= a; + this->m_data[1] *= a; + this->m_data[2] *= a; + } + template + inline Vec3 Vec3::operator^ (const Vec3 & rhs) const + { + return Vec3(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 + inline T Vec3::operator*(const Vec3 & 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 + inline Vec3 Vec3::operator+(const Vec3 & rhs) const + { + return Vec3(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]); + } + template + inline Vec3 Vec3::operator-(const Vec3 & rhs) const + { + return Vec3(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]); + } + template + inline Vec3 Vec3::operator-() const + { + return Vec3(-m_data[0],-m_data[1],-m_data[2]); + } + + template + inline Vec3 Vec3::operator*(T rhs) const + { + return Vec3(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]); + } + template + inline Vec3 Vec3::operator/ (T rhs) const + { + return Vec3(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs); + } + template + inline Vec3::Vec3(T a) + { + m_data[0] = m_data[1] = m_data[2] = a; + } + template + inline Vec3::Vec3(T x, T y, T z) + { + m_data[0] = x; + m_data[1] = y; + m_data[2] = z; + } + template + inline Vec3::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 + inline Vec3::~Vec3(void){}; + + template + inline Vec3::Vec3() {} + + template + inline Vec2 operator*(T lhs, const Vec2 & rhs) + { + return Vec2(lhs * rhs.X(), lhs * rhs.Y()); + } + template + inline T & Vec2::X() + { + return m_data[0]; + } + template + inline T & Vec2::Y() + { + return m_data[1]; + } + template + inline const T & Vec2::X() const + { + return m_data[0]; + } + template + inline const T & Vec2::Y() const + { + return m_data[1]; + } + template + inline double Vec2::GetNorm() const + { + double a = (double) (m_data[0]); + double b = (double) (m_data[1]); + return sqrt(a*a+b*b); + } + template + inline void Vec2::operator= (const Vec2 & rhs) + { + this->m_data[0] = rhs.m_data[0]; + this->m_data[1] = rhs.m_data[1]; + } + template + inline void Vec2::operator+=(const Vec2 & rhs) + { + this->m_data[0] += rhs.m_data[0]; + this->m_data[1] += rhs.m_data[1]; + } + template + inline void Vec2::operator-=(const Vec2 & rhs) + { + this->m_data[0] -= rhs.m_data[0]; + this->m_data[1] -= rhs.m_data[1]; + } + template + inline void Vec2::operator-=(T a) + { + this->m_data[0] -= a; + this->m_data[1] -= a; + } + template + inline void Vec2::operator+=(T a) + { + this->m_data[0] += a; + this->m_data[1] += a; + } + template + inline void Vec2::operator/=(T a) + { + this->m_data[0] /= a; + this->m_data[1] /= a; + } + template + inline void Vec2::operator*=(T a) + { + this->m_data[0] *= a; + this->m_data[1] *= a; + } + template + inline T Vec2::operator^ (const Vec2 & rhs) const + { + return m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]; + } + template + inline T Vec2::operator*(const Vec2 & rhs) const + { + return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1]); + } + template + inline Vec2 Vec2::operator+(const Vec2 & rhs) const + { + return Vec2(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1]); + } + template + inline Vec2 Vec2::operator-(const Vec2 & rhs) const + { + return Vec2(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1]); + } + template + inline Vec2 Vec2::operator-() const + { + return Vec2(-m_data[0],-m_data[1]) ; + } + + template + inline Vec2 Vec2::operator*(T rhs) const + { + return Vec2(rhs * this->m_data[0], rhs * this->m_data[1]); + } + template + inline Vec2 Vec2::operator/ (T rhs) const + { + return Vec2(m_data[0] / rhs, m_data[1] / rhs); + } + template + inline Vec2::Vec2(T a) + { + m_data[0] = m_data[1] = a; + } + template + inline Vec2::Vec2(T x, T y) + { + m_data[0] = x; + m_data[1] = y; + } + template + inline Vec2::Vec2(const Vec2 & rhs) + { + m_data[0] = rhs.m_data[0]; + m_data[1] = rhs.m_data[1]; + } + template + inline Vec2::~Vec2(void){}; + + template + inline Vec2::Vec2() {} +} +#endif //O3DGC_VECTOR_INL +