pull/1005/head
Kim Kulling 2016-09-22 09:52:56 +02:00
commit d005b38f99
38 changed files with 9304 additions and 112 deletions

View File

@ -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)

View File

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

View File

@ -139,9 +139,9 @@ Exporter::ExportFormatEntry gExporters[] =
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate /*| aiProcess_SortByPType*/),
Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate /*| aiProcess_SortByPType*/),
#endif #endif
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map> #include <map>
#include <string> #include <string>
#include <list>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <stdexcept> #include <stdexcept>
@ -361,8 +362,6 @@ namespace glTF
{ return id; } { return id; }
}; };
// //
// Classes for each glTF top-level object type // Classes for each glTF top-level object type
// //
@ -451,32 +450,115 @@ namespace glTF
//! A buffer points to binary geometry, animation, or skins. //! A buffer points to binary geometry, animation, or skins.
struct Buffer : public Object struct Buffer : public Object
{ {
public: /********************* Types *********************/
public:
enum Type enum Type
{ {
Type_arraybuffer, Type_arraybuffer,
Type_text Type_text
}; };
//std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) /// \struct SEncodedRegion
size_t byteLength; //!< The length of the buffer in bytes. (default: 0) /// Descriptor of encoded region in "bufferView".
//std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") 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: /// \fn ~SEncodedRegion()
shared_ptr<uint8_t> mData; //!< Pointer to the data /// Destructor.
bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) ~SEncodedRegion() { delete [] DecodedData; }
};
public: /******************* Variables *******************/
Buffer();
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<uint8_t> mData; //!< Pointer to the data
bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
/// \var EncodedRegion_List
/// List of encoded regions.
std::list<SEncodedRegion*> EncodedRegion_List;
/******************* Functions *******************/
public:
Buffer();
~Buffer();
void Read(Value& obj, Asset& r);
bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0);
/// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
/// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
/// \param [in] pDecodedData - pointer to decoded data array.
/// \param [in] pDecodedData_Length - size of encoded region, in bytes.
/// \param [in] pID - ID of the region.
void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID);
/// \fn void EncodedRegion_SetCurrent(const std::string& pID)
/// Select current encoded region by ID. \sa EncodedRegion_Current.
/// \param [in] pID - ID of the region.
void EncodedRegion_SetCurrent(const std::string& pID);
/// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
/// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
/// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
/// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
/// \param [in] pReplace_Data - pointer to array with new data for buffer.
/// \param [in] pReplace_Count - count of bytes in new data.
/// \return true - if successfully replaced, false if input arguments is out of range.
bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count);
size_t AppendData(uint8_t* data, size_t length); size_t AppendData(uint8_t* data, size_t length);
void Grow(size_t amount); void Grow(size_t amount);
@ -489,10 +571,12 @@ namespace glTF
bool IsSpecial() const bool IsSpecial() const
{ return mIsSpecial; } { return mIsSpecial; }
std::string GetURI()
{ return std::string(this->id) + ".bin"; }
static const char* TranslateId(Asset& r, const char* id); static const char* TranslateId(Asset& r, const char* id);
}; };
//! A view into a buffer generally representing a subset of the buffer. //! A view into a buffer generally representing a subset of the buffer.
struct BufferView : public Object struct BufferView : public Object
{ {
@ -502,11 +586,9 @@ namespace glTF
BufferViewTarget target; //! The target that the WebGL buffer should be bound to. BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
BufferView() {}
void Read(Value& obj, Asset& r); void Read(Value& obj, Asset& r);
}; };
struct Camera : public Object struct Camera : public Object
{ {
enum Type enum Type
@ -631,10 +713,77 @@ namespace glTF
Ref<Material> material; Ref<Material> material;
}; };
/// \struct SExtension
/// Extension used for mesh.
struct SExtension
{
/// \enum EType
/// Type of extension.
enum EType
{
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
Compression_Open3DGC,///< Compression of mesh data using Open3DGC algorythm.
#endif
Unknown
};
EType Type;///< Type of extension.
/// \fn SExtension
/// Constructor.
/// \param [in] pType - type of extension.
SExtension(const EType pType)
: Type(pType)
{}
};
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
/// \struct SCompression_Open3DGC
/// Compression of mesh data using Open3DGC algorythm.
struct SCompression_Open3DGC : public SExtension
{
using SExtension::Type;
std::string Buffer;///< ID of "buffer" used for storing compressed data.
size_t Offset;///< Offset in "bufferView" where compressed data are stored.
size_t Count;///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type".
bool Binary;///< If true then "binary" mode is used for coding, if false - "ascii" mode.
size_t IndicesCount;///< Count of indices in mesh.
size_t VerticesCount;///< Count of vertices in mesh.
// AttribType::Value Type;///< Is always "SCALAR".
// ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121).
/// \fn SCompression_Open3DGC
/// Constructor.
SCompression_Open3DGC()
: SExtension(Compression_Open3DGC)
{}
};
#endif
std::vector<Primitive> primitives; std::vector<Primitive> primitives;
std::list<SExtension*> Extension;///< List of extensions used in mesh.
Mesh() {} Mesh() {}
void Read(Value& obj, Asset& r);
/// \fn ~Mesh()
/// Destructor.
~Mesh() { for(std::list<SExtension*>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { delete *it; }; }
/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)
/// Get mesh data from JSON-object and place them to root asset.
/// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
/// \param [out] pAsset_Root - reference to root assed where data will be stored.
void Read(Value& pJSON_Object, Asset& pAsset_Root);
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
/// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
/// Decode part of "buffer" which encoded with Open3DGC algorithm.
/// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
/// \param [out] pAsset_Root - reference to root assed where data will be stored.
void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root);
#endif
}; };
struct Node : public Object struct Node : public Object
@ -805,6 +954,7 @@ namespace glTF
Ref<T> Get(const char* id); Ref<T> Get(const char* id);
Ref<T> Get(unsigned int i); Ref<T> Get(unsigned int i);
Ref<T> Get(const std::string& pID) { return Get(pID.c_str()); }
Ref<T> Create(const char* id); Ref<T> Create(const char* id);
Ref<T> Create(const std::string& id) Ref<T> Create(const std::string& id)

