Merge pull request #972 from smalcom/gltf_o3dgc
Support for Open3DGC-compression in glTF importer/exporter.pull/1001/head
commit
c11ae8e722
|
@ -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)
|
|
@ -699,7 +699,54 @@ SET ( openddl_parser_SRCS
|
|||
)
|
||||
SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
|
||||
|
||||
SET ( open3dgc_SRCS
|
||||
../contrib/Open3DGC/o3dgcAdjacencyInfo.h
|
||||
../contrib/Open3DGC/o3dgcArithmeticCodec.cpp
|
||||
../contrib/Open3DGC/o3dgcArithmeticCodec.h
|
||||
../contrib/Open3DGC/o3dgcBinaryStream.h
|
||||
../contrib/Open3DGC/o3dgcCommon.h
|
||||
../contrib/Open3DGC/o3dgcDVEncodeParams.h
|
||||
../contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp
|
||||
../contrib/Open3DGC/o3dgcDynamicVectorDecoder.h
|
||||
../contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp
|
||||
../contrib/Open3DGC/o3dgcDynamicVectorEncoder.h
|
||||
../contrib/Open3DGC/o3dgcDynamicVector.h
|
||||
../contrib/Open3DGC/o3dgcFIFO.h
|
||||
../contrib/Open3DGC/o3dgcIndexedFaceSet.h
|
||||
../contrib/Open3DGC/o3dgcIndexedFaceSet.inl
|
||||
../contrib/Open3DGC/o3dgcSC3DMCDecoder.h
|
||||
../contrib/Open3DGC/o3dgcSC3DMCDecoder.inl
|
||||
../contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h
|
||||
../contrib/Open3DGC/o3dgcSC3DMCEncoder.h
|
||||
../contrib/Open3DGC/o3dgcSC3DMCEncoder.inl
|
||||
../contrib/Open3DGC/o3dgcTimer.h
|
||||
../contrib/Open3DGC/o3dgcTools.cpp
|
||||
../contrib/Open3DGC/o3dgcTriangleFans.cpp
|
||||
../contrib/Open3DGC/o3dgcTriangleFans.h
|
||||
../contrib/Open3DGC/o3dgcTriangleListDecoder.h
|
||||
../contrib/Open3DGC/o3dgcTriangleListDecoder.inl
|
||||
../contrib/Open3DGC/o3dgcTriangleListEncoder.h
|
||||
../contrib/Open3DGC/o3dgcTriangleListEncoder.inl
|
||||
../contrib/Open3DGC/o3dgcVector.h
|
||||
../contrib/Open3DGC/o3dgcVector.inl
|
||||
)
|
||||
SOURCE_GROUP( open3dgc FILES ${open3dgc_SRCS})
|
||||
|
||||
# Check dependencies for glTF importer with Open3DGC-compression.
|
||||
# RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file
|
||||
# has implementation for different platforms: WIN32, __MACH__ and other ("else" block).
|
||||
FIND_PACKAGE(RT QUIET)
|
||||
IF (RT_FOUND OR MSVC)
|
||||
SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 )
|
||||
ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 )
|
||||
ELSE ()
|
||||
SET (open3dgc_SRCS "")
|
||||
MESSAGE (INFO " RT-extension not found. glTF import/export will be built without Open3DGC-compression.")
|
||||
#!TODO: off course is better to remove statistics timers from o3dgc codec. Or propose to choose what to use.
|
||||
ENDIF ()
|
||||
|
||||
INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" )
|
||||
INCLUDE_DIRECTORIES( "../contrib" )
|
||||
|
||||
# VC2010 fixes
|
||||
if(MSVC10)
|
||||
|
@ -746,6 +793,7 @@ SET( assimp_src
|
|||
${Poly2Tri_SRCS}
|
||||
${Clipper_SRCS}
|
||||
${openddl_parser_SRCS}
|
||||
${open3dgc_SRCS}
|
||||
# Necessary to show the headers in the project when using the VC++ generator:
|
||||
|
||||
${PUBLIC_HEADERS}
|
||||
|
@ -820,6 +868,11 @@ else (UNZIP_FOUND)
|
|||
INCLUDE_DIRECTORIES("../")
|
||||
endif (UNZIP_FOUND)
|
||||
|
||||
# Add RT-extension library for glTF importer with Open3DGC-compression.
|
||||
IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC)
|
||||
TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY})
|
||||
ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC)
|
||||
|
||||
INSTALL( TARGETS assimp
|
||||
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
|
||||
|
|
161
code/glTFAsset.h
161
code/glTFAsset.h
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
@ -361,8 +362,6 @@ namespace glTF
|
|||
{ return id; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Classes for each glTF top-level object type
|
||||
//
|
||||
|
@ -452,6 +451,7 @@ namespace glTF
|
|||
//! A buffer points to binary geometry, animation, or skins.
|
||||
struct Buffer : public Object
|
||||
{
|
||||
/********************* Types *********************/
|
||||
public:
|
||||
|
||||
enum Type
|
||||
|
@ -460,23 +460,105 @@ namespace glTF
|
|||
Type_text
|
||||
};
|
||||
|
||||
/// \struct SEncodedRegion
|
||||
/// Descriptor of encoded region in "bufferView".
|
||||
struct SEncodedRegion
|
||||
{
|
||||
const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes.
|
||||
const size_t EncodedData_Length;///< Size of encoded region, in bytes.
|
||||
uint8_t* const DecodedData;///< Cached encoded data.
|
||||
const size_t DecodedData_Length;///< Size of decoded region, in bytes.
|
||||
const std::string ID;///< ID of the region.
|
||||
|
||||
/// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
|
||||
/// Constructor.
|
||||
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
|
||||
/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
|
||||
/// \param [in] pDecodedData - pointer to decoded data array.
|
||||
/// \param [in] pDecodedData_Length - size of encoded region, in bytes.
|
||||
/// \param [in] pID - ID of the region.
|
||||
SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
|
||||
: Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID)
|
||||
{}
|
||||
|
||||
/// \fn ~SEncodedRegion()
|
||||
/// Destructor.
|
||||
~SEncodedRegion() { delete [] DecodedData; }
|
||||
};
|
||||
|
||||
/******************* Variables *******************/
|
||||
|
||||
//std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
|
||||
size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
|
||||
//std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
|
||||
|
||||
Type type;
|
||||
|
||||
/// \var EncodedRegion_Current
|
||||
/// Pointer to currently active encoded region.
|
||||
/// Why not decoding all regions at once and not to set one buffer with decoded data?
|
||||
/// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded
|
||||
/// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But
|
||||
/// offset is counted for another regions is encoded.
|
||||
/// Example. You have two meshes. For every of it you have 4 bytes of data. That data compressed to 2 bytes. So, you have buffer with encoded data:
|
||||
/// M1_E0, M1_E1, M2_E0, M2_E1.
|
||||
/// After decoding you'll get:
|
||||
/// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3.
|
||||
/// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like
|
||||
/// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4}
|
||||
/// but in real life you'll get:
|
||||
/// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4}
|
||||
/// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded.
|
||||
/// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished
|
||||
/// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data.
|
||||
///
|
||||
/// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in
|
||||
/// exporter and importer. And, thanks to such way, there is no need to load whole file into memory.
|
||||
SEncodedRegion* EncodedRegion_Current;
|
||||
|
||||
private:
|
||||
|
||||
shared_ptr<uint8_t> mData; //!< Pointer to the data
|
||||
bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
|
||||
|
||||
/// \var EncodedRegion_List
|
||||
/// List of encoded regions.
|
||||
std::list<SEncodedRegion*> EncodedRegion_List;
|
||||
|
||||
/******************* Functions *******************/
|
||||
|
||||
public:
|
||||
|
||||
Buffer();
|
||||
~Buffer();
|
||||
|
||||
void Read(Value& obj, Asset& r);
|
||||
|
||||
bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0);
|
||||
|
||||
/// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
|
||||
/// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
|
||||
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
|
||||
/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
|
||||
/// \param [in] pDecodedData - pointer to decoded data array.
|
||||
/// \param [in] pDecodedData_Length - size of encoded region, in bytes.
|
||||
/// \param [in] pID - ID of the region.
|
||||
void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID);
|
||||
|
||||
/// \fn void EncodedRegion_SetCurrent(const std::string& pID)
|
||||
/// Select current encoded region by ID. \sa EncodedRegion_Current.
|
||||
/// \param [in] pID - ID of the region.
|
||||
void EncodedRegion_SetCurrent(const std::string& pID);
|
||||
|
||||
/// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
|
||||
/// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
|
||||
/// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
|
||||
/// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
|
||||
/// \param [in] pReplace_Data - pointer to array with new data for buffer.
|
||||
/// \param [in] pReplace_Count - count of bytes in new data.
|
||||
/// \return true - if successfully replaced, false if input arguments is out of range.
|
||||
bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count);
|
||||
|
||||
size_t AppendData(uint8_t* data, size_t length);
|
||||
void Grow(size_t amount);
|
||||
|
||||
|
@ -492,7 +574,6 @@ namespace glTF
|
|||
static const char* TranslateId(Asset& r, const char* id);
|
||||
};
|
||||
|
||||
|
||||
//! A view into a buffer generally representing a subset of the buffer.
|
||||
struct BufferView : public Object
|
||||
{
|
||||
|
@ -502,11 +583,9 @@ namespace glTF
|
|||
|
||||
BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
|
||||
|
||||
BufferView() {}
|
||||
void Read(Value& obj, Asset& r);
|
||||
};
|
||||
|
||||
|
||||
struct Camera : public Object
|
||||
{
|
||||
enum Type
|
||||
|
@ -631,10 +710,77 @@ namespace glTF
|
|||
Ref<Material> 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::list<SExtension*> Extension;///< List of extensions used in 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
|
||||
|
@ -805,6 +951,7 @@ namespace glTF
|
|||
|
||||
Ref<T> Get(const char* id);
|
||||
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 std::string& id)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -40,6 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "StringUtils.h"
|
||||
|
||||
// Header files, Assimp
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
// Header files, Open3DGC.
|
||||
# include <Open3DGC/o3dgcSC3DMCDecoder.h>
|
||||
#endif
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace glTF {
|
||||
|
@ -243,9 +251,14 @@ Ref<T> LazyDict<T>::Create(const char* id)
|
|||
|
||||
|
||||
inline Buffer::Buffer()
|
||||
: byteLength(0), type(Type_arraybuffer), mIsSpecial(false)
|
||||
: byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false)
|
||||
{ }
|
||||
|
||||
inline Buffer::~Buffer()
|
||||
{
|
||||
for(SEncodedRegion* reg : EncodedRegion_List) delete reg;
|
||||
}
|
||||
|
||||
inline const char* Buffer::TranslateId(Asset& r, const char* id)
|
||||
{
|
||||
// Compatibility with old spec
|
||||
|
@ -326,6 +339,79 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO
|
|||
return true;
|
||||
}
|
||||
|
||||
inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
|
||||
{
|
||||
// Check pointer to data
|
||||
if(pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided.");
|
||||
|
||||
// Check offset
|
||||
if(pOffset > byteLength)
|
||||
{
|
||||
const uint8_t val_size = 32;
|
||||
|
||||
char val[val_size];
|
||||
|
||||
ai_snprintf(val, val_size, "%llu", (long long)pOffset);
|
||||
throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region.");
|
||||
}
|
||||
|
||||
// Check length
|
||||
if((pOffset + pEncodedData_Length) > byteLength)
|
||||
{
|
||||
const uint8_t val_size = 64;
|
||||
|
||||
char val[val_size];
|
||||
|
||||
ai_snprintf(val, val_size, "%llu, %llu", (long long)pOffset, (long long)pEncodedData_Length);
|
||||
throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range.");
|
||||
}
|
||||
|
||||
// Add new region
|
||||
EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID));
|
||||
// And set new value for "byteLength"
|
||||
byteLength += (pDecodedData_Length - pEncodedData_Length);
|
||||
}
|
||||
|
||||
inline void Buffer::EncodedRegion_SetCurrent(const std::string& pID)
|
||||
{
|
||||
if((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return;
|
||||
|
||||
for(SEncodedRegion* reg : EncodedRegion_List)
|
||||
{
|
||||
if(reg->ID == pID)
|
||||
{
|
||||
EncodedRegion_Current = reg;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found.");
|
||||
}
|
||||
|
||||
inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
|
||||
{
|
||||
const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count;
|
||||
|
||||
uint8_t* new_data;
|
||||
|
||||
if((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false;
|
||||
|
||||
new_data = new uint8_t[new_data_size];
|
||||
// Copy data which place before replacing part.
|
||||
memcpy(new_data, mData.get(), pBufferData_Offset);
|
||||
// Copy new data.
|
||||
memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count);
|
||||
// Copy data which place after replacing part.
|
||||
memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset);
|
||||
// Apply new data
|
||||
mData.reset(new_data);
|
||||
byteLength = new_data_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline size_t Buffer::AppendData(uint8_t* data, size_t length)
|
||||
{
|
||||
size_t offset = this->byteLength;
|
||||
|
@ -343,6 +429,9 @@ inline void Buffer::Grow(size_t amount)
|
|||
byteLength += amount;
|
||||
}
|
||||
|
||||
//
|
||||
// struct BufferView
|
||||
//
|
||||
|
||||
inline void BufferView::Read(Value& obj, Asset& r)
|
||||
{
|
||||
|
@ -355,7 +444,9 @@ inline void BufferView::Read(Value& obj, Asset& r)
|
|||
byteLength = MemberOrDefault(obj, "byteLength", 0u);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// struct Accessor
|
||||
//
|
||||
|
||||
inline void Accessor::Read(Value& obj, Asset& r)
|
||||
{
|
||||
|
@ -395,6 +486,17 @@ inline uint8_t* Accessor::GetPointer()
|
|||
if (!basePtr) return 0;
|
||||
|
||||
size_t offset = byteOffset + bufferView->byteOffset;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
for (unsigned int i = 0; i < primitives->Size(); ++i) {
|
||||
Value& primitive = (*primitives)[i];
|
||||
|
@ -700,22 +803,250 @@ inline void Mesh::Read(Value& obj, Asset& r)
|
|||
if (GetAttribVector(prim, attr, vec, undPos)) {
|
||||
size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
|
||||
if ((*vec).size() <= idx) (*vec).resize(idx + 1);
|
||||
(*vec)[idx] = r.accessors.Get(it->value.GetString());
|
||||
(*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Value* indices = FindString(primitive, "indices")) {
|
||||
prim.indices = r.accessors.Get(indices->GetString());
|
||||
prim.indices = pAsset_Root.accessors.Get(indices->GetString());
|
||||
}
|
||||
|
||||
if (Value* material = FindString(primitive, "material")) {
|
||||
prim.material = r.materials.Get(material->GetString());
|
||||
}
|
||||
prim.material = pAsset_Root.materials.Get(material->GetString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************** Mesh extensions ******************/
|
||||
Value* json_extensions = FindObject(pJSON_Object, "extensions");
|
||||
|
||||
if(json_extensions == nullptr) goto mr_skip_extensions;
|
||||
|
||||
for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++)
|
||||
{
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
if(it_memb->name.GetString() == std::string("Open3DGC-compression"))
|
||||
{
|
||||
// Search for compressed data.
|
||||
// Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and
|
||||
// new data will replace old encoded part by request. In fact \"compressedData\" is kind of "accessor" structure.
|
||||
Value* comp_data = FindObject(it_memb->value, "compressedData");
|
||||
|
||||
if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\".");
|
||||
|
||||
DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data.");
|
||||
|
||||
/************** Read data from JSON-document **************/
|
||||
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
|
||||
if(!ReadMember(*comp_data, pFieldName, pOut)) \
|
||||
{ \
|
||||
throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); \
|
||||
}
|
||||
|
||||
const char* mode_str;
|
||||
const char* type_str;
|
||||
ComponentType component_type;
|
||||
SCompression_Open3DGC* ext_o3dgc = new SCompression_Open3DGC;
|
||||
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("buffer", ext_o3dgc->Buffer);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", ext_o3dgc->Offset);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("count", ext_o3dgc->Count);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", ext_o3dgc->IndicesCount);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", ext_o3dgc->VerticesCount);
|
||||
|
||||
#undef MESH_READ_COMPRESSEDDATA_MEMBER
|
||||
|
||||
// Check some values
|
||||
if(strcmp(type_str, "SCALAR")) throw DeadlyImportError("GLTF: only \"SCALAR\" type is supported for compressed data.");
|
||||
if(component_type != ComponentType_UNSIGNED_BYTE) throw DeadlyImportError("GLTF: only \"UNSIGNED_BYTE\" component type is supported for compressed data.");
|
||||
|
||||
// Set read/write data mode.
|
||||
if(strcmp(mode_str, "binary") == 0)
|
||||
ext_o3dgc->Binary = true;
|
||||
else if(strcmp(mode_str, "ascii") == 0)
|
||||
ext_o3dgc->Binary = false;
|
||||
else
|
||||
throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\".");
|
||||
|
||||
/************************ Decoding ************************/
|
||||
Decode_O3DGC(*ext_o3dgc, pAsset_Root);
|
||||
Extension.push_back(ext_o3dgc);// store info in mesh extensions list.
|
||||
}// if(it_memb->name.GetString() == "Open3DGC-compression")
|
||||
else
|
||||
#endif
|
||||
{
|
||||
throw DeadlyImportError(std::string("GLTF: Unknown mesh extension: \"") + it_memb->name.GetString() + "\".");
|
||||
}
|
||||
}// for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
|
||||
|
||||
mr_skip_extensions:
|
||||
|
||||
return;// After label some operators must be present.
|
||||
}
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
|
||||
{
|
||||
typedef unsigned short IndicesType;///< \sa glTFExporter::ExportMeshes.
|
||||
|
||||
o3dgc::SC3DMCDecoder<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)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -56,11 +56,11 @@ namespace glTF {
|
|||
inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
|
||||
val.SetArray();
|
||||
val.Reserve(N, al);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
for (decltype(N) i = 0; i < N; ++i) {
|
||||
val.PushBack(r[i], al);
|
||||
}
|
||||
return val;
|
||||
};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
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);
|
||||
}
|
||||
obj.AddMember(StringRef(fieldId), lst, al);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -199,6 +199,60 @@ namespace glTF {
|
|||
|
||||
inline void Write(Value& obj, Mesh& m, AssetWriter& w)
|
||||
{
|
||||
/********************* Name **********************/
|
||||
obj.AddMember("name", m.name, w.mAl);
|
||||
|
||||
/**************** Mesh extensions ****************/
|
||||
if(m.Extension.size() > 0)
|
||||
{
|
||||
Value json_extensions;
|
||||
|
||||
json_extensions.SetObject();
|
||||
for(Mesh::SExtension* ptr_ext : m.Extension)
|
||||
{
|
||||
switch(ptr_ext->Type)
|
||||
{
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
case Mesh::SExtension::EType::Compression_Open3DGC:
|
||||
{
|
||||
Value json_comp_data;
|
||||
Mesh::SCompression_Open3DGC* ptr_ext_comp = (Mesh::SCompression_Open3DGC*)ptr_ext;
|
||||
|
||||
// filling object "compressedData"
|
||||
json_comp_data.SetObject();
|
||||
json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl);
|
||||
json_comp_data.AddMember("byteOffset", ptr_ext_comp->Offset, w.mAl);
|
||||
json_comp_data.AddMember("componentType", 5121, w.mAl);
|
||||
json_comp_data.AddMember("type", "SCALAR", w.mAl);
|
||||
json_comp_data.AddMember("count", ptr_ext_comp->Count, w.mAl);
|
||||
if(ptr_ext_comp->Binary)
|
||||
json_comp_data.AddMember("mode", "binary", w.mAl);
|
||||
else
|
||||
json_comp_data.AddMember("mode", "ascii", w.mAl);
|
||||
|
||||
json_comp_data.AddMember("indicesCount", ptr_ext_comp->IndicesCount, w.mAl);
|
||||
json_comp_data.AddMember("verticesCount", ptr_ext_comp->VerticesCount, w.mAl);
|
||||
// filling object "Open3DGC-compression"
|
||||
Value json_o3dgc;
|
||||
|
||||
json_o3dgc.SetObject();
|
||||
json_o3dgc.AddMember("compressedData", json_comp_data, w.mAl);
|
||||
// add member to object "extensions"
|
||||
json_extensions.AddMember("Open3DGC-compression", json_o3dgc, w.mAl);
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported.");
|
||||
}// switch(ptr_ext->Type)
|
||||
}// for(Mesh::SExtension* ptr_ext : m.Extension)
|
||||
|
||||
// Add extensions to mesh
|
||||
obj.AddMember("extensions", json_extensions, w.mAl);
|
||||
}// if(m.Extension.size() > 0)
|
||||
|
||||
/****************** Primitives *******************/
|
||||
Value primitives;
|
||||
primitives.SetArray();
|
||||
primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -58,10 +58,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
// Header files, standart library.
|
||||
#include <memory>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "glTFAssetWriter.h"
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
// Header files, Open3DGC.
|
||||
# include <Open3DGC/o3dgcSC3DMCEncoder.h>
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -267,6 +274,22 @@ void glTFExporter::ExportMaterials()
|
|||
|
||||
void glTFExporter::ExportMeshes()
|
||||
{
|
||||
// Not for
|
||||
// using IndicesType = decltype(aiFace::mNumIndices);
|
||||
// But yes for
|
||||
// using IndicesType = unsigned short;
|
||||
// because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
|
||||
typedef unsigned short IndicesType;
|
||||
|
||||
// Variables needed for compression. BEGIN.
|
||||
// Indices, not pointers - because pointer to buffer is changin while writing to it.
|
||||
size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
|
||||
size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
|
||||
std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
|
||||
size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
|
||||
bool comp_allow;// Point that data of current mesh can be compressed.
|
||||
// Variables needed for compression. END.
|
||||
|
||||
std::string bufferId = mAsset->FindUniqueID("", "buffer");
|
||||
|
||||
Ref<Buffer> b = mAsset->GetBodyBuffer();
|
||||
|
@ -274,8 +297,33 @@ void glTFExporter::ExportMeshes()
|
|||
b = mAsset->buffers.Create(bufferId);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
|
||||
const aiMesh* aim = mScene->mMeshes[i];
|
||||
for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
|
||||
const aiMesh* aim = mScene->mMeshes[idx_mesh];
|
||||
|
||||
// Check if compressing requested and mesh can be encoded.
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
comp_allow = mProperties->GetPropertyBool("extensions.Open3DGC.use", false);
|
||||
#else
|
||||
comp_allow = false;
|
||||
#endif
|
||||
|
||||
if(comp_allow && (aim->mPrimitiveTypes == aiPrimitiveType_TRIANGLE) && (aim->mNumVertices > 0) && (aim->mNumFaces > 0))
|
||||
{
|
||||
idx_srcdata_tc.clear();
|
||||
idx_srcdata_tc.reserve(AI_MAX_NUMBER_OF_TEXTURECOORDS);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
if(aim->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
|
||||
msg = "all primitives of the mesh must be a triangles.";
|
||||
else
|
||||
msg = "mesh must has vertices and faces.";
|
||||
|
||||
DefaultLogger::get()->warn("GLTF: can not use Open3DGC-compression: " + msg);
|
||||
comp_allow = false;
|
||||
}
|
||||
|
||||
std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh");
|
||||
Ref<Mesh> m = mAsset->meshes.Create(meshId);
|
||||
|
@ -284,12 +332,20 @@ void glTFExporter::ExportMeshes()
|
|||
|
||||
p.material = mAsset->materials.Get(aim->mMaterialIndex);
|
||||
|
||||
/******************* Vertices ********************/
|
||||
// If compression is used then you need parameters of uncompressed region: begin and size. At this step "begin" is stored.
|
||||
if(comp_allow) idx_srcdata_begin = b->byteLength;
|
||||
|
||||
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||
if (v) p.attributes.position.push_back(v);
|
||||
|
||||
/******************** Normals ********************/
|
||||
if(comp_allow && (aim->mNormals > 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array.
|
||||
|
||||
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||
if (n) p.attributes.normal.push_back(n);
|
||||
|
||||
/************** Texture coordinates **************/
|
||||
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
// Flip UV y coords
|
||||
if (aim -> mNumUVComponents[i] > 1) {
|
||||
|
@ -300,20 +356,27 @@ void glTFExporter::ExportMeshes()
|
|||
|
||||
if (aim->mNumUVComponents[i] > 0) {
|
||||
AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
|
||||
|
||||
if(comp_allow) idx_srcdata_tc.push_back(b->byteLength);// Store index of texture coordinates array.
|
||||
|
||||
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true);
|
||||
if (tc) p.attributes.texcoord.push_back(tc);
|
||||
}
|
||||
}
|
||||
|
||||
/*************** Vertices indices ****************/
|
||||
idx_srcdata_ind = b->byteLength;// Store index of indices array.
|
||||
|
||||
if (aim->mNumFaces > 0) {
|
||||
std::vector<IndicesType> indices;
|
||||
unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices;
|
||||
std::vector<uint16_t> indices;
|
||||
indices.resize(aim->mNumFaces * nIndicesPerFace);
|
||||
for (size_t i = 0; i < aim->mNumFaces; ++i) {
|
||||
for (size_t j = 0; j < nIndicesPerFace; ++j) {
|
||||
indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]);
|
||||
}
|
||||
}
|
||||
|
||||
p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT, true);
|
||||
}
|
||||
|
||||
|
@ -327,7 +390,99 @@ void glTFExporter::ExportMeshes()
|
|||
default: // aiPrimitiveType_TRIANGLE
|
||||
p.mode = PrimitiveMode_TRIANGLES;
|
||||
}
|
||||
|
||||
/****************** Compression ******************/
|
||||
///TODO: animation: weights, joints.
|
||||
if(comp_allow)
|
||||
{
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
// Only one type of compression supported at now - Open3DGC.
|
||||
//
|
||||
o3dgc::BinaryStream bs;
|
||||
o3dgc::SC3DMCEncoder<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)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -259,6 +259,38 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
|
|||
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
|
||||
Mesh& mesh = r.meshes[m];
|
||||
|
||||
// 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());
|
||||
|
||||
|
@ -294,14 +326,13 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
|
|||
}
|
||||
|
||||
Mesh::Primitive::Attributes& attr = prim.attributes;
|
||||
|
||||
if (attr.position.size() > 0 && attr.position[0]) {
|
||||
aim->mNumVertices = attr.position[0]->count;
|
||||
attr.position[0]->ExtractData(aim->mVertices);
|
||||
}
|
||||
|
||||
if (attr.normal.size() > 0 && attr.normal[0]) {
|
||||
attr.normal[0]->ExtractData(aim->mNormals);
|
||||
}
|
||||
if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals);
|
||||
|
||||
for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
|
||||
attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
|
||||
|
@ -641,7 +672,7 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS
|
|||
|
||||
// TODO: it does not split the loaded vertices, should it?
|
||||
//pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
|
||||
Assimp::MakeVerboseFormatProcess process;
|
||||
MakeVerboseFormatProcess process;
|
||||
process.Execute(pScene);
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue