Merge upstream master

pull/1001/head
johnmaf 2016-09-20 11:53:12 -04:00
commit c9f28192d9
47 changed files with 10342 additions and 115 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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