View File

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

View File

@ -79,6 +79,7 @@ public:
AssetWriter(Asset& asset); AssetWriter(Asset& asset);
void WriteFile(const char* path); void WriteFile(const char* path);
void WriteGLBFile(const char* path);
}; };
} }

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------
@ -56,11 +56,11 @@ namespace glTF {
inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
val.SetArray(); val.SetArray();
val.Reserve(N, al); val.Reserve(N, al);
for (int i = 0; i < N; ++i) { for (decltype(N) i = 0; i < N; ++i) {
val.PushBack(r[i], al); val.PushBack(r[i], al);
} }
return val; return val;
}; }
template<class T> template<class T>
inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) { inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
@ -72,7 +72,7 @@ namespace glTF {
lst.PushBack(StringRef(v[i]->id), al); lst.PushBack(StringRef(v[i]->id), al);
} }
obj.AddMember(StringRef(fieldId), lst, al); obj.AddMember(StringRef(fieldId), lst, al);
}; }
} }
@ -94,9 +94,6 @@ namespace glTF {
inline void Write(Value& obj, Buffer& b, AssetWriter& w) inline void Write(Value& obj, Buffer& b, AssetWriter& w)
{ {
std::string dataURI = "data:application/octet-stream;base64,";
Util::EncodeBase64(b.GetPointer(), b.byteLength, dataURI);
const char* type; const char* type;
switch (b.type) { switch (b.type) {
case Buffer::Type_text: case Buffer::Type_text:
@ -107,7 +104,7 @@ namespace glTF {
obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl); obj.AddMember("byteLength", static_cast<uint64_t>(b.byteLength), w.mAl);
obj.AddMember("type", StringRef(type), w.mAl); obj.AddMember("type", StringRef(type), w.mAl);
obj.AddMember("uri", Value(dataURI, w.mAl).Move(), w.mAl); obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl);
} }
inline void Write(Value& obj, BufferView& bv, AssetWriter& w) inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
@ -199,6 +196,60 @@ namespace glTF {
inline void Write(Value& obj, Mesh& m, AssetWriter& w) inline void Write(Value& obj, Mesh& m, AssetWriter& w)
{ {
/********************* Name **********************/
obj.AddMember("name", m.name, w.mAl);
/**************** Mesh extensions ****************/
if(m.Extension.size() > 0)
{
Value json_extensions;
json_extensions.SetObject();
for(Mesh::SExtension* ptr_ext : m.Extension)
{
switch(ptr_ext->Type)
{
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
case Mesh::SExtension::EType::Compression_Open3DGC:
{
Value json_comp_data;
Mesh::SCompression_Open3DGC* ptr_ext_comp = (Mesh::SCompression_Open3DGC*)ptr_ext;
// filling object "compressedData"
json_comp_data.SetObject();
json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl);
json_comp_data.AddMember("byteOffset", ptr_ext_comp->Offset, w.mAl);
json_comp_data.AddMember("componentType", 5121, w.mAl);
json_comp_data.AddMember("type", "SCALAR", w.mAl);
json_comp_data.AddMember("count", ptr_ext_comp->Count, w.mAl);
if(ptr_ext_comp->Binary)
json_comp_data.AddMember("mode", "binary", w.mAl);
else
json_comp_data.AddMember("mode", "ascii", w.mAl);
json_comp_data.AddMember("indicesCount", ptr_ext_comp->IndicesCount, w.mAl);
json_comp_data.AddMember("verticesCount", ptr_ext_comp->VerticesCount, w.mAl);
// filling object "Open3DGC-compression"
Value json_o3dgc;
json_o3dgc.SetObject();
json_o3dgc.AddMember("compressedData", json_comp_data, w.mAl);
// add member to object "extensions"
json_extensions.AddMember("Open3DGC-compression", json_o3dgc, w.mAl);
}
break;
#endif
default:
throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported.");
}// switch(ptr_ext->Type)
}// for(Mesh::SExtension* ptr_ext : m.Extension)
// Add extensions to mesh
obj.AddMember("extensions", json_extensions, w.mAl);
}// if(m.Extension.size() > 0)
/****************** Primitives *******************/
Value primitives; Value primitives;
primitives.SetArray(); primitives.SetArray();
primitives.Reserve(unsigned(m.primitives.size()), w.mAl); primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
@ -328,39 +379,61 @@ namespace glTF {
inline void AssetWriter::WriteFile(const char* path) inline void AssetWriter::WriteFile(const char* path)
{ {
bool isBinary = mAsset.extensionsUsed.KHR_binary_glTF; std::unique_ptr<IOStream> jsonOutFile(mAsset.OpenFile(path, "wt", true));
std::unique_ptr<IOStream> outfile if (jsonOutFile == 0) {
(mAsset.OpenFile(path, isBinary ? "wb" : "wt", true)); throw DeadlyExportError("Could not open output file: " + std::string(path));
}
StringBuffer docBuffer;
PrettyWriter<StringBuffer> writer(docBuffer);
mDoc.Accept(writer);
if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
throw DeadlyExportError("Failed to write scene data!");
}
// Write buffer data to separate .bin files
for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) {
Ref<Buffer> b = mAsset.buffers.Get(i);
std::string binPath = b->GetURI();
std::unique_ptr<IOStream> binOutFile(mAsset.OpenFile(binPath, "wb", true));
if (binOutFile == 0) {
throw DeadlyExportError("Could not open output file: " + binPath);
}
if (b->byteLength > 0) {
if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
throw DeadlyExportError("Failed to write binary file: " + binPath);
}
}
}
}
inline void AssetWriter::WriteGLBFile(const char* path)
{
std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true));
if (outfile == 0) { if (outfile == 0) {
throw DeadlyExportError("Could not open output file: " + std::string(path)); throw DeadlyExportError("Could not open output file: " + std::string(path));
} }
if (isBinary) { // we will write the header later, skip its size
// we will write the header later, skip its size outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
}
StringBuffer docBuffer; StringBuffer docBuffer;
Writer<StringBuffer> writer(docBuffer);
bool pretty = true; mDoc.Accept(writer);
if (!isBinary && pretty) {
PrettyWriter<StringBuffer> writer(docBuffer);
mDoc.Accept(writer);
}
else {
Writer<StringBuffer> writer(docBuffer);
mDoc.Accept(writer);
}
if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
throw DeadlyExportError("Failed to write scene data!"); throw DeadlyExportError("Failed to write scene data!");
} }
if (isBinary) { WriteBinaryData(outfile.get(), docBuffer.GetSize());
WriteBinaryData(outfile.get(), docBuffer.GetSize());
}
} }
inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength) inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength)
@ -385,7 +458,6 @@ namespace glTF {
} }
} }
// //
// write the header // write the header
// //

View File

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

View File

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

View File

@ -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

View File

@ -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 <stdlib.h>
#include "o3dgcArithmeticCodec.h"
namespace o3dgc
{
// - - Constants - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const unsigned AC__MinLength = 0x01000000U; // threshold for renormalization
const unsigned AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length
// Maximum values for binary models
const unsigned BM__LengthShift = 13; // length bits discarded before mult.
const unsigned BM__MaxCount = 1 << BM__LengthShift; // for adaptive models
// Maximum values for general models
const unsigned DM__LengthShift = 15; // length bits discarded before mult.
const unsigned DM__MaxCount = 1 << DM__LengthShift; // for adaptive models
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Static functions - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void AC_Error(const char * msg)
{
fprintf(stderr, "\n\n -> Arithmetic coding error: ");
fputs(msg, stderr);
fputs("\n Execution terminated!\n", stderr);
getchar();
exit(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Coding implementations - - - - - - - - - - - - - - - - - - - - - - - -
inline void Arithmetic_Codec::propagate_carry(void)
{
unsigned char * p; // carry propagation on compressed data buffer
for (p = ac_pointer - 1; *p == 0xFFU; p--) *p = 0;
++*p;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void Arithmetic_Codec::renorm_enc_interval(void)
{
do { // output and discard top byte
*ac_pointer++ = (unsigned char)(base >> 24);
base <<= 8;
} while ((length <<= 8) < AC__MinLength); // length multiplied by 256
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void Arithmetic_Codec::renorm_dec_interval(void)
{
do { // read least-significant byte
value = (value << 8) | unsigned(*++ac_pointer);
} while ((length <<= 8) < AC__MinLength); // length multiplied by 256
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::put_bit(unsigned bit)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
#endif
length >>= 1; // halve interval
if (bit) {
unsigned init_base = base;
base += length; // move base
if (init_base > base) propagate_carry(); // overflow = carry
}
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::get_bit(void)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
length >>= 1; // halve interval
unsigned bit = (value >= length); // decode bit
if (bit) value -= length; // move base
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return bit; // return data bit value
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::put_bits(unsigned data, unsigned bits)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
if (data >= (1U << bits)) AC_Error("invalid data");
#endif
unsigned init_base = base;
base += data * (length >>= bits); // new interval base and length
if (init_base > base) propagate_carry(); // overflow = carry
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::get_bits(unsigned bits)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
#endif
unsigned s = value / (length >>= bits); // decode symbol, change length
value -= length * s; // update interval
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned bit,
Static_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
// update interval
if (bit == 0)
length = x;
else {
unsigned init_base = base;
base += x;
length -= x;
if (init_base > base) propagate_carry(); // overflow = carry
}
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Static_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
unsigned bit = (value >= x); // decision
// update & shift interval
if (bit == 0)
length = x;
else {
value -= x; // shifted interval base = 0
length -= x;
}
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return bit; // return data bit value
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned bit,
Adaptive_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
// update interval
if (bit == 0) {
length = x;
++M.bit_0_count;
}
else {
unsigned init_base = base;
base += x;
length -= x;
if (init_base > base) propagate_carry(); // overflow = carry
}
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
if (--M.bits_until_update == 0) M.update(); // periodic model update
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Adaptive_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
unsigned bit = (value >= x); // decision
// update interval
if (bit == 0) {
length = x;
++M.bit_0_count;
}
else {
value -= x;
length -= x;
}
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
if (--M.bits_until_update == 0) M.update(); // periodic model update
return bit; // return data bit value
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned data,
Static_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
if (data >= M.data_symbols) AC_Error("invalid data symbol");
#endif
unsigned x, init_base = base;
// compute products
if (data == M.last_symbol) {
x = M.distribution[data] * (length >> DM__LengthShift);
base += x; // update interval
length -= x; // no product needed
}
else {
x = M.distribution[data] * (length >>= DM__LengthShift);
base += x; // update interval
length = M.distribution[data+1] * length - x;
}
if (init_base > base) propagate_carry(); // overflow = carry
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Static_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned n, s, x, y = length;
if (M.decoder_table) { // use table look-up for faster decoding
unsigned dv = value / (length >>= DM__LengthShift);
unsigned t = dv >> M.table_shift;
s = M.decoder_table[t]; // initial decision based on table look-up
n = M.decoder_table[t+1] + 1;
while (n > s + 1) { // finish with bisection search
unsigned m = (s + n) >> 1;
if (M.distribution[m] > dv) n = m; else s = m;
}
// compute products
x = M.distribution[s] * length;
if (s != M.last_symbol) y = M.distribution[s+1] * length;
}
else { // decode using only multiplications
x = s = 0;
length >>= DM__LengthShift;
unsigned m = (n = M.data_symbols) >> 1;
// decode via bisection search
do {
unsigned z = length * M.distribution[m];
if (z > value) {
n = m;
y = z; // value is smaller
}
else {
s = m;
x = z; // value is larger or equal
}
} while ((m = (s + n) >> 1) != s);
}
value -= x; // update interval
length = y - x;
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned data,
Adaptive_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
if (data >= M.data_symbols)
{
AC_Error("invalid data symbol");
}
#endif
unsigned x, init_base = base;
// compute products
if (data == M.last_symbol) {
x = M.distribution[data] * (length >> DM__LengthShift);
base += x; // update interval
length -= x; // no product needed
}
else {
x = M.distribution[data] * (length >>= DM__LengthShift);
base += x; // update interval
length = M.distribution[data+1] * length - x;
}
if (init_base > base) propagate_carry(); // overflow = carry
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
++M.symbol_count[data];
if (--M.symbols_until_update == 0) M.update(true); // periodic model update
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Adaptive_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned n, s, x, y = length;
if (M.decoder_table) { // use table look-up for faster decoding
unsigned dv = value / (length >>= DM__LengthShift);
unsigned t = dv >> M.table_shift;
s = M.decoder_table[t]; // initial decision based on table look-up
n = M.decoder_table[t+1] + 1;
while (n > s + 1) { // finish with bisection search
unsigned m = (s + n) >> 1;
if (M.distribution[m] > dv) n = m; else s = m;
}
// compute products
x = M.distribution[s] * length;
if (s != M.last_symbol) {
y = M.distribution[s+1] * length;
}
}
else { // decode using only multiplications
x = s = 0;
length >>= DM__LengthShift;
unsigned m = (n = M.data_symbols) >> 1;
// decode via bisection search
do {
unsigned z = length * M.distribution[m];
if (z > value) {
n = m;
y = z; // value is smaller
}
else {
s = m;
x = z; // value is larger or equal
}
} while ((m = (s + n) >> 1) != s);
}
value -= x; // update interval
length = y - x;
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
++M.symbol_count[s];
if (--M.symbols_until_update == 0) M.update(false); // periodic model update
return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Other Arithmetic_Codec implementations - - - - - - - - - - - - - - - -
Arithmetic_Codec::Arithmetic_Codec(void)
{
mode = buffer_size = 0;
new_buffer = code_buffer = 0;
}
Arithmetic_Codec::Arithmetic_Codec(unsigned max_code_bytes,
unsigned char * user_buffer)
{
mode = buffer_size = 0;
new_buffer = code_buffer = 0;
set_buffer(max_code_bytes, user_buffer);
}
Arithmetic_Codec::~Arithmetic_Codec(void)
{
delete [] new_buffer;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::set_buffer(unsigned max_code_bytes,
unsigned char * user_buffer)
{
// test for reasonable sizes
if (!max_code_bytes)// || (max_code_bytes > 0x10000000U)) // updated by K. Mammou
{
AC_Error("invalid codec buffer size");
}
if (mode != 0) AC_Error("cannot set buffer while encoding or decoding");
if (user_buffer != 0) { // user provides memory buffer
buffer_size = max_code_bytes;
code_buffer = user_buffer; // set buffer for compressed data
delete [] new_buffer; // free anything previously assigned
new_buffer = 0;
return;
}
if (max_code_bytes <= buffer_size) return; // enough available
buffer_size = max_code_bytes; // assign new memory
delete [] new_buffer; // free anything previously assigned
if ((new_buffer = new unsigned char[buffer_size+16]) == 0) // 16 extra bytes
AC_Error("cannot assign memory for compressed data buffer");
code_buffer = new_buffer; // set buffer for compressed data
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::start_encoder(void)
{
if (mode != 0) AC_Error("cannot start encoder");
if (buffer_size == 0) AC_Error("no code buffer set");
mode = 1;
base = 0; // initialize encoder variables: interval and pointer
length = AC__MaxLength;
ac_pointer = code_buffer; // pointer to next data byte
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::start_decoder(void)
{
if (mode != 0) AC_Error("cannot start decoder");
if (buffer_size == 0) AC_Error("no code buffer set");
// initialize decoder: interval, pointer, initial code value
mode = 2;
length = AC__MaxLength;
ac_pointer = code_buffer + 3;
value = (unsigned(code_buffer[0]) << 24)|(unsigned(code_buffer[1]) << 16) |
(unsigned(code_buffer[2]) << 8)| unsigned(code_buffer[3]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::read_from_file(FILE * code_file)
{
unsigned shift = 0, code_bytes = 0;
int file_byte;
// read variable-length header with number of code bytes
do {
if ((file_byte = getc(code_file)) == EOF)
AC_Error("cannot read code from file");
code_bytes |= unsigned(file_byte & 0x7F) << shift;
shift += 7;
} while (file_byte & 0x80);
// read compressed data
if (code_bytes > buffer_size) AC_Error("code buffer overflow");
if (fread(code_buffer, 1, code_bytes, code_file) != code_bytes)
AC_Error("cannot read code from file");
start_decoder(); // initialize decoder
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::stop_encoder(void)
{
if (mode != 1) AC_Error("invalid to stop encoder");
mode = 0;
unsigned init_base = base; // done encoding: set final data bytes
if (length > 2 * AC__MinLength) {
base += AC__MinLength; // base offset
length = AC__MinLength >> 1; // set new length for 1 more byte
}
else {
base += AC__MinLength >> 1; // base offset
length = AC__MinLength >> 9; // set new length for 2 more bytes
}
if (init_base > base) propagate_carry(); // overflow = carry
renorm_enc_interval(); // renormalization = output last bytes
unsigned code_bytes = unsigned(ac_pointer - code_buffer);
if (code_bytes > buffer_size) AC_Error("code buffer overflow");
return code_bytes; // number of bytes used
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::write_to_file(FILE * code_file)
{
unsigned header_bytes = 0, code_bytes = stop_encoder(), nb = code_bytes;
// write variable-length header with number of code bytes
do {
int file_byte = int(nb & 0x7FU);
if ((nb >>= 7) > 0) file_byte |= 0x80;
if (putc(file_byte, code_file) == EOF)
AC_Error("cannot write compressed data to file");
header_bytes++;
} while (nb);
// write compressed data
if (fwrite(code_buffer, 1, code_bytes, code_file) != code_bytes)
AC_Error("cannot write compressed data to file");
return code_bytes + header_bytes; // bytes used
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::stop_decoder(void)
{
if (mode != 2) AC_Error("invalid to stop decoder");
mode = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - Static bit model implementation - - - - - - - - - - - - - - - - - - - - -
Static_Bit_Model::Static_Bit_Model(void)
{
bit_0_prob = 1U << (BM__LengthShift - 1); // p0 = 0.5
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Static_Bit_Model::set_probability_0(double p0)
{
if ((p0 < 0.0001)||(p0 > 0.9999)) AC_Error("invalid bit probability");
bit_0_prob = unsigned(p0 * (1 << BM__LengthShift));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - Adaptive bit model implementation - - - - - - - - - - - - - - - - - - - -
Adaptive_Bit_Model::Adaptive_Bit_Model(void)
{
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Bit_Model::reset(void)
{
// initialization to equiprobable model
bit_0_count = 1;
bit_count = 2;
bit_0_prob = 1U << (BM__LengthShift - 1);
update_cycle = bits_until_update = 4; // start with frequent updates
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Bit_Model::update(void)
{
// halve counts when a threshold is reached
if ((bit_count += update_cycle) > BM__MaxCount) {
bit_count = (bit_count + 1) >> 1;
bit_0_count = (bit_0_count + 1) >> 1;
if (bit_0_count == bit_count) ++bit_count;
}
// compute scaled bit 0 probability
unsigned scale = 0x80000000U / bit_count;
bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift);
// set frequency of model updates
update_cycle = (5 * update_cycle) >> 2;
if (update_cycle > 64) update_cycle = 64;
bits_until_update = update_cycle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Static data model implementation - - - - - - - - - - - - - - - - - - -
Static_Data_Model::Static_Data_Model(void)
{
data_symbols = 0;
distribution = 0;
}
Static_Data_Model::~Static_Data_Model(void)
{
delete [] distribution;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Static_Data_Model::set_distribution(unsigned number_of_symbols,
const double probability[])
{
if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
AC_Error("invalid number of data symbols");
if (data_symbols != number_of_symbols) { // assign memory for data model
data_symbols = number_of_symbols;
last_symbol = data_symbols - 1;
delete [] distribution;
// define size of table for fast decoding
if (data_symbols > 16) {
unsigned table_bits = 3;
while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
table_size = 1 << table_bits;
table_shift = DM__LengthShift - table_bits;
distribution = new unsigned[data_symbols+table_size+2];
decoder_table = distribution + data_symbols;
}
else { // small alphabet: no table needed
decoder_table = 0;
table_size = table_shift = 0;
distribution = new unsigned[data_symbols];
}
if (distribution == 0) AC_Error("cannot assign model memory");
}
// compute cumulative distribution, decoder table
unsigned s = 0;
double sum = 0.0, p = 1.0 / double(data_symbols);
for (unsigned k = 0; k < data_symbols; k++) {
if (probability) p = probability[k];
if ((p < 0.0001) || (p > 0.9999)) AC_Error("invalid symbol probability");
distribution[k] = unsigned(sum * (1 << DM__LengthShift));
sum += p;
if (table_size == 0) continue;
unsigned w = distribution[k] >> table_shift;
while (s < w) decoder_table[++s] = k - 1;
}
if (table_size != 0) {
decoder_table[0] = 0;
while (s <= table_size) decoder_table[++s] = data_symbols - 1;
}
if ((sum < 0.9999) || (sum > 1.0001)) AC_Error("invalid probabilities");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Adaptive data model implementation - - - - - - - - - - - - - - - - - -
Adaptive_Data_Model::Adaptive_Data_Model(void)
{
data_symbols = 0;
distribution = 0;
}
Adaptive_Data_Model::Adaptive_Data_Model(unsigned number_of_symbols)
{
data_symbols = 0;
distribution = 0;
set_alphabet(number_of_symbols);
}
Adaptive_Data_Model::~Adaptive_Data_Model(void)
{
delete [] distribution;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Data_Model::set_alphabet(unsigned number_of_symbols)
{
if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
AC_Error("invalid number of data symbols");
if (data_symbols != number_of_symbols) { // assign memory for data model
data_symbols = number_of_symbols;
last_symbol = data_symbols - 1;
delete [] distribution;
// define size of table for fast decoding
if (data_symbols > 16) {
unsigned table_bits = 3;
while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
table_size = 1 << table_bits;
table_shift = DM__LengthShift - table_bits;
distribution = new unsigned[2*data_symbols+table_size+2];
decoder_table = distribution + 2 * data_symbols;
}
else { // small alphabet: no table needed
decoder_table = 0;
table_size = table_shift = 0;
distribution = new unsigned[2*data_symbols];
}
symbol_count = distribution + data_symbols;
if (distribution == 0) AC_Error("cannot assign model memory");
}
reset(); // initialize model
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Data_Model::update(bool from_encoder)
{
// halve counts when a threshold is reached
if ((total_count += update_cycle) > DM__MaxCount) {
total_count = 0;
for (unsigned n = 0; n < data_symbols; n++)
total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
}
// compute cumulative distribution, decoder table
unsigned k, sum = 0, s = 0;
unsigned scale = 0x80000000U / total_count;
if (from_encoder || (table_size == 0))
for (k = 0; k < data_symbols; k++) {
distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
sum += symbol_count[k];
}
else {
for (k = 0; k < data_symbols; k++) {
distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
sum += symbol_count[k];
unsigned w = distribution[k] >> table_shift;
while (s < w) decoder_table[++s] = k - 1;
}
decoder_table[0] = 0;
while (s <= table_size) decoder_table[++s] = data_symbols - 1;
}
// set frequency of model updates
update_cycle = (5 * update_cycle) >> 2;
unsigned max_cycle = (data_symbols + 6) << 3;
if (update_cycle > max_cycle) update_cycle = max_cycle;
symbols_until_update = update_cycle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Data_Model::reset(void)
{
if (data_symbols == 0) return;
// restore probability estimates to uniform distribution
total_count = 0;
update_cycle = data_symbols;
for (unsigned k = 0; k < data_symbols; k++) symbol_count[k] = 1;
update(false);
symbols_until_update = update_cycle = (data_symbols + 6) >> 1;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

View File

@ -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 <stdio.h>
#include "o3dgcCommon.h"
namespace o3dgc
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Class definitions - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Static_Bit_Model // static model for binary data
{
public:
Static_Bit_Model(void);
void set_probability_0(double); // set probability of symbol '0'
private: // . . . . . . . . . . . . . . . . . . . . . .
unsigned bit_0_prob;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Static_Data_Model // static model for general data
{
public:
Static_Data_Model(void);
~Static_Data_Model(void);
unsigned model_symbols(void) { return data_symbols; }
void set_distribution(unsigned number_of_symbols,
const double probability[] = 0); // 0 means uniform
private: // . . . . . . . . . . . . . . . . . . . . . .
unsigned * distribution, * decoder_table;
unsigned data_symbols, last_symbol, table_size, table_shift;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Adaptive_Bit_Model // adaptive model for binary data
{
public:
Adaptive_Bit_Model(void);
void reset(void); // reset to equiprobable model
private: // . . . . . . . . . . . . . . . . . . . . . .
void update(void);
unsigned update_cycle, bits_until_update;
unsigned bit_0_prob, bit_0_count, bit_count;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Adaptive_Data_Model // adaptive model for binary data
{
public:
Adaptive_Data_Model(void);
Adaptive_Data_Model(unsigned number_of_symbols);
~Adaptive_Data_Model(void);
unsigned model_symbols(void) { return data_symbols; }
void reset(void); // reset to equiprobable model
void set_alphabet(unsigned number_of_symbols);
private: // . . . . . . . . . . . . . . . . . . . . . .
void update(bool);
unsigned * distribution, * symbol_count, * decoder_table;
unsigned total_count, update_cycle, symbols_until_update;
unsigned data_symbols, last_symbol, table_size, table_shift;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Encoder and decoder class - - - - - - - - - - - - - - - - - - - - - - -
// Class with both the arithmetic encoder and decoder. All compressed data is
// saved to a memory buffer
class Arithmetic_Codec
{
public:
Arithmetic_Codec(void);
~Arithmetic_Codec(void);
Arithmetic_Codec(unsigned max_code_bytes,
unsigned char * user_buffer = 0); // 0 = assign new
unsigned char * buffer(void) { return code_buffer; }
void set_buffer(unsigned max_code_bytes,
unsigned char * user_buffer = 0); // 0 = assign new
void start_encoder(void);
void start_decoder(void);
void read_from_file(FILE * code_file); // read code data, start decoder
unsigned stop_encoder(void); // returns number of bytes used
unsigned write_to_file(FILE * code_file); // stop encoder, write code data
void stop_decoder(void);
void put_bit(unsigned bit);
unsigned get_bit(void);
void put_bits(unsigned data, unsigned number_of_bits);
unsigned get_bits(unsigned number_of_bits);
void encode(unsigned bit,
Static_Bit_Model &);
unsigned decode(Static_Bit_Model &);
void encode(unsigned data,
Static_Data_Model &);
unsigned decode(Static_Data_Model &);
void encode(unsigned bit,
Adaptive_Bit_Model &);
unsigned decode(Adaptive_Bit_Model &);
void encode(unsigned data,
Adaptive_Data_Model &);
unsigned decode(Adaptive_Data_Model &);
// This section was added by K. Mammou
void ExpGolombEncode(unsigned int symbol,
int k,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1)
{
while(1)
{
if (symbol >= (unsigned int)(1<<k))
{
encode(1, bModel1);
symbol = symbol - (1<<k);
k++;
}
else
{
encode(0, bModel1); // now terminated zero of unary part
while (k--) // next binary part
{
encode((signed short)((symbol>>k)&1), bModel0);
}
break;
}
}
}
unsigned ExpGolombDecode(int k,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1)
{
unsigned int l;
int symbol = 0;
int binary_symbol = 0;
do
{
l=decode(bModel1);
if (l==1)
{
symbol += (1<<k);
k++;
}
}
while (l!=0);
while (k--) //next binary part
if (decode(bModel0)==1)
{
binary_symbol |= (1<<k);
}
return (unsigned int) (symbol+binary_symbol);
}
//----------------------------------------------------------
private: // . . . . . . . . . . . . . . . . . . . . . .
void propagate_carry(void);
void renorm_enc_interval(void);
void renorm_dec_interval(void);
unsigned char * code_buffer, * new_buffer, * ac_pointer;
unsigned base, value, length; // arithmetic coding state
unsigned buffer_size, mode; // mode: 0 = undef, 1 = encoder, 2 = decoder
};
inline long DecodeIntACEGC(Arithmetic_Codec & acd,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long exp_k,
const unsigned long M)
{
unsigned long uiValue = acd.decode(mModelValues);
if (uiValue == M)
{
uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
}
return UIntToInt(uiValue);
}
inline unsigned long DecodeUIntACEGC(Arithmetic_Codec & acd,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long exp_k,
const unsigned long M)
{
unsigned long uiValue = acd.decode(mModelValues);
if (uiValue == M)
{
uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
}
return uiValue;
}
inline void EncodeIntACEGC(long predResidual,
Arithmetic_Codec & ace,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long M)
{
unsigned long uiValue = IntToUInt(predResidual);
if (uiValue < M)
{
ace.encode(uiValue, mModelValues);
}
else
{
ace.encode(M, mModelValues);
ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
}
}
inline void EncodeUIntACEGC(long predResidual,
Arithmetic_Codec & ace,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long M)
{
unsigned long uiValue = (unsigned long) predResidual;
if (uiValue < M)
{
ace.encode(uiValue, mModelValues);
}
else
{
ace.encode(M, mModelValues);
ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#endif

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

@ -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.
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

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