From 054820e6ffc03f1a914f2bc688d7f030cf01894b Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Wed, 3 Aug 2016 03:34:54 +0300 Subject: [PATCH 01/32] [+] Added Open3DGC codec from KhronosGroup repository. --- contrib/Open3DGC/o3dgcAdjacencyInfo.h | 155 +++ contrib/Open3DGC/o3dgcArithmeticCodec.cpp | 863 ++++++++++++++++ contrib/Open3DGC/o3dgcArithmeticCodec.h | 339 +++++++ contrib/Open3DGC/o3dgcBinaryStream.h | 430 ++++++++ contrib/Open3DGC/o3dgcCommon.h | 412 ++++++++ contrib/Open3DGC/o3dgcDVEncodeParams.h | 62 ++ contrib/Open3DGC/o3dgcDynamicVector.h | 84 ++ .../Open3DGC/o3dgcDynamicVectorDecoder.cpp | 278 ++++++ contrib/Open3DGC/o3dgcDynamicVectorDecoder.h | 76 ++ .../Open3DGC/o3dgcDynamicVectorEncoder.cpp | 295 ++++++ contrib/Open3DGC/o3dgcDynamicVectorEncoder.h | 79 ++ contrib/Open3DGC/o3dgcFIFO.h | 97 ++ contrib/Open3DGC/o3dgcIndexedFaceSet.h | 263 +++++ contrib/Open3DGC/o3dgcIndexedFaceSet.inl | 47 + contrib/Open3DGC/o3dgcSC3DMCDecoder.h | 111 +++ contrib/Open3DGC/o3dgcSC3DMCDecoder.inl | 850 ++++++++++++++++ contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h | 140 +++ contrib/Open3DGC/o3dgcSC3DMCEncoder.h | 116 +++ contrib/Open3DGC/o3dgcSC3DMCEncoder.inl | 927 ++++++++++++++++++ contrib/Open3DGC/o3dgcTimer.h | 132 +++ contrib/Open3DGC/o3dgcTools.cpp | 22 + contrib/Open3DGC/o3dgcTriangleFans.cpp | 475 +++++++++ contrib/Open3DGC/o3dgcTriangleFans.h | 291 ++++++ contrib/Open3DGC/o3dgcTriangleListDecoder.h | 133 +++ contrib/Open3DGC/o3dgcTriangleListDecoder.inl | 364 +++++++ contrib/Open3DGC/o3dgcTriangleListEncoder.h | 101 ++ contrib/Open3DGC/o3dgcTriangleListEncoder.inl | 719 ++++++++++++++ contrib/Open3DGC/o3dgcVector.h | 184 ++++ contrib/Open3DGC/o3dgcVector.inl | 317 ++++++ 29 files changed, 8362 insertions(+) create mode 100644 contrib/Open3DGC/o3dgcAdjacencyInfo.h create mode 100644 contrib/Open3DGC/o3dgcArithmeticCodec.cpp create mode 100644 contrib/Open3DGC/o3dgcArithmeticCodec.h create mode 100644 contrib/Open3DGC/o3dgcBinaryStream.h create mode 100644 contrib/Open3DGC/o3dgcCommon.h create mode 100644 contrib/Open3DGC/o3dgcDVEncodeParams.h create mode 100644 contrib/Open3DGC/o3dgcDynamicVector.h create mode 100644 contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp create mode 100644 contrib/Open3DGC/o3dgcDynamicVectorDecoder.h create mode 100644 contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp create mode 100644 contrib/Open3DGC/o3dgcDynamicVectorEncoder.h create mode 100644 contrib/Open3DGC/o3dgcFIFO.h create mode 100644 contrib/Open3DGC/o3dgcIndexedFaceSet.h create mode 100644 contrib/Open3DGC/o3dgcIndexedFaceSet.inl create mode 100644 contrib/Open3DGC/o3dgcSC3DMCDecoder.h create mode 100644 contrib/Open3DGC/o3dgcSC3DMCDecoder.inl create mode 100644 contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h create mode 100644 contrib/Open3DGC/o3dgcSC3DMCEncoder.h create mode 100644 contrib/Open3DGC/o3dgcSC3DMCEncoder.inl create mode 100644 contrib/Open3DGC/o3dgcTimer.h create mode 100644 contrib/Open3DGC/o3dgcTools.cpp create mode 100644 contrib/Open3DGC/o3dgcTriangleFans.cpp create mode 100644 contrib/Open3DGC/o3dgcTriangleFans.h create mode 100644 contrib/Open3DGC/o3dgcTriangleListDecoder.h create mode 100644 contrib/Open3DGC/o3dgcTriangleListDecoder.inl create mode 100644 contrib/Open3DGC/o3dgcTriangleListEncoder.h create mode 100644 contrib/Open3DGC/o3dgcTriangleListEncoder.inl create mode 100644 contrib/Open3DGC/o3dgcVector.h create mode 100644 contrib/Open3DGC/o3dgcVector.inl diff --git a/contrib/Open3DGC/o3dgcAdjacencyInfo.h b/contrib/Open3DGC/o3dgcAdjacencyInfo.h new file mode 100644 index 000000000..6b53a242d --- /dev/null +++ b/contrib/Open3DGC/o3dgcAdjacencyInfo.h @@ -0,0 +1,155 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_ADJACENCY_INFO_H +#define O3DGC_ADJACENCY_INFO_H + +#include "o3dgcCommon.h" + +namespace o3dgc +{ + const long O3DGC_MIN_NEIGHBORS_SIZE = 128; + const long O3DGC_MIN_NUM_NEIGHBORS_SIZE = 16; + //! + class AdjacencyInfo + { + public: + //! Constructor. + AdjacencyInfo(long numNeighborsSize = O3DGC_MIN_NUM_NEIGHBORS_SIZE, + long neighborsSize = O3DGC_MIN_NUM_NEIGHBORS_SIZE) + { + m_numElements = 0; + m_neighborsSize = neighborsSize; + m_numNeighborsSize = numNeighborsSize; + m_numNeighbors = new long [m_numNeighborsSize]; + m_neighbors = new long [m_neighborsSize ]; + }; + //! Destructor. + ~AdjacencyInfo(void) + { + delete [] m_neighbors; + delete [] m_numNeighbors; + }; + O3DGCErrorCode Allocate(long numNeighborsSize, long neighborsSize) + { + m_numElements = numNeighborsSize; + if (neighborsSize > m_neighborsSize) + { + delete [] m_numNeighbors; + m_neighborsSize = neighborsSize; + m_numNeighbors = new long [m_numNeighborsSize]; + } + if (numNeighborsSize > m_numNeighborsSize) + { + delete [] m_neighbors; + m_numNeighborsSize = numNeighborsSize; + m_neighbors = new long [m_neighborsSize]; + } + return O3DGC_OK; + } + O3DGCErrorCode AllocateNumNeighborsArray(long numElements) + { + if (numElements > m_numNeighborsSize) + { + delete [] m_numNeighbors; + m_numNeighborsSize = numElements; + m_numNeighbors = new long [m_numNeighborsSize]; + } + m_numElements = numElements; + return O3DGC_OK; + } + O3DGCErrorCode AllocateNeighborsArray() + { + for(long i = 1; i < m_numElements; ++i) + { + m_numNeighbors[i] += m_numNeighbors[i-1]; + } + if (m_numNeighbors[m_numElements-1] > m_neighborsSize) + { + delete [] m_neighbors; + m_neighborsSize = m_numNeighbors[m_numElements-1]; + m_neighbors = new long [m_neighborsSize]; + } + return O3DGC_OK; + } + O3DGCErrorCode ClearNumNeighborsArray() + { + memset(m_numNeighbors, 0x00, sizeof(long) * m_numElements); + return O3DGC_OK; + } + O3DGCErrorCode ClearNeighborsArray() + { + memset(m_neighbors, 0xFF, sizeof(long) * m_neighborsSize); + return O3DGC_OK; + } + O3DGCErrorCode AddNeighbor(long element, long neighbor) + { + assert(m_numNeighbors[element] <= m_numNeighbors[m_numElements-1]); + long p0 = Begin(element); + long p1 = End(element); + for(long p = p0; p < p1; p++) + { + if (m_neighbors[p] == -1) + { + m_neighbors[p] = neighbor; + return O3DGC_OK; + } + } + return O3DGC_ERROR_BUFFER_FULL; + } + long Begin(long element) const + { + assert(element < m_numElements); + assert(element >= 0); + return (element>0)?m_numNeighbors[element-1]:0; + } + long End(long element) const + { + assert(element < m_numElements); + assert(element >= 0); + return m_numNeighbors[element]; + } + long GetNeighbor(long element) const + { + assert(element < m_neighborsSize); + assert(element >= 0); + return m_neighbors[element]; + } + long GetNumNeighbors(long element) const + { + return End(element) - Begin(element); + } + long * const GetNumNeighborsBuffer() { return m_numNeighbors;} + long * const GetNeighborsBuffer() { return m_neighbors;} + + private: + long m_neighborsSize; // actual allocated size for m_neighbors + long m_numNeighborsSize; // actual allocated size for m_numNeighbors + long m_numElements; // number of elements + long * m_neighbors; // + long * m_numNeighbors; // + }; +} +#endif // O3DGC_ADJACENCY_INFO_H + diff --git a/contrib/Open3DGC/o3dgcArithmeticCodec.cpp b/contrib/Open3DGC/o3dgcArithmeticCodec.cpp new file mode 100644 index 000000000..1d160ba95 --- /dev/null +++ b/contrib/Open3DGC/o3dgcArithmeticCodec.cpp @@ -0,0 +1,863 @@ +/* +Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + +*/ +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// **************************** - +// ARITHMETIC CODING EXAMPLES - +// **************************** - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// Fast arithmetic coding implementation - +// -> 32-bit variables, 32-bit product, periodic updates, table decoding - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// Version 1.00 - April 25, 2004 - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// WARNING - +// ========= - +// - +// The only purpose of this program is to demonstrate the basic principles - +// of arithmetic coding. It is provided as is, without any express or - +// implied warranty, without even the warranty of fitness for any particular - +// purpose, or that the implementations are correct. - +// - +// Permission to copy and redistribute this code is hereby granted, provided - +// that this warning and copyright notices are not removed or altered. - +// - +// Copyright (c) 2004 by Amir Said (said@ieee.org) & - +// William A. Pearlman (pearlw@ecse.rpi.edu) - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// A description of the arithmetic coding method used here is available in - +// - +// Lossless Compression Handbook, ed. K. Sayood - +// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - +// - +// A. Said, Introduction to Arithetic Coding Theory and Practice - +// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +// - - Inclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#include +#include "o3dgcArithmeticCodec.h" + +namespace o3dgc +{ + // - - Constants - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + const unsigned AC__MinLength = 0x01000000U; // threshold for renormalization + const unsigned AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length + + // Maximum values for binary models + const unsigned BM__LengthShift = 13; // length bits discarded before mult. + const unsigned BM__MaxCount = 1 << BM__LengthShift; // for adaptive models + + // Maximum values for general models + const unsigned DM__LengthShift = 15; // length bits discarded before mult. + const unsigned DM__MaxCount = 1 << DM__LengthShift; // for adaptive models + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - - Static functions - - - - - - - - - - - - - - - - - - - - - - - - - - - + + static void AC_Error(const char * msg) + { + fprintf(stderr, "\n\n -> Arithmetic coding error: "); + fputs(msg, stderr); + fputs("\n Execution terminated!\n", stderr); + getchar(); + exit(1); + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - - Coding implementations - - - - - - - - - - - - - - - - - - - - - - - - + + inline void Arithmetic_Codec::propagate_carry(void) + { + unsigned char * p; // carry propagation on compressed data buffer + for (p = ac_pointer - 1; *p == 0xFFU; p--) *p = 0; + ++*p; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + inline void Arithmetic_Codec::renorm_enc_interval(void) + { + do { // output and discard top byte + *ac_pointer++ = (unsigned char)(base >> 24); + base <<= 8; + } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + inline void Arithmetic_Codec::renorm_dec_interval(void) + { + do { // read least-significant byte + value = (value << 8) | unsigned(*++ac_pointer); + } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::put_bit(unsigned bit) + { + #ifdef _DEBUG + if (mode != 1) AC_Error("encoder not initialized"); + #endif + + length >>= 1; // halve interval + if (bit) { + unsigned init_base = base; + base += length; // move base + if (init_base > base) propagate_carry(); // overflow = carry + } + + if (length < AC__MinLength) renorm_enc_interval(); // renormalization + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::get_bit(void) + { + #ifdef _DEBUG + if (mode != 2) AC_Error("decoder not initialized"); + #endif + + length >>= 1; // halve interval + unsigned bit = (value >= length); // decode bit + if (bit) value -= length; // move base + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + return bit; // return data bit value + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::put_bits(unsigned data, unsigned bits) + { + #ifdef _DEBUG + if (mode != 1) AC_Error("encoder not initialized"); + if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits"); + if (data >= (1U << bits)) AC_Error("invalid data"); + #endif + + unsigned init_base = base; + base += data * (length >>= bits); // new interval base and length + + if (init_base > base) propagate_carry(); // overflow = carry + if (length < AC__MinLength) renorm_enc_interval(); // renormalization + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::get_bits(unsigned bits) + { + #ifdef _DEBUG + if (mode != 2) AC_Error("decoder not initialized"); + if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits"); + #endif + + unsigned s = value / (length >>= bits); // decode symbol, change length + + value -= length * s; // update interval + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + return s; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::encode(unsigned bit, + Static_Bit_Model & M) + { + #ifdef _DEBUG + if (mode != 1) AC_Error("encoder not initialized"); + #endif + + unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 + // update interval + if (bit == 0) + length = x; + else { + unsigned init_base = base; + base += x; + length -= x; + if (init_base > base) propagate_carry(); // overflow = carry + } + + if (length < AC__MinLength) renorm_enc_interval(); // renormalization + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::decode(Static_Bit_Model & M) + { + #ifdef _DEBUG + if (mode != 2) AC_Error("decoder not initialized"); + #endif + + unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 + unsigned bit = (value >= x); // decision + // update & shift interval + if (bit == 0) + length = x; + else { + value -= x; // shifted interval base = 0 + length -= x; + } + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + return bit; // return data bit value + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::encode(unsigned bit, + Adaptive_Bit_Model & M) + { + #ifdef _DEBUG + if (mode != 1) AC_Error("encoder not initialized"); + #endif + + unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 + // update interval + if (bit == 0) { + length = x; + ++M.bit_0_count; + } + else { + unsigned init_base = base; + base += x; + length -= x; + if (init_base > base) propagate_carry(); // overflow = carry + } + + if (length < AC__MinLength) renorm_enc_interval(); // renormalization + + if (--M.bits_until_update == 0) M.update(); // periodic model update + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::decode(Adaptive_Bit_Model & M) + { + #ifdef _DEBUG + if (mode != 2) AC_Error("decoder not initialized"); + #endif + + unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 + unsigned bit = (value >= x); // decision + // update interval + if (bit == 0) { + length = x; + ++M.bit_0_count; + } + else { + value -= x; + length -= x; + } + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + if (--M.bits_until_update == 0) M.update(); // periodic model update + + return bit; // return data bit value + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::encode(unsigned data, + Static_Data_Model & M) + { + #ifdef _DEBUG + if (mode != 1) AC_Error("encoder not initialized"); + if (data >= M.data_symbols) AC_Error("invalid data symbol"); + #endif + + unsigned x, init_base = base; + // compute products + if (data == M.last_symbol) { + x = M.distribution[data] * (length >> DM__LengthShift); + base += x; // update interval + length -= x; // no product needed + } + else { + x = M.distribution[data] * (length >>= DM__LengthShift); + base += x; // update interval + length = M.distribution[data+1] * length - x; + } + + if (init_base > base) propagate_carry(); // overflow = carry + + if (length < AC__MinLength) renorm_enc_interval(); // renormalization + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::decode(Static_Data_Model & M) + { + #ifdef _DEBUG + if (mode != 2) AC_Error("decoder not initialized"); + #endif + + unsigned n, s, x, y = length; + + if (M.decoder_table) { // use table look-up for faster decoding + + unsigned dv = value / (length >>= DM__LengthShift); + unsigned t = dv >> M.table_shift; + + s = M.decoder_table[t]; // initial decision based on table look-up + n = M.decoder_table[t+1] + 1; + + while (n > s + 1) { // finish with bisection search + unsigned m = (s + n) >> 1; + if (M.distribution[m] > dv) n = m; else s = m; + } + // compute products + x = M.distribution[s] * length; + if (s != M.last_symbol) y = M.distribution[s+1] * length; + } + + else { // decode using only multiplications + + x = s = 0; + length >>= DM__LengthShift; + unsigned m = (n = M.data_symbols) >> 1; + // decode via bisection search + do { + unsigned z = length * M.distribution[m]; + if (z > value) { + n = m; + y = z; // value is smaller + } + else { + s = m; + x = z; // value is larger or equal + } + } while ((m = (s + n) >> 1) != s); + } + + value -= x; // update interval + length = y - x; + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + return s; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::encode(unsigned data, + Adaptive_Data_Model & M) + { + #ifdef _DEBUG + if (mode != 1) AC_Error("encoder not initialized"); + if (data >= M.data_symbols) + { + AC_Error("invalid data symbol"); + } + #endif + + unsigned x, init_base = base; + // compute products + if (data == M.last_symbol) { + x = M.distribution[data] * (length >> DM__LengthShift); + base += x; // update interval + length -= x; // no product needed + } + else { + x = M.distribution[data] * (length >>= DM__LengthShift); + base += x; // update interval + length = M.distribution[data+1] * length - x; + } + + if (init_base > base) propagate_carry(); // overflow = carry + + if (length < AC__MinLength) renorm_enc_interval(); // renormalization + + ++M.symbol_count[data]; + if (--M.symbols_until_update == 0) M.update(true); // periodic model update + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::decode(Adaptive_Data_Model & M) + { + #ifdef _DEBUG + if (mode != 2) AC_Error("decoder not initialized"); + #endif + + unsigned n, s, x, y = length; + + if (M.decoder_table) { // use table look-up for faster decoding + + unsigned dv = value / (length >>= DM__LengthShift); + unsigned t = dv >> M.table_shift; + + s = M.decoder_table[t]; // initial decision based on table look-up + n = M.decoder_table[t+1] + 1; + + while (n > s + 1) { // finish with bisection search + unsigned m = (s + n) >> 1; + if (M.distribution[m] > dv) n = m; else s = m; + } + // compute products + x = M.distribution[s] * length; + if (s != M.last_symbol) { + y = M.distribution[s+1] * length; + } + } + + else { // decode using only multiplications + + x = s = 0; + length >>= DM__LengthShift; + unsigned m = (n = M.data_symbols) >> 1; + // decode via bisection search + do { + unsigned z = length * M.distribution[m]; + if (z > value) { + n = m; + y = z; // value is smaller + } + else { + s = m; + x = z; // value is larger or equal + } + } while ((m = (s + n) >> 1) != s); + } + + value -= x; // update interval + length = y - x; + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + ++M.symbol_count[s]; + if (--M.symbols_until_update == 0) M.update(false); // periodic model update + + return s; + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - - Other Arithmetic_Codec implementations - - - - - - - - - - - - - - - - + + Arithmetic_Codec::Arithmetic_Codec(void) + { + mode = buffer_size = 0; + new_buffer = code_buffer = 0; + } + + Arithmetic_Codec::Arithmetic_Codec(unsigned max_code_bytes, + unsigned char * user_buffer) + { + mode = buffer_size = 0; + new_buffer = code_buffer = 0; + set_buffer(max_code_bytes, user_buffer); + } + + Arithmetic_Codec::~Arithmetic_Codec(void) + { + delete [] new_buffer; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::set_buffer(unsigned max_code_bytes, + unsigned char * user_buffer) + { + // test for reasonable sizes + if (!max_code_bytes)// || (max_code_bytes > 0x10000000U)) // updated by K. Mammou + { + AC_Error("invalid codec buffer size"); + } + if (mode != 0) AC_Error("cannot set buffer while encoding or decoding"); + + if (user_buffer != 0) { // user provides memory buffer + buffer_size = max_code_bytes; + code_buffer = user_buffer; // set buffer for compressed data + delete [] new_buffer; // free anything previously assigned + new_buffer = 0; + return; + } + + if (max_code_bytes <= buffer_size) return; // enough available + + buffer_size = max_code_bytes; // assign new memory + delete [] new_buffer; // free anything previously assigned + if ((new_buffer = new unsigned char[buffer_size+16]) == 0) // 16 extra bytes + AC_Error("cannot assign memory for compressed data buffer"); + code_buffer = new_buffer; // set buffer for compressed data + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::start_encoder(void) + { + if (mode != 0) AC_Error("cannot start encoder"); + if (buffer_size == 0) AC_Error("no code buffer set"); + + mode = 1; + base = 0; // initialize encoder variables: interval and pointer + length = AC__MaxLength; + ac_pointer = code_buffer; // pointer to next data byte + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::start_decoder(void) + { + if (mode != 0) AC_Error("cannot start decoder"); + if (buffer_size == 0) AC_Error("no code buffer set"); + + // initialize decoder: interval, pointer, initial code value + mode = 2; + length = AC__MaxLength; + ac_pointer = code_buffer + 3; + value = (unsigned(code_buffer[0]) << 24)|(unsigned(code_buffer[1]) << 16) | + (unsigned(code_buffer[2]) << 8)| unsigned(code_buffer[3]); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::read_from_file(FILE * code_file) + { + unsigned shift = 0, code_bytes = 0; + int file_byte; + // read variable-length header with number of code bytes + do { + if ((file_byte = getc(code_file)) == EOF) + AC_Error("cannot read code from file"); + code_bytes |= unsigned(file_byte & 0x7F) << shift; + shift += 7; + } while (file_byte & 0x80); + // read compressed data + if (code_bytes > buffer_size) AC_Error("code buffer overflow"); + if (fread(code_buffer, 1, code_bytes, code_file) != code_bytes) + AC_Error("cannot read code from file"); + + start_decoder(); // initialize decoder + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::stop_encoder(void) + { + if (mode != 1) AC_Error("invalid to stop encoder"); + mode = 0; + + unsigned init_base = base; // done encoding: set final data bytes + + if (length > 2 * AC__MinLength) { + base += AC__MinLength; // base offset + length = AC__MinLength >> 1; // set new length for 1 more byte + } + else { + base += AC__MinLength >> 1; // base offset + length = AC__MinLength >> 9; // set new length for 2 more bytes + } + + if (init_base > base) propagate_carry(); // overflow = carry + + renorm_enc_interval(); // renormalization = output last bytes + + unsigned code_bytes = unsigned(ac_pointer - code_buffer); + if (code_bytes > buffer_size) AC_Error("code buffer overflow"); + + return code_bytes; // number of bytes used + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + unsigned Arithmetic_Codec::write_to_file(FILE * code_file) + { + unsigned header_bytes = 0, code_bytes = stop_encoder(), nb = code_bytes; + + // write variable-length header with number of code bytes + do { + int file_byte = int(nb & 0x7FU); + if ((nb >>= 7) > 0) file_byte |= 0x80; + if (putc(file_byte, code_file) == EOF) + AC_Error("cannot write compressed data to file"); + header_bytes++; + } while (nb); + // write compressed data + if (fwrite(code_buffer, 1, code_bytes, code_file) != code_bytes) + AC_Error("cannot write compressed data to file"); + + return code_bytes + header_bytes; // bytes used + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Arithmetic_Codec::stop_decoder(void) + { + if (mode != 2) AC_Error("invalid to stop decoder"); + mode = 0; + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - Static bit model implementation - - - - - - - - - - - - - - - - - - - - - + + Static_Bit_Model::Static_Bit_Model(void) + { + bit_0_prob = 1U << (BM__LengthShift - 1); // p0 = 0.5 + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Static_Bit_Model::set_probability_0(double p0) + { + if ((p0 < 0.0001)||(p0 > 0.9999)) AC_Error("invalid bit probability"); + bit_0_prob = unsigned(p0 * (1 << BM__LengthShift)); + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - Adaptive bit model implementation - - - - - - - - - - - - - - - - - - - - + + Adaptive_Bit_Model::Adaptive_Bit_Model(void) + { + reset(); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Adaptive_Bit_Model::reset(void) + { + // initialization to equiprobable model + bit_0_count = 1; + bit_count = 2; + bit_0_prob = 1U << (BM__LengthShift - 1); + update_cycle = bits_until_update = 4; // start with frequent updates + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Adaptive_Bit_Model::update(void) + { + // halve counts when a threshold is reached + + if ((bit_count += update_cycle) > BM__MaxCount) { + bit_count = (bit_count + 1) >> 1; + bit_0_count = (bit_0_count + 1) >> 1; + if (bit_0_count == bit_count) ++bit_count; + } + // compute scaled bit 0 probability + unsigned scale = 0x80000000U / bit_count; + bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift); + + // set frequency of model updates + update_cycle = (5 * update_cycle) >> 2; + if (update_cycle > 64) update_cycle = 64; + bits_until_update = update_cycle; + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - - Static data model implementation - - - - - - - - - - - - - - - - - - - + + Static_Data_Model::Static_Data_Model(void) + { + data_symbols = 0; + distribution = 0; + } + + Static_Data_Model::~Static_Data_Model(void) + { + delete [] distribution; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Static_Data_Model::set_distribution(unsigned number_of_symbols, + const double probability[]) + { + if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11))) + AC_Error("invalid number of data symbols"); + + if (data_symbols != number_of_symbols) { // assign memory for data model + data_symbols = number_of_symbols; + last_symbol = data_symbols - 1; + delete [] distribution; + // define size of table for fast decoding + if (data_symbols > 16) { + unsigned table_bits = 3; + while (data_symbols > (1U << (table_bits + 2))) ++table_bits; + table_size = 1 << table_bits; + table_shift = DM__LengthShift - table_bits; + distribution = new unsigned[data_symbols+table_size+2]; + decoder_table = distribution + data_symbols; + } + else { // small alphabet: no table needed + decoder_table = 0; + table_size = table_shift = 0; + distribution = new unsigned[data_symbols]; + } + if (distribution == 0) AC_Error("cannot assign model memory"); + } + // compute cumulative distribution, decoder table + unsigned s = 0; + double sum = 0.0, p = 1.0 / double(data_symbols); + + for (unsigned k = 0; k < data_symbols; k++) { + if (probability) p = probability[k]; + if ((p < 0.0001) || (p > 0.9999)) AC_Error("invalid symbol probability"); + distribution[k] = unsigned(sum * (1 << DM__LengthShift)); + sum += p; + if (table_size == 0) continue; + unsigned w = distribution[k] >> table_shift; + while (s < w) decoder_table[++s] = k - 1; + } + + if (table_size != 0) { + decoder_table[0] = 0; + while (s <= table_size) decoder_table[++s] = data_symbols - 1; + } + + if ((sum < 0.9999) || (sum > 1.0001)) AC_Error("invalid probabilities"); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - - Adaptive data model implementation - - - - - - - - - - - - - - - - - - + + Adaptive_Data_Model::Adaptive_Data_Model(void) + { + data_symbols = 0; + distribution = 0; + } + + Adaptive_Data_Model::Adaptive_Data_Model(unsigned number_of_symbols) + { + data_symbols = 0; + distribution = 0; + set_alphabet(number_of_symbols); + } + + Adaptive_Data_Model::~Adaptive_Data_Model(void) + { + delete [] distribution; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Adaptive_Data_Model::set_alphabet(unsigned number_of_symbols) + { + if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11))) + AC_Error("invalid number of data symbols"); + + if (data_symbols != number_of_symbols) { // assign memory for data model + data_symbols = number_of_symbols; + last_symbol = data_symbols - 1; + delete [] distribution; + // define size of table for fast decoding + if (data_symbols > 16) { + unsigned table_bits = 3; + while (data_symbols > (1U << (table_bits + 2))) ++table_bits; + table_size = 1 << table_bits; + table_shift = DM__LengthShift - table_bits; + distribution = new unsigned[2*data_symbols+table_size+2]; + decoder_table = distribution + 2 * data_symbols; + } + else { // small alphabet: no table needed + decoder_table = 0; + table_size = table_shift = 0; + distribution = new unsigned[2*data_symbols]; + } + symbol_count = distribution + data_symbols; + if (distribution == 0) AC_Error("cannot assign model memory"); + } + + reset(); // initialize model + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Adaptive_Data_Model::update(bool from_encoder) + { + // halve counts when a threshold is reached + + if ((total_count += update_cycle) > DM__MaxCount) { + total_count = 0; + for (unsigned n = 0; n < data_symbols; n++) + total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1); + } + // compute cumulative distribution, decoder table + unsigned k, sum = 0, s = 0; + unsigned scale = 0x80000000U / total_count; + + if (from_encoder || (table_size == 0)) + for (k = 0; k < data_symbols; k++) { + distribution[k] = (scale * sum) >> (31 - DM__LengthShift); + sum += symbol_count[k]; + } + else { + for (k = 0; k < data_symbols; k++) { + distribution[k] = (scale * sum) >> (31 - DM__LengthShift); + sum += symbol_count[k]; + unsigned w = distribution[k] >> table_shift; + while (s < w) decoder_table[++s] = k - 1; + } + decoder_table[0] = 0; + while (s <= table_size) decoder_table[++s] = data_symbols - 1; + } + // set frequency of model updates + update_cycle = (5 * update_cycle) >> 2; + unsigned max_cycle = (data_symbols + 6) << 3; + if (update_cycle > max_cycle) update_cycle = max_cycle; + symbols_until_update = update_cycle; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void Adaptive_Data_Model::reset(void) + { + if (data_symbols == 0) return; + + // restore probability estimates to uniform distribution + total_count = 0; + update_cycle = data_symbols; + for (unsigned k = 0; k < data_symbols; k++) symbol_count[k] = 1; + update(false); + symbols_until_update = update_cycle = (data_symbols + 6) >> 1; + } +} +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/contrib/Open3DGC/o3dgcArithmeticCodec.h b/contrib/Open3DGC/o3dgcArithmeticCodec.h new file mode 100644 index 000000000..d3cf6d14a --- /dev/null +++ b/contrib/Open3DGC/o3dgcArithmeticCodec.h @@ -0,0 +1,339 @@ +/* +Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// **************************** - +// ARITHMETIC CODING EXAMPLES - +// **************************** - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// Fast arithmetic coding implementation - +// -> 32-bit variables, 32-bit product, periodic updates, table decoding - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// Version 1.00 - April 25, 2004 - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// WARNING - +// ========= - +// - +// The only purpose of this program is to demonstrate the basic principles - +// of arithmetic coding. It is provided as is, without any express or - +// implied warranty, without even the warranty of fitness for any particular - +// purpose, or that the implementations are correct. - +// - +// Permission to copy and redistribute this code is hereby granted, provided - +// that this warning and copyright notices are not removed or altered. - +// - +// Copyright (c) 2004 by Amir Said (said@ieee.org) & - +// William A. Pearlman (pearlw@ecse.rpi.edu) - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// - +// A description of the arithmetic coding method used here is available in - +// - +// Lossless Compression Handbook, ed. K. Sayood - +// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - +// - +// A. Said, Introduction to Arithetic Coding Theory and Practice - +// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - +// - +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +// - - Definitions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#ifndef O3DGC_ARITHMETIC_CODEC +#define O3DGC_ARITHMETIC_CODEC + +#include +#include "o3dgcCommon.h" + +namespace o3dgc +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - - Class definitions - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Static_Bit_Model // static model for binary data + { + public: + + Static_Bit_Model(void); + + void set_probability_0(double); // set probability of symbol '0' + + private: // . . . . . . . . . . . . . . . . . . . . . . + unsigned bit_0_prob; + friend class Arithmetic_Codec; + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Static_Data_Model // static model for general data + { + public: + + Static_Data_Model(void); + ~Static_Data_Model(void); + + unsigned model_symbols(void) { return data_symbols; } + + void set_distribution(unsigned number_of_symbols, + const double probability[] = 0); // 0 means uniform + + private: // . . . . . . . . . . . . . . . . . . . . . . + unsigned * distribution, * decoder_table; + unsigned data_symbols, last_symbol, table_size, table_shift; + friend class Arithmetic_Codec; + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Adaptive_Bit_Model // adaptive model for binary data + { + public: + + Adaptive_Bit_Model(void); + + void reset(void); // reset to equiprobable model + + private: // . . . . . . . . . . . . . . . . . . . . . . + void update(void); + unsigned update_cycle, bits_until_update; + unsigned bit_0_prob, bit_0_count, bit_count; + friend class Arithmetic_Codec; + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Adaptive_Data_Model // adaptive model for binary data + { + public: + + Adaptive_Data_Model(void); + Adaptive_Data_Model(unsigned number_of_symbols); + ~Adaptive_Data_Model(void); + + unsigned model_symbols(void) { return data_symbols; } + + void reset(void); // reset to equiprobable model + void set_alphabet(unsigned number_of_symbols); + + private: // . . . . . . . . . . . . . . . . . . . . . . + void update(bool); + unsigned * distribution, * symbol_count, * decoder_table; + unsigned total_count, update_cycle, symbols_until_update; + unsigned data_symbols, last_symbol, table_size, table_shift; + friend class Arithmetic_Codec; + }; + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // - - Encoder and decoder class - - - - - - - - - - - - - - - - - - - - - - - + + // Class with both the arithmetic encoder and decoder. All compressed data is + // saved to a memory buffer + + class Arithmetic_Codec + { + public: + + Arithmetic_Codec(void); + ~Arithmetic_Codec(void); + Arithmetic_Codec(unsigned max_code_bytes, + unsigned char * user_buffer = 0); // 0 = assign new + + unsigned char * buffer(void) { return code_buffer; } + + void set_buffer(unsigned max_code_bytes, + unsigned char * user_buffer = 0); // 0 = assign new + + void start_encoder(void); + void start_decoder(void); + void read_from_file(FILE * code_file); // read code data, start decoder + + unsigned stop_encoder(void); // returns number of bytes used + unsigned write_to_file(FILE * code_file); // stop encoder, write code data + void stop_decoder(void); + + void put_bit(unsigned bit); + unsigned get_bit(void); + + void put_bits(unsigned data, unsigned number_of_bits); + unsigned get_bits(unsigned number_of_bits); + + void encode(unsigned bit, + Static_Bit_Model &); + unsigned decode(Static_Bit_Model &); + + void encode(unsigned data, + Static_Data_Model &); + unsigned decode(Static_Data_Model &); + + void encode(unsigned bit, + Adaptive_Bit_Model &); + unsigned decode(Adaptive_Bit_Model &); + + void encode(unsigned data, + Adaptive_Data_Model &); + unsigned decode(Adaptive_Data_Model &); + +// This section was added by K. Mammou + void ExpGolombEncode(unsigned int symbol, + int k, + Static_Bit_Model & bModel0, + Adaptive_Bit_Model & bModel1) + { + while(1) + { + if (symbol >= (unsigned int)(1<>k)&1), bModel0); + } + break; + } + } + } + + + unsigned ExpGolombDecode(int k, + Static_Bit_Model & bModel0, + Adaptive_Bit_Model & bModel1) + { + unsigned int l; + int symbol = 0; + int binary_symbol = 0; + do + { + l=decode(bModel1); + if (l==1) + { + symbol += (1<>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; + } + } + void WriteUInt32ASCII(unsigned long value) + { + for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i) + { + m_stream.PushBack(value & O3DGC_BINARY_STREAM_MAX_SYMBOL0); + value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; + } + } + void WriteIntASCII(long value) + { + WriteUIntASCII(IntToUInt(value)); + } + void WriteUIntASCII(unsigned long value) + { + if (value >= O3DGC_BINARY_STREAM_MAX_SYMBOL0) + { + m_stream.PushBack(O3DGC_BINARY_STREAM_MAX_SYMBOL0); + value -= O3DGC_BINARY_STREAM_MAX_SYMBOL0; + unsigned char a, b; + do + { + a = ((value & O3DGC_BINARY_STREAM_MAX_SYMBOL1) << 1); + b = ( (value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1) > 0); + a += b; + m_stream.PushBack(a); + } while (b); + } + else + { + m_stream.PushBack((unsigned char) value); + } + } + void WriteUCharASCII(unsigned char value) + { + assert(value <= O3DGC_BINARY_STREAM_MAX_SYMBOL0); + m_stream.PushBack(value); + } + float ReadFloat32ASCII(unsigned long & position) const + { + unsigned long value = ReadUInt32ASCII(position); + float fvalue = *((float *)(&value)); + return fvalue; + } + unsigned long ReadUInt32ASCII(unsigned long & position) const + { + assert(position < m_stream.GetSize() - O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32); + unsigned long value = 0; + unsigned long shift = 0; + for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i) + { + value += (m_stream[position++] << shift); + shift += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; + } + return value; + } + long ReadIntASCII(unsigned long & position) const + { + return UIntToInt(ReadUIntASCII(position)); + } + unsigned long ReadUIntASCII(unsigned long & position) const + { + unsigned long value = m_stream[position++]; + if (value == O3DGC_BINARY_STREAM_MAX_SYMBOL0) + { + long x; + unsigned long i = 0; + do + { + x = m_stream[position++]; + value += ( (x>>1) << i); + i += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1; + } while (x & 1); + } + return value; + } + unsigned char ReadUCharASCII(unsigned long & position) const + { + return m_stream[position++]; + } + O3DGCErrorCode Save(const char * const fileName) + { + FILE * fout = fopen(fileName, "wb"); + if (!fout) + { + return O3DGC_ERROR_CREATE_FILE; + } + fwrite(m_stream.GetBuffer(), 1, m_stream.GetSize(), fout); + fclose(fout); + return O3DGC_OK; + } + O3DGCErrorCode Load(const char * const fileName) + { + FILE * fin = fopen(fileName, "rb"); + if (!fin) + { + return O3DGC_ERROR_OPEN_FILE; + } + fseek(fin, 0, SEEK_END); + unsigned long size = ftell(fin); + m_stream.Allocate(size); + rewind(fin); + unsigned int nread = (unsigned int) fread((void *) m_stream.GetBuffer(), 1, size, fin); + m_stream.SetSize(size); + if (nread != size) + { + return O3DGC_ERROR_READ_FILE; + } + fclose(fin); + return O3DGC_OK; + } + O3DGCErrorCode LoadFromBuffer(unsigned char * buffer, unsigned long bufferSize) + { + m_stream.Allocate(bufferSize); + memcpy(m_stream.GetBuffer(), buffer, bufferSize); + m_stream.SetSize(bufferSize); + return O3DGC_OK; + } + unsigned long GetSize() const + { + return m_stream.GetSize(); + } + const unsigned char * const GetBuffer(unsigned long position) const + { + return m_stream.GetBuffer() + position; + } + unsigned char * const GetBuffer(unsigned long position) + { + return (m_stream.GetBuffer() + position); + } + unsigned char * const GetBuffer() + { + return m_stream.GetBuffer(); + } + void GetBuffer(unsigned long position, unsigned char * & buffer) const + { + buffer = (unsigned char *) (m_stream.GetBuffer() + position); // fix me: ugly! + } + void SetSize(unsigned long size) + { + m_stream.SetSize(size); + }; + void Allocate(unsigned long size) + { + m_stream.Allocate(size); + } + + private: + Vector m_stream; + O3DGCEndianness m_endianness; + }; + +} +#endif // O3DGC_BINARY_STREAM_H + diff --git a/contrib/Open3DGC/o3dgcCommon.h b/contrib/Open3DGC/o3dgcCommon.h new file mode 100644 index 000000000..a9be4d885 --- /dev/null +++ b/contrib/Open3DGC/o3dgcCommon.h @@ -0,0 +1,412 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_COMMON_H +#define O3DGC_COMMON_H + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include + +namespace o3dgc +{ + typedef float Real; + const double O3DGC_MAX_DOUBLE = 1.79769e+308; + const long O3DGC_MIN_LONG = -2147483647; + const long O3DGC_MAX_LONG = 2147483647; + const long O3DGC_MAX_UCHAR8 = 255; + const long O3DGC_MAX_TFAN_SIZE = 256; + const unsigned long O3DGC_MAX_ULONG = 4294967295; + + const unsigned long O3DGC_SC3DMC_START_CODE = 0x00001F1; + const unsigned long O3DGC_DV_START_CODE = 0x00001F2; + const unsigned long O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES = 256; + const unsigned long O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES = 256; + const unsigned long O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES = 32; + + const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS = 2; + const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS = 257; + + enum O3DGCEndianness + { + O3DGC_BIG_ENDIAN = 0, + O3DGC_LITTLE_ENDIAN = 1 + }; + enum O3DGCErrorCode + { + O3DGC_OK, + O3DGC_ERROR_BUFFER_FULL, + O3DGC_ERROR_CREATE_FILE, + O3DGC_ERROR_OPEN_FILE, + O3DGC_ERROR_READ_FILE, + O3DGC_ERROR_CORRUPTED_STREAM, + O3DGC_ERROR_NON_SUPPORTED_FEATURE + }; + enum O3DGCSC3DMCBinarization + { + O3DGC_SC3DMC_BINARIZATION_FL = 0, // Fixed Length (not supported) + O3DGC_SC3DMC_BINARIZATION_BP = 1, // BPC (not supported) + O3DGC_SC3DMC_BINARIZATION_FC = 2, // 4 bits Coding (not supported) + O3DGC_SC3DMC_BINARIZATION_AC = 3, // Arithmetic Coding (not supported) + O3DGC_SC3DMC_BINARIZATION_AC_EGC = 4, // Arithmetic Coding & EGCk + O3DGC_SC3DMC_BINARIZATION_ASCII = 5 // Arithmetic Coding & EGCk + }; + enum O3DGCStreamType + { + O3DGC_STREAM_TYPE_UNKOWN = 0, + O3DGC_STREAM_TYPE_ASCII = 1, + O3DGC_STREAM_TYPE_BINARY = 2 + }; + enum O3DGCSC3DMCQuantizationMode + { + O3DGC_SC3DMC_DIAG_BB = 0, // supported + O3DGC_SC3DMC_MAX_ALL_DIMS = 1, // supported + O3DGC_SC3DMC_MAX_SEP_DIM = 2 // supported + }; + enum O3DGCSC3DMCPredictionMode + { + O3DGC_SC3DMC_NO_PREDICTION = 0, // supported + O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION = 1, // supported + O3DGC_SC3DMC_XOR_PREDICTION = 2, // not supported + O3DGC_SC3DMC_ADAPTIVE_DIFFERENTIAL_PREDICTION = 3, // not supported + O3DGC_SC3DMC_CIRCULAR_DIFFERENTIAL_PREDICTION = 4, // not supported + O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION = 5, // supported + O3DGC_SC3DMC_SURF_NORMALS_PREDICTION = 6 // supported + }; + enum O3DGCSC3DMCEncodingMode + { + O3DGC_SC3DMC_ENCODE_MODE_QBCR = 0, // not supported + O3DGC_SC3DMC_ENCODE_MODE_SVA = 1, // not supported + O3DGC_SC3DMC_ENCODE_MODE_TFAN = 2, // supported + }; + enum O3DGCDVEncodingMode + { + O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT = 0 + }; + enum O3DGCIFSFloatAttributeType + { + O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_UNKOWN = 0, + O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_POSITION = 1, + O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_NORMAL = 2, + O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_COLOR = 3, + O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD = 4, + O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_WEIGHT = 5 + + }; + enum O3DGCIFSIntAttributeType + { + O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN = 0, + O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX = 1, + O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID = 2, + O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID = 3 + }; + + template + inline const T absolute(const T& a) + { + return (a < (T)(0)) ? -a : a; + } + template + inline const T min(const T& a, const T& b) + { + return (b < a) ? b : a; + } + template + inline const T max(const T& a, const T& b) + { + return (b > a) ? b : a; + } + template + inline void swap(T& a, T& b) + { + T tmp = a; + a = b; + b = tmp; + } + inline double log2( double n ) + { + return log(n) / log(2.0); + } + + inline O3DGCEndianness SystemEndianness() + { + unsigned long num = 1; + return ( *((char *)(&num)) == 1 )? O3DGC_LITTLE_ENDIAN : O3DGC_BIG_ENDIAN ; + } + class SC3DMCStats + { + public: + SC3DMCStats(void) + { + memset(this, 0, sizeof(SC3DMCStats)); + }; + ~SC3DMCStats(void){}; + + double m_timeCoord; + double m_timeNormal; + double m_timeCoordIndex; + double m_timeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + double m_timeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; + double m_timeReorder; + + unsigned long m_streamSizeCoord; + unsigned long m_streamSizeNormal; + unsigned long m_streamSizeCoordIndex; + unsigned long m_streamSizeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + unsigned long m_streamSizeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; + + }; + typedef struct + { + long m_a; + long m_b; + long m_c; + } SC3DMCTriplet; + + typedef struct + { + SC3DMCTriplet m_id; + long m_pred[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; + } SC3DMCPredictor; + + inline bool operator< (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs) + { + if (lhs.m_c != rhs.m_c) + { + return (lhs.m_c < rhs.m_c); + } + else if (lhs.m_b != rhs.m_b) + { + return (lhs.m_b < rhs.m_b); + } + return (lhs.m_a < rhs.m_a); + } + inline bool operator== (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs) + { + return (lhs.m_c == rhs.m_c && lhs.m_b == rhs.m_b && lhs.m_a == rhs.m_a); + } + + + // fix me: optimize this function (e.g., binary search) + inline unsigned long Insert(SC3DMCTriplet e, unsigned long & nPred, SC3DMCPredictor * const list) + { + unsigned long pos = 0xFFFFFFFF; + bool foundOrInserted = false; + for (unsigned long j = 0; j < nPred; ++j) + { + if (e == list[j].m_id) + { + foundOrInserted = true; + break; + } + else if (e < list[j].m_id) + { + if (nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS) + { + ++nPred; + } + for (unsigned long h = nPred-1; h > j; --h) + { + list[h] = list[h-1]; + } + list[j].m_id = e; + pos = j; + foundOrInserted = true; + break; + } + } + if (!foundOrInserted && nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS) + { + pos = nPred; + list[nPred++].m_id = e; + } + return pos; + } + template + inline void SphereToCube(const T x, const T y, const T z, + T & a, T & b, char & index) + { + T ax = absolute(x); + T ay = absolute(y); + T az = absolute(z); + if (az >= ax && az >= ay) + { + if (z >= (T)(0)) + { + index = 0; + a = x; + b = y; + } + else + { + index = 1; + a = -x; + b = -y; + } + } + else if (ay >= ax && ay >= az) + { + if (y >= (T)(0)) + { + index = 2; + a = z; + b = x; + } + else + { + index = 3; + a = -z; + b = -x; + } + } + else if (ax >= ay && ax >= az) + { + if (x >= (T)(0)) + { + index = 4; + a = y; + b = z; + } + else + { + index = 5; + a = -y; + b = -z; + } + } + } + inline void CubeToSphere(const Real a, const Real b, const char index, + Real & x, Real & y, Real & z) + { + switch( index ) + { + case 0: + x = a; + y = b; + z = (Real) sqrt(max(0.0, 1.0 - x*x-y*y)); + break; + case 1: + x = -a; + y = -b; + z = -(Real) sqrt(max(0.0, 1.0 - x*x-y*y)); + break; + case 2: + z = a; + x = b; + y = (Real) sqrt(max(0.0, 1.0 - x*x-z*z)); + break; + case 3: + z = -a; + x = -b; + y = -(Real) sqrt(max(0.0, 1.0 - x*x-z*z)); + break; + case 4: + y = a; + z = b; + x = (Real) sqrt(max(0.0, 1.0 - y*y-z*z)); + break; + case 5: + y = -a; + z = -b; + x = -(Real) sqrt(max(0.0, 1.0 - y*y-z*z)); + break; + } + } + inline unsigned long IntToUInt(long value) + { + return (value < 0)?(unsigned long) (-1 - (2 * value)):(unsigned long) (2 * value); + } + inline long UIntToInt(unsigned long uiValue) + { + return (uiValue & 1)?-((long) ((uiValue+1) >> 1)):((long) (uiValue >> 1)); + } + inline void ComputeVectorMinMax(const Real * const tab, + unsigned long size, + unsigned long dim, + unsigned long stride, + Real * minTab, + Real * maxTab, + O3DGCSC3DMCQuantizationMode quantMode) + { + if (size == 0 || dim == 0) + { + return; + } + unsigned long p = 0; + for(unsigned long d = 0; d < dim; ++d) + { + maxTab[d] = minTab[d] = tab[p++]; + } + p = stride; + for(unsigned long i = 1; i < size; ++i) + { + for(unsigned long d = 0; d < dim; ++d) + { + if (maxTab[d] < tab[p+d]) maxTab[d] = tab[p+d]; + if (minTab[d] > tab[p+d]) minTab[d] = tab[p+d]; + } + p += stride; + } + + if (quantMode == O3DGC_SC3DMC_DIAG_BB) + { + Real diag = 0.0; + Real r; + for(unsigned long d = 0; d < dim; ++d) + { + r = (maxTab[d] - minTab[d]); + diag += r*r; + } + diag = sqrt(diag); + for(unsigned long d = 0; d < dim; ++d) + { + maxTab[d] = minTab[d] + diag; + } + } + else if (quantMode == O3DGC_SC3DMC_MAX_ALL_DIMS) + { + Real maxr = (maxTab[0] - minTab[0]); + Real r; + for(unsigned long d = 1; d < dim; ++d) + { + r = (maxTab[d] - minTab[d]); + if ( r > maxr) + { + maxr = r; + } + } + for(unsigned long d = 0; d < dim; ++d) + { + maxTab[d] = minTab[d] + maxr; + } + } + } +} +#endif // O3DGC_COMMON_H + diff --git a/contrib/Open3DGC/o3dgcDVEncodeParams.h b/contrib/Open3DGC/o3dgcDVEncodeParams.h new file mode 100644 index 000000000..6f639f678 --- /dev/null +++ b/contrib/Open3DGC/o3dgcDVEncodeParams.h @@ -0,0 +1,62 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_DV_ENCODE_PARAMS_H +#define O3DGC_DV_ENCODE_PARAMS_H + +#include "o3dgcCommon.h" + +namespace o3dgc +{ + class DVEncodeParams + { + public: + //! Constructor. + DVEncodeParams(void) + { + m_quantBits = 10; + m_streamTypeMode = O3DGC_STREAM_TYPE_ASCII; + m_encodeMode = O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT; + }; + //! Destructor. + ~DVEncodeParams(void) {}; + + unsigned long GetQuantBits() const { return m_quantBits;} + O3DGCStreamType GetStreamType() const { return m_streamTypeMode;} + O3DGCDVEncodingMode GetEncodeMode() const { return m_encodeMode;} + + void SetQuantBits (unsigned long quantBits ) { m_quantBits = quantBits;} + + void SetStreamType(O3DGCStreamType streamTypeMode) { m_streamTypeMode = streamTypeMode;} + void SetEncodeMode(O3DGCDVEncodingMode encodeMode ) { m_encodeMode = encodeMode ;} + + + private: + unsigned long m_quantBits; + O3DGCStreamType m_streamTypeMode; + O3DGCDVEncodingMode m_encodeMode; + }; +} +#endif // O3DGC_DV_ENCODE_PARAMS_H + diff --git a/contrib/Open3DGC/o3dgcDynamicVector.h b/contrib/Open3DGC/o3dgcDynamicVector.h new file mode 100644 index 000000000..edc97d83c --- /dev/null +++ b/contrib/Open3DGC/o3dgcDynamicVector.h @@ -0,0 +1,84 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_DYNAMIC_VECTOR_SET_H +#define O3DGC_DYNAMIC_VECTOR_SET_H + +#include "o3dgcCommon.h" + +namespace o3dgc +{ + class DynamicVector + { + public: + //! Constructor. + DynamicVector(void) + { + m_num = 0; + m_dim = 0; + m_stride = 0; + m_max = 0; + m_min = 0; + m_vectors = 0; + }; + //! Destructor. + ~DynamicVector(void) {}; + + unsigned long GetNVector() const { return m_num;} + unsigned long GetDimVector() const { return m_dim;} + unsigned long GetStride() const { return m_stride;} + const Real * const GetMin() const { return m_min;} + const Real * const GetMax() const { return m_max;} + const Real * const GetVectors() const { return m_vectors;} + Real * const GetVectors() { return m_vectors;} + Real GetMin(unsigned long j) const { return m_min[j];} + Real GetMax(unsigned long j) const { return m_max[j];} + + void SetNVector (unsigned long num ) { m_num = num ;} + void SetDimVector (unsigned long dim ) { m_dim = dim ;} + void SetStride (unsigned long stride ) { m_stride = stride ;} + void SetMin (Real * const min ) { m_min = min ;} + void SetMax (Real * const max ) { m_max = max ;} + void SetMin (unsigned long j, Real min) { m_min[j] = min ;} + void SetMax (unsigned long j, Real max) { m_max[j] = max ;} + void SetVectors (Real * const vectors) { m_vectors = vectors ;} + + void ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode) + { + assert( m_max && m_min && m_vectors && m_stride && m_dim && m_num); + ComputeVectorMinMax(m_vectors, m_num , m_dim, m_stride, m_min , m_max , quantMode); + } + + private: + unsigned long m_num; + unsigned long m_dim; + unsigned long m_stride; + Real * m_max; + Real * m_min; + Real * m_vectors; + }; + +} +#endif // O3DGC_DYNAMIC_VECTOR_SET_H + diff --git a/contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp b/contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp new file mode 100644 index 000000000..b92452eb6 --- /dev/null +++ b/contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp @@ -0,0 +1,278 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include "o3dgcDynamicVectorDecoder.h" +#include "o3dgcArithmeticCodec.h" + + +//#define DEBUG_VERBOSE + +namespace o3dgc +{ +#ifdef DEBUG_VERBOSE + FILE * g_fileDebugDVCDec = NULL; +#endif //DEBUG_VERBOSE + + O3DGCErrorCode IUpdate(long * const data, const long size) + { + assert(size > 1); + const long size1 = size - 1; + long p = 2; + data[0] -= data[1] >> 1; + while(p < size1) + { + data[p] -= (data[p-1] + data[p+1] + 2) >> 2; + p += 2; + } + if ( p == size1) + { + data[p] -= data[p-1]>>1; + } + return O3DGC_OK; + } + O3DGCErrorCode IPredict(long * const data, const long size) + { + assert(size > 1); + const long size1 = size - 1; + long p = 1; + while(p < size1) + { + data[p] += (data[p-1] + data[p+1] + 1) >> 1; + p += 2; + } + if ( p == size1) + { + data[p] += data[p-1]; + } + return O3DGC_OK; + } + O3DGCErrorCode Merge(long * const data, const long size) + { + assert(size > 1); + const long h = (size >> 1) + (size & 1); + long a = h-1; + long b = h; + while (a > 0) + { + for (long i = a; i < b; i += 2) + { + swap(data[i], data[i+1]); + } + --a; + ++b; + } + return O3DGC_OK; + } + inline O3DGCErrorCode ITransform(long * const data, const unsigned long size) + { + unsigned long n = size; + unsigned long even = 0; + unsigned long k = 0; + even += ((n&1) << k++); + while(n > 1) + { + n = (n >> 1) + (n & 1); + even += ((n&1) << k++); + } + for(long i = k-2; i >= 0; --i) + { + n = (n << 1) - ((even>>i) & 1); + Merge (data, n); + IUpdate (data, n); + IPredict(data, n); + } + return O3DGC_OK; + } + DynamicVectorDecoder::DynamicVectorDecoder(void) + { + m_streamSize = 0; + m_maxNumVectors = 0; + m_numVectors = 0; + m_dimVectors = 0; + m_quantVectors = 0; + m_iterator = 0; + m_streamType = O3DGC_STREAM_TYPE_UNKOWN; + } + DynamicVectorDecoder::~DynamicVectorDecoder() + { + delete [] m_quantVectors; + } + O3DGCErrorCode DynamicVectorDecoder::DecodeHeader(DynamicVector & dynamicVector, + const BinaryStream & bstream) + { + unsigned long iterator0 = m_iterator; + unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY); + if (start_code != O3DGC_DV_START_CODE) + { + m_iterator = iterator0; + start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII); + if (start_code != O3DGC_DV_START_CODE) + { + return O3DGC_ERROR_CORRUPTED_STREAM; + } + else + { + m_streamType = O3DGC_STREAM_TYPE_ASCII; + } + } + else + { + m_streamType = O3DGC_STREAM_TYPE_BINARY; + } + m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType); + m_params.SetEncodeMode( (O3DGCDVEncodingMode) bstream.ReadUChar(m_iterator, m_streamType)); + dynamicVector.SetNVector ( bstream.ReadUInt32(m_iterator, m_streamType) ); + + if (dynamicVector.GetNVector() > 0) + { + dynamicVector.SetDimVector( bstream.ReadUInt32(m_iterator, m_streamType) ); + m_params.SetQuantBits(bstream.ReadUChar(m_iterator, m_streamType)); + } + return O3DGC_OK; + } + O3DGCErrorCode DynamicVectorDecoder::DecodePlayload(DynamicVector & dynamicVector, + const BinaryStream & bstream) + { + O3DGCErrorCode ret = O3DGC_OK; +#ifdef DEBUG_VERBOSE + g_fileDebugDVCDec = fopen("dv_dec.txt", "w"); +#endif //DEBUG_VERBOSE + unsigned long start = m_iterator; + unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size + + const unsigned long dim = dynamicVector.GetDimVector(); + const unsigned long num = dynamicVector.GetNVector(); + const unsigned long size = dim * num; + for(unsigned long j=0 ; j < dynamicVector.GetDimVector() ; ++j) + { + dynamicVector.SetMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + dynamicVector.SetMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + } + Arithmetic_Codec acd; + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + unsigned char * buffer = 0; + streamSize -= (m_iterator - start); + unsigned int exp_k = 0; + unsigned int M = 0; + if (m_streamType == O3DGC_STREAM_TYPE_BINARY) + { + bstream.GetBuffer(m_iterator, buffer); + m_iterator += streamSize; + acd.set_buffer(streamSize, buffer); + acd.start_decoder(); + exp_k = acd.ExpGolombDecode(0, bModel0, bModel1); + M = acd.ExpGolombDecode(0, bModel0, bModel1); + } + Adaptive_Data_Model mModelValues(M+2); + + if (m_maxNumVectors < size) + { + delete [] m_quantVectors; + m_maxNumVectors = size; + m_quantVectors = new long [size]; + } + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + for(unsigned long v = 0; v < num; ++v) + { + for(unsigned long d = 0; d < dim; ++d) + { + m_quantVectors[d * num + v] = bstream.ReadIntASCII(m_iterator); + } + } + } + else + { + for(unsigned long v = 0; v < num; ++v) + { + for(unsigned long d = 0; d < dim; ++d) + { + m_quantVectors[d * num + v] = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); + } + } + } + #ifdef DEBUG_VERBOSE + printf("IntArray (%i, %i)\n", num, dim); + fprintf(g_fileDebugDVCDec, "IntArray (%i, %i)\n", num, dim); + for(unsigned long v = 0; v < num; ++v) + { + for(unsigned long d = 0; d < dim; ++d) + { + printf("%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v])); + fprintf(g_fileDebugDVCDec, "%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v])); + } + } + fflush(g_fileDebugDVCDec); + #endif //DEBUG_VERBOSE + for(unsigned long d = 0; d < dim; ++d) + { + ITransform(m_quantVectors + d * num, num); + } + IQuantize(dynamicVector.GetVectors(), + num, + dim, + dynamicVector.GetStride(), + dynamicVector.GetMin(), + dynamicVector.GetMax(), + m_params.GetQuantBits()); + +#ifdef DEBUG_VERBOSE + fclose(g_fileDebugDVCDec); +#endif //DEBUG_VERBOSE + return ret; + } + O3DGCErrorCode DynamicVectorDecoder::IQuantize(Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits) + { + const unsigned long size = numFloatArray * dimFloatArray; + Real r; + if (m_maxNumVectors < size) + { + delete [] m_quantVectors; + m_maxNumVectors = size; + m_quantVectors = new long [m_maxNumVectors]; + } + Real idelta; + for(unsigned long d = 0; d < dimFloatArray; ++d) + { + r = maxFloatArray[d] - minFloatArray[d]; + if (r > 0.0f) + { + idelta = (float)(r) / ((1 << nQBits) - 1); + } + else + { + idelta = 1.0f; + } + for(unsigned long v = 0; v < numFloatArray; ++v) + { + floatArray[v * stride + d] = m_quantVectors[v + d * numFloatArray] * idelta + minFloatArray[d]; + } + } + return O3DGC_OK; + } +} diff --git a/contrib/Open3DGC/o3dgcDynamicVectorDecoder.h b/contrib/Open3DGC/o3dgcDynamicVectorDecoder.h new file mode 100644 index 000000000..6e21b4fa3 --- /dev/null +++ b/contrib/Open3DGC/o3dgcDynamicVectorDecoder.h @@ -0,0 +1,76 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_DYNAMIC_VECTOR_DECODER_H +#define O3DGC_DYNAMIC_VECTOR_DECODER_H + +#include "o3dgcCommon.h" +#include "o3dgcBinaryStream.h" +#include "o3dgcDVEncodeParams.h" +#include "o3dgcDynamicVector.h" + +namespace o3dgc +{ + //! + class DynamicVectorDecoder + { + public: + //! Constructor. + DynamicVectorDecoder(void); + //! Destructor. + ~DynamicVectorDecoder(void); + //! + //! + O3DGCErrorCode DecodeHeader(DynamicVector & dynamicVector, + const BinaryStream & bstream); + //! + O3DGCErrorCode DecodePlayload(DynamicVector & dynamicVector, + const BinaryStream & bstream); + + O3DGCStreamType GetStreamType() const { return m_streamType; } + void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } + unsigned long GetIterator() const { return m_iterator;} + O3DGCErrorCode SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; } + + private: + O3DGCErrorCode IQuantize(Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits); + + unsigned long m_streamSize; + unsigned long m_maxNumVectors; + unsigned long m_numVectors; + unsigned long m_dimVectors; + unsigned long m_iterator; + long * m_quantVectors; + DVEncodeParams m_params; + O3DGCStreamType m_streamType; + }; +} +#endif // O3DGC_DYNAMIC_VECTOR_DECODER_H + diff --git a/contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp b/contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp new file mode 100644 index 000000000..00ae75e35 --- /dev/null +++ b/contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp @@ -0,0 +1,295 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include "o3dgcDVEncodeParams.h" +#include "o3dgcDynamicVectorEncoder.h" +#include "o3dgcArithmeticCodec.h" +#include "o3dgcBinaryStream.h" + +//#define DEBUG_VERBOSE + +namespace o3dgc +{ +#ifdef DEBUG_VERBOSE + FILE * g_fileDebugDVEnc = NULL; +#endif //DEBUG_VERBOSE + + inline O3DGCErrorCode Update(long * const data, const long size) + { + assert(size > 1); + const long size1 = size - 1; + long p = 2; + data[0] += data[1] >> 1; + while(p < size1) + { + data[p] += (data[p-1] + data[p+1] + 2) >> 2; + p += 2; + } + if ( p == size1) + { + data[p] += data[p-1]>>1; + } + return O3DGC_OK; + } + inline O3DGCErrorCode Predict(long * const data, const long size) + { + assert(size > 1); + const long size1 = size - 1; + long p = 1; + while(p < size1) + { + data[p] -= (data[p-1] + data[p+1] + 1) >> 1; + p += 2; + } + if ( p == size1) + { + data[p] -= data[p-1]; + } + return O3DGC_OK; + } + inline O3DGCErrorCode Split(long * const data, const long size) + { + assert(size > 1); + long a = 1; + long b = size-1; + while (a < b) + { + for (long i = a; i < b; i += 2) + { + swap(data[i], data[i+1]); + } + ++a; + --b; + } + return O3DGC_OK; + } + inline O3DGCErrorCode Transform(long * const data, const unsigned long size) + { + unsigned long n = size; + while(n > 1) + { + Predict(data, n); + Update (data, n); + Split(data, n); + n = (n >> 1) + (n & 1); + } + return O3DGC_OK; + } + DynamicVectorEncoder::DynamicVectorEncoder(void) + { + m_maxNumVectors = 0; + m_numVectors = 0; + m_dimVectors = 0; + m_quantVectors = 0; + m_sizeBufferAC = 0; + m_bufferAC = 0; + m_posSize = 0; + m_streamType = O3DGC_STREAM_TYPE_UNKOWN; + } + DynamicVectorEncoder::~DynamicVectorEncoder() + { + delete [] m_quantVectors; + delete [] m_bufferAC; + } + O3DGCErrorCode DynamicVectorEncoder::Encode(const DVEncodeParams & params, + const DynamicVector & dynamicVector, + BinaryStream & bstream) + { + assert(params.GetQuantBits() > 0); + assert(dynamicVector.GetNVector() > 0); + assert(dynamicVector.GetDimVector() > 0); + assert(dynamicVector.GetStride() >= dynamicVector.GetDimVector()); + assert(dynamicVector.GetVectors() && dynamicVector.GetMin() && dynamicVector.GetMax()); + assert(m_streamType != O3DGC_STREAM_TYPE_UNKOWN); + // Encode header + unsigned long start = bstream.GetSize(); + EncodeHeader(params, dynamicVector, bstream); + // Encode payload + EncodePayload(params, dynamicVector, bstream); + bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType); + return O3DGC_OK; + + } + O3DGCErrorCode DynamicVectorEncoder::EncodeHeader(const DVEncodeParams & params, + const DynamicVector & dynamicVector, + BinaryStream & bstream) + { + m_streamType = params.GetStreamType(); + bstream.WriteUInt32(O3DGC_DV_START_CODE, m_streamType); + m_posSize = bstream.GetSize(); + bstream.WriteUInt32(0, m_streamType); // to be filled later + bstream.WriteUChar((unsigned char) params.GetEncodeMode(), m_streamType); + bstream.WriteUInt32(dynamicVector.GetNVector() , m_streamType); + if (dynamicVector.GetNVector() > 0) + { + bstream.WriteUInt32(dynamicVector.GetDimVector(), m_streamType); + bstream.WriteUChar ((unsigned char) params.GetQuantBits(), m_streamType); + } + return O3DGC_OK; + } + O3DGCErrorCode DynamicVectorEncoder::EncodeAC(unsigned long num, + unsigned long dim, + unsigned long M, + unsigned long & encodedBytes) + { + Arithmetic_Codec ace; + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + Adaptive_Data_Model mModelValues(M+2); + const unsigned int NMAX = num * dim * 8 + 100; + if ( m_sizeBufferAC < NMAX ) + { + delete [] m_bufferAC; + m_sizeBufferAC = NMAX; + m_bufferAC = new unsigned char [m_sizeBufferAC]; + } + ace.set_buffer(NMAX, m_bufferAC); + ace.start_encoder(); + ace.ExpGolombEncode(0, 0, bModel0, bModel1); + ace.ExpGolombEncode(M, 0, bModel0, bModel1); + for(unsigned long v = 0; v < num; ++v) + { + for(unsigned long d = 0; d < dim; ++d) + { + EncodeIntACEGC(m_quantVectors[d * num + v], ace, mModelValues, bModel0, bModel1, M); + } + } + encodedBytes = ace.stop_encoder(); + return O3DGC_OK; + } + + O3DGCErrorCode DynamicVectorEncoder::EncodePayload(const DVEncodeParams & params, + const DynamicVector & dynamicVector, + BinaryStream & bstream) + { +#ifdef DEBUG_VERBOSE + g_fileDebugDVEnc = fopen("dv_enc.txt", "w"); +#endif //DEBUG_VERBOSE + unsigned long start = bstream.GetSize(); + const unsigned long dim = dynamicVector.GetDimVector(); + const unsigned long num = dynamicVector.GetNVector(); + + bstream.WriteUInt32(0, m_streamType); + + for(unsigned long j=0 ; j bestEncodedBytes) + { + break; + } + bestM = M; + bestEncodedBytes = encodedBytes; + M *= 2; + } + EncodeAC(num, dim, bestM, encodedBytes); + for(unsigned long i = 0; i < encodedBytes; ++i) + { + bstream.WriteUChar8Bin(m_bufferAC[i]); + } + } + bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType); +#ifdef DEBUG_VERBOSE + fclose(g_fileDebugDVEnc); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } + O3DGCErrorCode DynamicVectorEncoder::Quantize(const Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits) + { + const unsigned long size = numFloatArray * dimFloatArray; + Real r; + if (m_maxNumVectors < size) + { + delete [] m_quantVectors; + m_maxNumVectors = size; + m_quantVectors = new long [m_maxNumVectors]; + } + Real delta; + for(unsigned long d = 0; d < dimFloatArray; ++d) + { + r = maxFloatArray[d] - minFloatArray[d]; + if (r > 0.0f) + { + delta = (float)((1 << nQBits) - 1) / r; + } + else + { + delta = 1.0f; + } + for(unsigned long v = 0; v < numFloatArray; ++v) + { + m_quantVectors[v + d * numFloatArray] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta + 0.5f); + } + } + return O3DGC_OK; + } +} diff --git a/contrib/Open3DGC/o3dgcDynamicVectorEncoder.h b/contrib/Open3DGC/o3dgcDynamicVectorEncoder.h new file mode 100644 index 000000000..de42a020f --- /dev/null +++ b/contrib/Open3DGC/o3dgcDynamicVectorEncoder.h @@ -0,0 +1,79 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_DYNAMIC_VECTOR_ENCODER_H +#define O3DGC_DYNAMIC_VECTOR_ENCODER_H + +#include "o3dgcCommon.h" +#include "o3dgcBinaryStream.h" +#include "o3dgcDynamicVector.h" + +namespace o3dgc +{ + //! + class DynamicVectorEncoder + { + public: + //! Constructor. + DynamicVectorEncoder(void); + //! Destructor. + ~DynamicVectorEncoder(void); + //! + O3DGCErrorCode Encode(const DVEncodeParams & params, + const DynamicVector & dynamicVector, + BinaryStream & bstream); + O3DGCStreamType GetStreamType() const { return m_streamType; } + void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } + + private: + O3DGCErrorCode EncodeHeader(const DVEncodeParams & params, + const DynamicVector & dynamicVector, + BinaryStream & bstream); + O3DGCErrorCode EncodePayload(const DVEncodeParams & params, + const DynamicVector & dynamicVector, + BinaryStream & bstream); + O3DGCErrorCode Quantize(const Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits); + O3DGCErrorCode EncodeAC(unsigned long num, + unsigned long dim, + unsigned long M, + unsigned long & encodedBytes); + + unsigned long m_posSize; + unsigned long m_sizeBufferAC; + unsigned long m_maxNumVectors; + unsigned long m_numVectors; + unsigned long m_dimVectors; + unsigned char * m_bufferAC; + long * m_quantVectors; + O3DGCStreamType m_streamType; + }; +} +#endif // O3DGC_DYNAMIC_VECTOR_ENCODER_H + diff --git a/contrib/Open3DGC/o3dgcFIFO.h b/contrib/Open3DGC/o3dgcFIFO.h new file mode 100644 index 000000000..874c26475 --- /dev/null +++ b/contrib/Open3DGC/o3dgcFIFO.h @@ -0,0 +1,97 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_FIFO_H +#define O3DGC_FIFO_H + +#include "o3dgcCommon.h" + +namespace o3dgc +{ + //! + template < typename T > class FIFO + { + public: + //! Constructor. + FIFO() + { + m_buffer = 0; + m_allocated = 0; + m_size = 0; + m_start = 0; + m_end = 0; + }; + //! Destructor. + ~FIFO(void) + { + delete [] m_buffer; + }; + O3DGCErrorCode Allocate(unsigned long size) + { + assert(size > 0); + if (size > m_allocated) + { + delete [] m_buffer; + m_allocated = size; + m_buffer = new T [m_allocated]; + } + Clear(); + return O3DGC_OK; + } + const T & PopFirst() + { + assert(m_size > 0); + --m_size; + unsigned long current = m_start++; + if (m_start == m_allocated) + { + m_end = 0; + } + return m_buffer[current]; + }; + void PushBack(const T & value) + { + assert( m_size < m_allocated); + m_buffer[m_end] = value; + ++m_size; + ++m_end; + if (m_end == m_allocated) + { + m_end = 0; + } + } + const unsigned long GetSize() const { return m_size;}; + const unsigned long GetAllocatedSize() const { return m_allocated;}; + void Clear() { m_start = m_end = m_size = 0;}; + + private: + T * m_buffer; + unsigned long m_allocated; + unsigned long m_size; + unsigned long m_start; + unsigned long m_end; + }; +} +#endif // O3DGC_FIFO_H + diff --git a/contrib/Open3DGC/o3dgcIndexedFaceSet.h b/contrib/Open3DGC/o3dgcIndexedFaceSet.h new file mode 100644 index 000000000..4af9de437 --- /dev/null +++ b/contrib/Open3DGC/o3dgcIndexedFaceSet.h @@ -0,0 +1,263 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_INDEXED_FACE_SET_H +#define O3DGC_INDEXED_FACE_SET_H + +#include "o3dgcCommon.h" + +namespace o3dgc +{ + template + class IndexedFaceSet + { + public: + //! Constructor. + IndexedFaceSet(void) + { + memset(this, 0, sizeof(IndexedFaceSet)); + m_ccw = true; + m_solid = true; + m_convex = true; + m_isTriangularMesh = true; + m_creaseAngle = 30; + }; + //! Destructor. + ~IndexedFaceSet(void) {}; + + unsigned long GetNCoordIndex() const { return m_nCoordIndex ;} + // only coordIndex is supported + unsigned long GetNCoord() const { return m_nCoord ;} + unsigned long GetNNormal() const { return m_nNormal ;} + unsigned long GetNFloatAttribute(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return m_nFloatAttribute[a]; + } + unsigned long GetNIntAttribute(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + return m_nIntAttribute[a]; + } + unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;} + unsigned long GetNumIntAttributes() const { return m_numIntAttributes ;} + const Real * const GetCoordMin () const { return m_coordMin;} + const Real * const GetCoordMax () const { return m_coordMax;} + const Real * const GetNormalMin () const { return m_normalMin;} + const Real * const GetNormalMax () const { return m_normalMax;} + Real GetCoordMin (int j) const { return m_coordMin[j] ;} + Real GetCoordMax (int j) const { return m_coordMax[j] ;} + Real GetNormalMin (int j) const { return m_normalMin[j] ;} + Real GetNormalMax (int j) const { return m_normalMax[j] ;} + + const O3DGCIFSFloatAttributeType GetFloatAttributeType(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return m_typeFloatAttribute[a]; + } + const O3DGCIFSIntAttributeType GetIntAttributeType(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + return m_typeIntAttribute[a]; + } + const unsigned long GetFloatAttributeDim(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return m_dimFloatAttribute[a]; + } + unsigned long GetIntAttributeDim(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + return m_dimIntAttribute[a]; + } + const Real * const GetFloatAttributeMin(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return &(m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]); + } + const Real * const GetFloatAttributeMax(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return &(m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]); + } + Real GetFloatAttributeMin(unsigned long a, unsigned long dim) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + return m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim]; + } + Real GetFloatAttributeMax(unsigned long a, unsigned long dim) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + return m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim]; + } + Real GetCreaseAngle() const { return m_creaseAngle ;} + bool GetCCW() const { return m_ccw ;} + bool GetSolid() const { return m_solid ;} + bool GetConvex() const { return m_convex ;} + bool GetIsTriangularMesh() const { return m_isTriangularMesh;} + const unsigned long * const GetIndexBufferID() const { return m_indexBufferID ;} + const T * const GetCoordIndex() const { return m_coordIndex;} + T * const GetCoordIndex() { return m_coordIndex;} + Real * const GetCoord() const { return m_coord ;} + Real * const GetNormal() const { return m_normal ;} + Real * const GetFloatAttribute(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return m_floatAttribute[a]; + } + long * const GetIntAttribute(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + return m_intAttribute[a] ; + } + // only coordIndex is supported + void SetNNormalIndex(unsigned long) {} + void SetNTexCoordIndex(unsigned long) {} + void SetNFloatAttributeIndex(int, unsigned long) {} + void SetNIntAttributeIndex (int, unsigned long) {} + // per triangle attributes not supported + void SetNormalPerVertex(bool) {} + void SetColorPerVertex(bool) {} + void SetFloatAttributePerVertex(int, bool){} + void SetIntAttributePerVertex (int, bool){} + void SetNCoordIndex (unsigned long nCoordIndex) { m_nCoordIndex = nCoordIndex;} + void SetNCoord (unsigned long nCoord) { m_nCoord = nCoord ;} + void SetNNormal (unsigned long nNormal) { m_nNormal = nNormal ;} + void SetNumFloatAttributes(unsigned long numFloatAttributes) + { + assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_numFloatAttributes = numFloatAttributes; + } + void SetNumIntAttributes (unsigned long numIntAttributes) + { + assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + m_numIntAttributes = numIntAttributes; + } + void SetCreaseAngle (Real creaseAngle) { m_creaseAngle = creaseAngle ;} + void SetCCW (bool ccw) { m_ccw = ccw ;} + void SetSolid (bool solid) { m_solid = solid ;} + void SetConvex (bool convex) { m_convex = convex ;} + void SetIsTriangularMesh (bool isTriangularMesh) { m_isTriangularMesh = isTriangularMesh;} + void SetCoordMin (int j, Real min) { m_coordMin[j] = min;} + void SetCoordMax (int j, Real max) { m_coordMax[j] = max;} + void SetNormalMin (int j, Real min) { m_normalMin[j] = min;} + void SetNormalMax (int j, Real max) { m_normalMax[j] = max;} + void SetNFloatAttribute(unsigned long a, unsigned long nFloatAttribute) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_nFloatAttribute[a] = nFloatAttribute; + } + void SetNIntAttribute(unsigned long a, unsigned long nIntAttribute) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + m_nIntAttribute[a] = nIntAttribute; + } + void SetFloatAttributeDim(unsigned long a, unsigned long d) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_dimFloatAttribute[a] = d; + } + void SetIntAttributeDim(unsigned long a, unsigned long d) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + m_dimIntAttribute[a] = d; + } + void SetFloatAttributeType(unsigned long a, O3DGCIFSFloatAttributeType t) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_typeFloatAttribute[a] = t; + } + void SetIntAttributeType(unsigned long a, O3DGCIFSIntAttributeType t) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + m_typeIntAttribute[a] = t; + } + void SetFloatAttributeMin(unsigned long a, unsigned long dim, Real min) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = min; + } + void SetFloatAttributeMax(unsigned long a, unsigned long dim, Real max) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = max; + } + void SetIndexBufferID (unsigned long * const indexBufferID) { m_indexBufferID = indexBufferID;} + void SetCoordIndex (T * const coordIndex) { m_coordIndex = coordIndex;} + void SetCoord (Real * const coord ) { m_coord = coord ;} + void SetNormal (Real * const normal ) { m_normal = normal ;} + void SetFloatAttribute (unsigned long a, Real * const floatAttribute) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_floatAttribute[a] = floatAttribute; + } + void SetIntAttribute (unsigned long a, long * const intAttribute) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + m_intAttribute[a] = intAttribute ; + } + void ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode); + + private: + // triangles list + unsigned long m_nCoordIndex; + T * m_coordIndex; + unsigned long * m_indexBufferID; + // coord, normals, texcoord and color + unsigned long m_nCoord; + unsigned long m_nNormal; + Real m_coordMin [3]; + Real m_coordMax [3]; + Real m_normalMin [3]; + Real m_normalMax [3]; + Real * m_coord; + Real * m_normal; + // other attributes + unsigned long m_numFloatAttributes; + unsigned long m_numIntAttributes; + O3DGCIFSFloatAttributeType m_typeFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + O3DGCIFSIntAttributeType m_typeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; + unsigned long m_nFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + unsigned long m_nIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; + unsigned long m_dimFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + unsigned long m_dimIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; + Real m_minFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; + Real m_maxFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; + Real * m_floatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + long * m_intAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + // mesh info + Real m_creaseAngle; + bool m_ccw; + bool m_solid; + bool m_convex; + bool m_isTriangularMesh; + }; +} +#include "o3dgcIndexedFaceSet.inl" // template implementation +#endif // O3DGC_INDEXED_FACE_SET_H + diff --git a/contrib/Open3DGC/o3dgcIndexedFaceSet.inl b/contrib/Open3DGC/o3dgcIndexedFaceSet.inl new file mode 100644 index 000000000..ddac26d76 --- /dev/null +++ b/contrib/Open3DGC/o3dgcIndexedFaceSet.inl @@ -0,0 +1,47 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_INDEXED_FACE_SET_INL +#define O3DGC_INDEXED_FACE_SET_INL + +#include +namespace o3dgc +{ + template + void IndexedFaceSet::ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode) + { + ComputeVectorMinMax(m_coord , m_nCoord , 3, 3, m_coordMin , m_coordMax , quantMode); + ComputeVectorMinMax(m_normal , m_nNormal , 3, 3, m_normalMin , m_normalMax , quantMode); + unsigned long numFloatAttributes = GetNumFloatAttributes(); + for(unsigned long a = 0; a < numFloatAttributes; ++a) + { + ComputeVectorMinMax(m_floatAttribute[a], + m_nFloatAttribute[a], + m_dimFloatAttribute[a], + m_dimFloatAttribute[a], // stride + m_minFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES), + m_maxFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES), quantMode); + } + } +} +#endif // O3DGC_INDEXED_FACE_SET_INL diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.h b/contrib/Open3DGC/o3dgcSC3DMCDecoder.h new file mode 100644 index 000000000..c8ca70ff6 --- /dev/null +++ b/contrib/Open3DGC/o3dgcSC3DMCDecoder.h @@ -0,0 +1,111 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_SC3DMC_DECODER_H +#define O3DGC_SC3DMC_DECODER_H + +#include "o3dgcCommon.h" +#include "o3dgcBinaryStream.h" +#include "o3dgcIndexedFaceSet.h" +#include "o3dgcSC3DMCEncodeParams.h" +#include "o3dgcTriangleListDecoder.h" + +namespace o3dgc +{ + //! + template + class SC3DMCDecoder + { + public: + //! Constructor. + SC3DMCDecoder(void) + { + m_iterator = 0; + m_streamSize = 0; + m_quantFloatArray = 0; + m_quantFloatArraySize = 0; + m_normals = 0; + m_normalsSize = 0; + m_streamType = O3DGC_STREAM_TYPE_UNKOWN; + }; + //! Destructor. + ~SC3DMCDecoder(void) + { + delete [] m_normals; + delete [] m_quantFloatArray; + } + //! + O3DGCErrorCode DecodeHeader(IndexedFaceSet & ifs, + const BinaryStream & bstream); + //! + O3DGCErrorCode DecodePlayload(IndexedFaceSet & ifs, + const BinaryStream & bstream); + const SC3DMCStats & GetStats() const { return m_stats;} + unsigned long GetIterator() const { return m_iterator;} + O3DGCErrorCode SetIterator(unsigned long iterator) { m_iterator = iterator;} + + + private: + O3DGCErrorCode DecodeFloatArray(Real * const floatArray, + unsigned long numfloatArraySize, + unsigned long dimfloatArraySize, + unsigned long stride, + const Real * const minfloatArray, + const Real * const maxfloatArray, + unsigned long nQBits, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode & predMode, + const BinaryStream & bstream); + O3DGCErrorCode IQuantizeFloatArray(Real * const floatArray, + unsigned long numfloatArraySize, + unsigned long dimfloatArraySize, + unsigned long stride, + const Real * const minfloatArray, + const Real * const maxfloatArray, + unsigned long nQBits); + O3DGCErrorCode DecodeIntArray(long * const intArray, + unsigned long numIntArraySize, + unsigned long dimIntArraySize, + unsigned long stride, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode & predMode, + const BinaryStream & bstream); + O3DGCErrorCode ProcessNormals(const IndexedFaceSet & ifs); + + unsigned long m_iterator; + unsigned long m_streamSize; + SC3DMCEncodeParams m_params; + TriangleListDecoder m_triangleListDecoder; + long * m_quantFloatArray; + unsigned long m_quantFloatArraySize; + Vector m_orientation; + Real * m_normals; + unsigned long m_normalsSize; + SC3DMCStats m_stats; + O3DGCStreamType m_streamType; + }; +} +#include "o3dgcSC3DMCDecoder.inl" // template implementation +#endif // O3DGC_SC3DMC_DECODER_H + diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl new file mode 100644 index 000000000..040b405be --- /dev/null +++ b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl @@ -0,0 +1,850 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_SC3DMC_DECODER_INL +#define O3DGC_SC3DMC_DECODER_INL + +#include "o3dgcArithmeticCodec.h" +#include "o3dgcTimer.h" + +//#define DEBUG_VERBOSE + +namespace o3dgc +{ +#ifdef DEBUG_VERBOSE + FILE * g_fileDebugSC3DMCDec = NULL; +#endif //DEBUG_VERBOSE + + template + O3DGCErrorCode SC3DMCDecoder::DecodeHeader(IndexedFaceSet & ifs, + const BinaryStream & bstream) + { + unsigned long iterator0 = m_iterator; + unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY); + if (start_code != O3DGC_SC3DMC_START_CODE) + { + m_iterator = iterator0; + start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII); + if (start_code != O3DGC_SC3DMC_START_CODE) + { + return O3DGC_ERROR_CORRUPTED_STREAM; + } + else + { + m_streamType = O3DGC_STREAM_TYPE_ASCII; + } + } + else + { + m_streamType = O3DGC_STREAM_TYPE_BINARY; + } + + m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType); + m_params.SetEncodeMode( (O3DGCSC3DMCEncodingMode) bstream.ReadUChar(m_iterator, m_streamType)); + + ifs.SetCreaseAngle((Real) bstream.ReadFloat32(m_iterator, m_streamType)); + + unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType); + + ifs.SetCCW ((mask & 1) == 1); + ifs.SetSolid ((mask & 2) == 1); + ifs.SetConvex ((mask & 4) == 1); + ifs.SetIsTriangularMesh((mask & 8) == 1); + //bool markerBit0 = (mask & 16 ) == 1; + //bool markerBit1 = (mask & 32 ) == 1; + //bool markerBit2 = (mask & 64 ) == 1; + //bool markerBit3 = (mask & 128) == 1; + + ifs.SetNCoord (bstream.ReadUInt32(m_iterator, m_streamType)); + ifs.SetNNormal (bstream.ReadUInt32(m_iterator, m_streamType)); + + + ifs.SetNumFloatAttributes(bstream.ReadUInt32(m_iterator, m_streamType)); + ifs.SetNumIntAttributes (bstream.ReadUInt32(m_iterator, m_streamType)); + + if (ifs.GetNCoord() > 0) + { + ifs.SetNCoordIndex(bstream.ReadUInt32(m_iterator, m_streamType)); + for(int j=0 ; j<3 ; ++j) + { + ifs.SetCoordMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + ifs.SetCoordMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + } + m_params.SetCoordQuantBits( bstream.ReadUChar(m_iterator, m_streamType) ); + } + if (ifs.GetNNormal() > 0) + { + ifs.SetNNormalIndex(bstream.ReadUInt32(m_iterator, m_streamType)); + for(int j=0 ; j<3 ; ++j) + { + ifs.SetNormalMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + ifs.SetNormalMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + } + ifs.SetNormalPerVertex(bstream.ReadUChar(m_iterator, m_streamType) == 1); + m_params.SetNormalQuantBits(bstream.ReadUChar(m_iterator, m_streamType)); + } + + for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) + { + ifs.SetNFloatAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType)); + if (ifs.GetNFloatAttribute(a) > 0) + { + ifs.SetNFloatAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType)); + unsigned char d = bstream.ReadUChar(m_iterator, m_streamType); + ifs.SetFloatAttributeDim(a, d); + for(unsigned char j = 0 ; j < d ; ++j) + { + ifs.SetFloatAttributeMin(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + ifs.SetFloatAttributeMax(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); + } + ifs.SetFloatAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1); + ifs.SetFloatAttributeType(a, (O3DGCIFSFloatAttributeType) bstream.ReadUChar(m_iterator, m_streamType)); + m_params.SetFloatAttributeQuantBits(a, bstream.ReadUChar(m_iterator, m_streamType)); + } + } + for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) + { + ifs.SetNIntAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType)); + if (ifs.GetNIntAttribute(a) > 0) + { + ifs.SetNIntAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType)); + ifs.SetIntAttributeDim(a, bstream.ReadUChar(m_iterator, m_streamType)); + ifs.SetIntAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1); + ifs.SetIntAttributeType(a, (O3DGCIFSIntAttributeType) bstream.ReadUChar(m_iterator, m_streamType)); + } + } + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCDecoder::DecodePlayload(IndexedFaceSet & ifs, + const BinaryStream & bstream) + { + O3DGCErrorCode ret = O3DGC_OK; +#ifdef DEBUG_VERBOSE + g_fileDebugSC3DMCDec = fopen("tfans_dec_main.txt", "w"); +#endif //DEBUG_VERBOSE + + m_triangleListDecoder.SetStreamType(m_streamType); + m_stats.m_streamSizeCoordIndex = m_iterator; + Timer timer; + timer.Tic(); + m_triangleListDecoder.Decode(ifs.GetCoordIndex(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream, m_iterator); + timer.Toc(); + m_stats.m_timeCoordIndex = timer.GetElapsedTime(); + m_stats.m_streamSizeCoordIndex = m_iterator - m_stats.m_streamSizeCoordIndex; + + // decode coord + m_stats.m_streamSizeCoord = m_iterator; + timer.Tic(); + if (ifs.GetNCoord() > 0) + { + ret = DecodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(), + m_params.GetCoordQuantBits(), ifs, m_params.GetCoordPredMode(), bstream); + } + if (ret != O3DGC_OK) + { + return ret; + } + timer.Toc(); + m_stats.m_timeCoord = timer.GetElapsedTime(); + m_stats.m_streamSizeCoord = m_iterator - m_stats.m_streamSizeCoord; + + // decode Normal + m_stats.m_streamSizeNormal = m_iterator; + timer.Tic(); + if (ifs.GetNNormal() > 0) + { + DecodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(), + m_params.GetNormalQuantBits(), ifs, m_params.GetNormalPredMode(), bstream); + } + if (ret != O3DGC_OK) + { + return ret; + } + timer.Toc(); + m_stats.m_timeNormal = timer.GetElapsedTime(); + m_stats.m_streamSizeNormal = m_iterator - m_stats.m_streamSizeNormal; + + // decode FloatAttributes + for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) + { + m_stats.m_streamSizeFloatAttribute[a] = m_iterator; + timer.Tic(); + DecodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a), + ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a), + m_params.GetFloatAttributeQuantBits(a), ifs, m_params.GetFloatAttributePredMode(a), bstream); + timer.Toc(); + m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime(); + m_stats.m_streamSizeFloatAttribute[a] = m_iterator - m_stats.m_streamSizeFloatAttribute[a]; + } + if (ret != O3DGC_OK) + { + return ret; + } + + // decode IntAttributes + for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) + { + m_stats.m_streamSizeIntAttribute[a] = m_iterator; + timer.Tic(); + DecodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), ifs.GetIntAttributeDim(a), + ifs, m_params.GetIntAttributePredMode(a), bstream); + timer.Toc(); + m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime(); + m_stats.m_streamSizeIntAttribute[a] = m_iterator - m_stats.m_streamSizeIntAttribute[a]; + } + if (ret != O3DGC_OK) + { + return ret; + } + + timer.Tic(); + m_triangleListDecoder.Reorder(); + timer.Toc(); + m_stats.m_timeReorder = timer.GetElapsedTime(); + +#ifdef DEBUG_VERBOSE + fclose(g_fileDebugSC3DMCDec); +#endif //DEBUG_VERBOSE + return ret; + } + template + O3DGCErrorCode SC3DMCDecoder::DecodeIntArray(long * const intArray, + unsigned long numIntArray, + unsigned long dimIntArray, + unsigned long stride, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode & predMode, + const BinaryStream & bstream) + { + assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + long predResidual; + SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; + Arithmetic_Codec acd; + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); + unsigned long nPred; + + const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle(); + const T * const triangles = ifs.GetCoordIndex(); + const long nvert = (long) numIntArray; + unsigned char * buffer = 0; + unsigned long start = m_iterator; + unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size + unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType); + O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7); + predMode = (O3DGCSC3DMCPredictionMode)(mask & 7); + streamSize -= (m_iterator - start); + unsigned long iteratorPred = m_iterator + streamSize; + unsigned int exp_k = 0; + unsigned int M = 0; + if (m_streamType != O3DGC_STREAM_TYPE_ASCII) + { + if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC) + { + return O3DGC_ERROR_CORRUPTED_STREAM; + } + bstream.GetBuffer(m_iterator, buffer); + m_iterator += streamSize; + acd.set_buffer(streamSize, buffer); + acd.start_decoder(); + exp_k = acd.ExpGolombDecode(0, bModel0, bModel1); + M = acd.ExpGolombDecode(0, bModel0, bModel1); + } + else + { + if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII) + { + return O3DGC_ERROR_CORRUPTED_STREAM; + } + bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size + } + Adaptive_Data_Model mModelValues(M+2); + +#ifdef DEBUG_VERBOSE + printf("IntArray (%i, %i)\n", numIntArray, dimIntArray); + fprintf(g_fileDebugSC3DMCDec, "IntArray (%i, %i)\n", numIntArray, dimIntArray); +#endif //DEBUG_VERBOSE + + for (long v=0; v < nvert; ++v) + { + nPred = 0; + if ( v2T.GetNumNeighbors(v) > 0 && + predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + int u0 = v2T.Begin(v); + int u1 = v2T.End(v); + for (long u = u0; u < u1; u++) + { + long ta = v2T.GetNeighbor(u); + if (ta < 0) + { + break; + } + for(long k = 0; k < 3; ++k) + { + long w = triangles[ta*3 + k]; + if ( w < v ) + { + SC3DMCTriplet id = {-1, -1, w}; + unsigned long p = Insert(id, nPred, m_neighbors); + if (p != 0xFFFFFFFF) + { + for (unsigned long i = 0; i < dimIntArray; i++) + { + m_neighbors[p].m_pred[i] = intArray[w*stride+i]; + } + } + } + } + } + } + if (nPred > 1) + { +#ifdef DEBUG_VERBOSE1 + printf("\t\t vm %i\n", v); + fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v); + for (unsigned long p = 0; p < nPred; ++p) + { + printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); + fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); + for (unsigned long i = 0; i < dimIntArray; ++i) + { + printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); + fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); + } + } +#endif //DEBUG_VERBOSE + unsigned long bestPred; + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bestPred = bstream.ReadUCharASCII(iteratorPred); + } + else + { + bestPred = acd.decode(mModelPreds); + } +#ifdef DEBUG_VERBOSE1 + printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); + fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); +#endif //DEBUG_VERBOSE + for (unsigned long i = 0; i < dimIntArray; i++) + { + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + predResidual = bstream.ReadIntASCII(m_iterator); + } + else + { + predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); + } + intArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i]; +#ifdef DEBUG_VERBOSE + printf("%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); + fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); +#endif //DEBUG_VERBOSE + } + } + else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + for (unsigned long i = 0; i < dimIntArray; i++) + { + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + predResidual = bstream.ReadIntASCII(m_iterator); + } + else + { + predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); + } + intArray[v*stride+i] = predResidual + intArray[(v-1)*stride+i]; +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", v*dimIntArray+i, predResidual); + fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + else + { + for (unsigned long i = 0; i < dimIntArray; i++) + { + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + predResidual = bstream.ReadUIntASCII(m_iterator); + } + else + { + predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); + } + intArray[v*stride+i] = predResidual; +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", v*dimIntArray+i, predResidual); + fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + } + m_iterator = iteratorPred; +#ifdef DEBUG_VERBOSE + fflush(g_fileDebugSC3DMCDec); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCDecoder::ProcessNormals(const IndexedFaceSet & ifs) + { + const long nvert = (long) ifs.GetNNormal(); + const unsigned long normalSize = ifs.GetNNormal() * 2; + if (m_normalsSize < normalSize) + { + delete [] m_normals; + m_normalsSize = normalSize; + m_normals = new Real [normalSize]; + } + const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle(); + const T * const triangles = ifs.GetCoordIndex(); + Vec3 p1, p2, p3, n0, nt; + long na0, nb0; + Real rna0, rnb0, norm0; + char ni0 = 0, ni1 = 0; + long a, b, c; + for (long v=0; v < nvert; ++v) + { + n0.X() = 0; + n0.Y() = 0; + n0.Z() = 0; + int u0 = v2T.Begin(v); + int u1 = v2T.End(v); + for (long u = u0; u < u1; u++) + { + long ta = v2T.GetNeighbor(u); + if (ta == -1) + { + break; + } + a = triangles[ta*3 + 0]; + b = triangles[ta*3 + 1]; + c = triangles[ta*3 + 2]; + p1.X() = m_quantFloatArray[3*a]; + p1.Y() = m_quantFloatArray[3*a+1]; + p1.Z() = m_quantFloatArray[3*a+2]; + p2.X() = m_quantFloatArray[3*b]; + p2.Y() = m_quantFloatArray[3*b+1]; + p2.Z() = m_quantFloatArray[3*b+2]; + p3.X() = m_quantFloatArray[3*c]; + p3.Y() = m_quantFloatArray[3*c+1]; + p3.Z() = m_quantFloatArray[3*c+2]; + nt = (p2-p1)^(p3-p1); + n0 += nt; + } + norm0 = (Real) n0.GetNorm(); + if (norm0 == 0.0) + { + norm0 = 1.0; + } + SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0); + + + rna0 = na0 / norm0; + rnb0 = nb0 / norm0; + ni1 = ni0 + m_orientation[v]; + m_orientation[v] = ni1; + if ( (ni1 >> 1) != (ni0 >> 1) ) + { + rna0 = Real(0.0); + rnb0 = Real(0.0); + } + m_normals[2*v] = rna0; + m_normals[2*v+1] = rnb0; + +#ifdef DEBUG_VERBOSE1 + printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); + fprintf(g_fileDebugSC3DMCDec, "n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); +#endif //DEBUG_VERBOSE + + } + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCDecoder::DecodeFloatArray(Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode & predMode, + const BinaryStream & bstream) + { + assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + long predResidual; + SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; + Arithmetic_Codec acd; + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); + unsigned long nPred; + + const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle(); + const T * const triangles = ifs.GetCoordIndex(); + const long nvert = (long) numFloatArray; + const unsigned long size = numFloatArray * dimFloatArray; + unsigned char * buffer = 0; + unsigned long start = m_iterator; + unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size + unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType); + O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7); + predMode = (O3DGCSC3DMCPredictionMode)(mask & 7); + streamSize -= (m_iterator - start); + unsigned long iteratorPred = m_iterator + streamSize; + unsigned int exp_k = 0; + unsigned int M = 0; + if (m_streamType != O3DGC_STREAM_TYPE_ASCII) + { + if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC) + { + return O3DGC_ERROR_CORRUPTED_STREAM; + } + bstream.GetBuffer(m_iterator, buffer); + m_iterator += streamSize; + acd.set_buffer(streamSize, buffer); + acd.start_decoder(); + exp_k = acd.ExpGolombDecode(0, bModel0, bModel1); + M = acd.ExpGolombDecode(0, bModel0, bModel1); + } + else + { + if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII) + { + return O3DGC_ERROR_CORRUPTED_STREAM; + } + bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size + } + Adaptive_Data_Model mModelValues(M+2); + + + if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) + { + m_orientation.Allocate(size); + m_orientation.Clear(); + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + for(unsigned long i = 0; i < numFloatArray; ++i) + { + m_orientation.PushBack((unsigned char) bstream.ReadIntASCII(m_iterator)); + } + } + else + { + Adaptive_Data_Model dModel(12); + for(unsigned long i = 0; i < numFloatArray; ++i) + { + m_orientation.PushBack((unsigned char) UIntToInt(acd.decode(dModel))); + } + } + ProcessNormals(ifs); + dimFloatArray = 2; + } +#ifdef DEBUG_VERBOSE + printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); + fprintf(g_fileDebugSC3DMCDec, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); +#endif //DEBUG_VERBOSE + + if (m_quantFloatArraySize < size) + { + delete [] m_quantFloatArray; + m_quantFloatArraySize = size; + m_quantFloatArray = new long [size]; + } + for (long v=0; v < nvert; ++v) + { + nPred = 0; + if ( v2T.GetNumNeighbors(v) > 0 && + predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + int u0 = v2T.Begin(v); + int u1 = v2T.End(v); + for (long u = u0; u < u1; u++) + { + long ta = v2T.GetNeighbor(u); + if (ta < 0) + { + break; + } + if (predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION) + { + long a,b; + if ((long) triangles[ta*3] == v) + { + a = triangles[ta*3 + 1]; + b = triangles[ta*3 + 2]; + } + else if ((long)triangles[ta*3 + 1] == v) + { + a = triangles[ta*3 + 0]; + b = triangles[ta*3 + 2]; + } + else + { + a = triangles[ta*3 + 0]; + b = triangles[ta*3 + 1]; + } + if ( a < v && b < v) + { + int u0 = v2T.Begin(a); + int u1 = v2T.End(a); + for (long u = u0; u < u1; u++) + { + long tb = v2T.GetNeighbor(u); + if (tb < 0) + { + break; + } + long c = -1; + bool foundB = false; + for(long k = 0; k < 3; ++k) + { + long x = triangles[tb*3 + k]; + if (x == b) + { + foundB = true; + } + if (x < v && x != a && x != b) + { + c = x; + } + } + if (c != -1 && foundB) + { + SC3DMCTriplet id = {min(a, b), max(a, b), -c-1}; + unsigned long p = Insert(id, nPred, m_neighbors); + if (p != 0xFFFFFFFF) + { + for (unsigned long i = 0; i < dimFloatArray; i++) + { + m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] + + m_quantFloatArray[b*stride+i] - + m_quantFloatArray[c*stride+i]; + } + } + } + } + } + } + if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION || + predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION || + predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION ) + { + for(long k = 0; k < 3; ++k) + { + long w = triangles[ta*3 + k]; + if ( w < v ) + { + SC3DMCTriplet id = {-1, -1, w}; + unsigned long p = Insert(id, nPred, m_neighbors); + if (p != 0xFFFFFFFF) + { + for (unsigned long i = 0; i < dimFloatArray; i++) + { + m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i]; + } + } + } + } + } + } + } + if (nPred > 1) + { +#ifdef DEBUG_VERBOSE1 + printf("\t\t vm %i\n", v); + fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v); + for (unsigned long p = 0; p < nPred; ++p) + { + printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); + fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); + for (unsigned long i = 0; i < dimFloatArray; ++i) + { + printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); + fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); + } + } +#endif //DEBUG_VERBOSE + unsigned long bestPred; + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bestPred = bstream.ReadUCharASCII(iteratorPred); + } + else + { + bestPred = acd.decode(mModelPreds); + } +#ifdef DEBUG_VERBOSE1 + printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); + fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); +#endif //DEBUG_VERBOSE + for (unsigned long i = 0; i < dimFloatArray; i++) + { + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + predResidual = bstream.ReadIntASCII(m_iterator); + } + else + { + predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); + } + m_quantFloatArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i]; +#ifdef DEBUG_VERBOSE + printf("%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); + fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); +#endif //DEBUG_VERBOSE + } + } + else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + for (unsigned long i = 0; i < dimFloatArray; i++) + { + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + predResidual = bstream.ReadIntASCII(m_iterator); + } + else + { + predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); + } + m_quantFloatArray[v*stride+i] = predResidual + m_quantFloatArray[(v-1)*stride+i]; +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", v*dimFloatArray+i, predResidual); + fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + else + { + for (unsigned long i = 0; i < dimFloatArray; i++) + { + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + predResidual = bstream.ReadUIntASCII(m_iterator); + } + else + { + predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); + } + m_quantFloatArray[v*stride+i] = predResidual; +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", v*dimFloatArray+i, predResidual); + fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + } + m_iterator = iteratorPred; + if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) + { + const Real minNormal[2] = {(Real)(-2),(Real)(-2)}; + const Real maxNormal[2] = {(Real)(2),(Real)(2)}; + Real na1, nb1; + Real na0, nb0; + char ni1; + IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minNormal, maxNormal, nQBits+1); + for (long v=0; v < nvert; ++v) + { + na0 = m_normals[2*v]; + nb0 = m_normals[2*v+1]; + na1 = floatArray[stride*v] + na0; + nb1 = floatArray[stride*v+1] + nb0; + ni1 = m_orientation[v]; + + CubeToSphere(na1, nb1, ni1, + floatArray[stride*v], + floatArray[stride*v+1], + floatArray[stride*v+2]); + +#ifdef DEBUG_VERBOSE1 + printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", + v, + floatArray[stride*v], + floatArray[stride*v+1], + floatArray[stride*v+2], + ni1, na1, nb1, + na0, nb0); + fprintf(g_fileDebugSC3DMCDec, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", + v, + floatArray[stride*v], + floatArray[stride*v+1], + floatArray[stride*v+2], + ni1, na1, nb1, + na0, nb0); +#endif //DEBUG_VERBOSE + } + } + else + { + IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits); + } +#ifdef DEBUG_VERBOSE + fflush(g_fileDebugSC3DMCDec); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCDecoder::IQuantizeFloatArray(Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits) + { + + Real idelta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; + Real r; + for(unsigned long d = 0; d < dimFloatArray; d++) + { + r = maxFloatArray[d] - minFloatArray[d]; + if (r > 0.0f) + { + idelta[d] = r/(float)((1 << nQBits) - 1); + } + else + { + idelta[d] = 1.0f; + } + } + for(unsigned long v = 0; v < numFloatArray; ++v) + { + for(unsigned long d = 0; d < dimFloatArray; ++d) + { +// floatArray[v * stride + d] = m_quantFloatArray[v * stride + d]; + floatArray[v * stride + d] = m_quantFloatArray[v * stride + d] * idelta[d] + minFloatArray[d]; + } + } + return O3DGC_OK; + } +} +#endif // O3DGC_SC3DMC_DECODER_INL + + diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h b/contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h new file mode 100644 index 000000000..5f3db969c --- /dev/null +++ b/contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h @@ -0,0 +1,140 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_SC3DMC_ENCODE_PARAMS_H +#define O3DGC_SC3DMC_ENCODE_PARAMS_H + +#include "o3dgcCommon.h" + +namespace o3dgc +{ + class SC3DMCEncodeParams + { + public: + //! Constructor. + SC3DMCEncodeParams(void) + { + memset(this, 0, sizeof(SC3DMCEncodeParams)); + m_encodeMode = O3DGC_SC3DMC_ENCODE_MODE_TFAN; + m_streamTypeMode = O3DGC_STREAM_TYPE_ASCII; + m_coordQuantBits = 14; + m_normalQuantBits = 8; + m_coordPredMode = O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION; + m_normalPredMode = O3DGC_SC3DMC_SURF_NORMALS_PREDICTION; + for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES; ++a) + { + m_floatAttributePredMode[a] = O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION; + } + for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES; ++a) + { + m_intAttributePredMode[a] = O3DGC_SC3DMC_NO_PREDICTION; + } + }; + //! Destructor. + ~SC3DMCEncodeParams(void) {}; + + O3DGCStreamType GetStreamType() const { return m_streamTypeMode;} + O3DGCSC3DMCEncodingMode GetEncodeMode() const { return m_encodeMode;} + + unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;} + unsigned long GetNumIntAttributes() const { return m_numIntAttributes;} + unsigned long GetCoordQuantBits() const { return m_coordQuantBits;} + unsigned long GetNormalQuantBits() const { return m_normalQuantBits;} + unsigned long GetFloatAttributeQuantBits(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return m_floatAttributeQuantBits[a]; + } + O3DGCSC3DMCPredictionMode GetCoordPredMode() const { return m_coordPredMode; } + O3DGCSC3DMCPredictionMode GetNormalPredMode() const { return m_normalPredMode; } + O3DGCSC3DMCPredictionMode GetFloatAttributePredMode(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return m_floatAttributePredMode[a]; + } + O3DGCSC3DMCPredictionMode GetIntAttributePredMode(unsigned long a) const + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + return m_intAttributePredMode[a]; + } + O3DGCSC3DMCPredictionMode & GetCoordPredMode() { return m_coordPredMode; } + O3DGCSC3DMCPredictionMode & GetNormalPredMode() { return m_normalPredMode; } + O3DGCSC3DMCPredictionMode & GetFloatAttributePredMode(unsigned long a) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + return m_floatAttributePredMode[a]; + } + O3DGCSC3DMCPredictionMode & GetIntAttributePredMode(unsigned long a) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + return m_intAttributePredMode[a]; + } + void SetStreamType(O3DGCStreamType streamTypeMode) { m_streamTypeMode = streamTypeMode;} + void SetEncodeMode(O3DGCSC3DMCEncodingMode encodeMode) { m_encodeMode = encodeMode;} + void SetNumFloatAttributes(unsigned long numFloatAttributes) + { + assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_numFloatAttributes = numFloatAttributes; + } + void SetNumIntAttributes (unsigned long numIntAttributes) + { + assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + m_numIntAttributes = numIntAttributes; + } + void SetCoordQuantBits (unsigned int coordQuantBits ) { m_coordQuantBits = coordQuantBits ; } + void SetNormalQuantBits (unsigned int normalQuantBits ) { m_normalQuantBits = normalQuantBits ; } + void SetFloatAttributeQuantBits(unsigned long a, unsigned long q) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_floatAttributeQuantBits[a] = q; + } + void SetCoordPredMode (O3DGCSC3DMCPredictionMode coordPredMode ) { m_coordPredMode = coordPredMode ; } + void SetNormalPredMode (O3DGCSC3DMCPredictionMode normalPredMode ) { m_normalPredMode = normalPredMode ; } + void SetFloatAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); + m_floatAttributePredMode[a] = p; + } + void SetIntAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p) + { + assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); + m_intAttributePredMode[a] = p; + } + private: + unsigned long m_numFloatAttributes; + unsigned long m_numIntAttributes; + unsigned long m_coordQuantBits; + unsigned long m_normalQuantBits; + unsigned long m_floatAttributeQuantBits[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + + O3DGCSC3DMCPredictionMode m_coordPredMode; + O3DGCSC3DMCPredictionMode m_normalPredMode; + O3DGCSC3DMCPredictionMode m_floatAttributePredMode[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; + O3DGCSC3DMCPredictionMode m_intAttributePredMode [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES]; + O3DGCStreamType m_streamTypeMode; + O3DGCSC3DMCEncodingMode m_encodeMode; + }; +} +#endif // O3DGC_SC3DMC_ENCODE_PARAMS_H + diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncoder.h b/contrib/Open3DGC/o3dgcSC3DMCEncoder.h new file mode 100644 index 000000000..9c4e95026 --- /dev/null +++ b/contrib/Open3DGC/o3dgcSC3DMCEncoder.h @@ -0,0 +1,116 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_SC3DMC_ENCODER_H +#define O3DGC_SC3DMC_ENCODER_H + +#include "o3dgcCommon.h" +#include "o3dgcBinaryStream.h" +#include "o3dgcIndexedFaceSet.h" +#include "o3dgcSC3DMCEncodeParams.h" +#include "o3dgcTriangleListEncoder.h" + +namespace o3dgc +{ + //! + template + class SC3DMCEncoder + { + public: + //! Constructor. + SC3DMCEncoder(void) + { + m_posSize = 0; + m_quantFloatArray = 0; + m_quantFloatArraySize = 0; + m_sizeBufferAC = 0; + m_bufferAC = 0; + m_normals = 0; + m_normalsSize = 0; + m_streamType = O3DGC_STREAM_TYPE_UNKOWN; + }; + //! Destructor. + ~SC3DMCEncoder(void) + { + delete [] m_normals; + delete [] m_quantFloatArray; + delete [] m_bufferAC; + } + //! + O3DGCErrorCode Encode(const SC3DMCEncodeParams & params, + const IndexedFaceSet & ifs, + BinaryStream & bstream); + const SC3DMCStats & GetStats() const { return m_stats;} + + private: + O3DGCErrorCode EncodeHeader(const SC3DMCEncodeParams & params, + const IndexedFaceSet & ifs, + BinaryStream & bstream); + O3DGCErrorCode EncodePayload(const SC3DMCEncodeParams & params, + const IndexedFaceSet & ifs, + BinaryStream & bstream); + O3DGCErrorCode EncodeFloatArray(const Real * const floatArray, + unsigned long numfloatArray, + unsigned long dimfloatArray, + unsigned long stride, + const Real * const minfloatArray, + const Real * const maxfloatArray, + unsigned long nQBits, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode predMode, + BinaryStream & bstream); + O3DGCErrorCode QuantizeFloatArray(const Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minfloatArray, + const Real * const maxfloatArray, + unsigned long nQBits); + O3DGCErrorCode EncodeIntArray(const long * const intArray, + unsigned long numIntArray, + unsigned long dimIntArray, + unsigned long stride, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode predMode, + BinaryStream & bstream); + O3DGCErrorCode ProcessNormals(const IndexedFaceSet & ifs); + TriangleListEncoder m_triangleListEncoder; + long * m_quantFloatArray; + unsigned long m_posSize; + unsigned long m_quantFloatArraySize; + unsigned char * m_bufferAC; + unsigned long m_sizeBufferAC; + SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; + unsigned long m_freqSymbols[O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS]; + unsigned long m_freqPreds [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; + Vector m_predictors; + Real * m_normals; + unsigned long m_normalsSize; + SC3DMCStats m_stats; + O3DGCStreamType m_streamType; + }; +} +#include "o3dgcSC3DMCEncoder.inl" // template implementation +#endif // O3DGC_SC3DMC_ENCODER_H + diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl b/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl new file mode 100644 index 000000000..b2c438814 --- /dev/null +++ b/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl @@ -0,0 +1,927 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_SC3DMC_ENCODER_INL +#define O3DGC_SC3DMC_ENCODER_INL + + +#include "o3dgcArithmeticCodec.h" +#include "o3dgcTimer.h" +#include "o3dgcVector.h" +#include "o3dgcBinaryStream.h" +#include "o3dgcCommon.h" + +//#define DEBUG_VERBOSE + +namespace o3dgc +{ +#ifdef DEBUG_VERBOSE + FILE * g_fileDebugSC3DMCEnc = NULL; +#endif //DEBUG_VERBOSE + + template + O3DGCErrorCode SC3DMCEncoder::Encode(const SC3DMCEncodeParams & params, + const IndexedFaceSet & ifs, + BinaryStream & bstream) + { + // Encode header + unsigned long start = bstream.GetSize(); + EncodeHeader(params, ifs, bstream); + // Encode payload + EncodePayload(params, ifs, bstream); + bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType); + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCEncoder::EncodeHeader(const SC3DMCEncodeParams & params, + const IndexedFaceSet & ifs, + BinaryStream & bstream) + { + m_streamType = params.GetStreamType(); + bstream.WriteUInt32(O3DGC_SC3DMC_START_CODE, m_streamType); + m_posSize = bstream.GetSize(); + bstream.WriteUInt32(0, m_streamType); // to be filled later + + bstream.WriteUChar(O3DGC_SC3DMC_ENCODE_MODE_TFAN, m_streamType); + bstream.WriteFloat32((float)ifs.GetCreaseAngle(), m_streamType); + + unsigned char mask = 0; + bool markerBit0 = false; + bool markerBit1 = false; + bool markerBit2 = false; + bool markerBit3 = false; + + mask += (ifs.GetCCW() ); + mask += (ifs.GetSolid() << 1); + mask += (ifs.GetConvex() << 2); + mask += (ifs.GetIsTriangularMesh() << 3); + mask += (markerBit0 << 4); + mask += (markerBit1 << 5); + mask += (markerBit2 << 6); + mask += (markerBit3 << 7); + + bstream.WriteUChar(mask, m_streamType); + + bstream.WriteUInt32(ifs.GetNCoord(), m_streamType); + bstream.WriteUInt32(ifs.GetNNormal(), m_streamType); + bstream.WriteUInt32(ifs.GetNumFloatAttributes(), m_streamType); + bstream.WriteUInt32(ifs.GetNumIntAttributes(), m_streamType); + + if (ifs.GetNCoord() > 0) + { + bstream.WriteUInt32(ifs.GetNCoordIndex(), m_streamType); + for(int j=0 ; j<3 ; ++j) + { + bstream.WriteFloat32((float) ifs.GetCoordMin(j), m_streamType); + bstream.WriteFloat32((float) ifs.GetCoordMax(j), m_streamType); + } + bstream.WriteUChar((unsigned char) params.GetCoordQuantBits(), m_streamType); + } + if (ifs.GetNNormal() > 0) + { + bstream.WriteUInt32(0, m_streamType); + for(int j=0 ; j<3 ; ++j) + { + bstream.WriteFloat32((float) ifs.GetNormalMin(j), m_streamType); + bstream.WriteFloat32((float) ifs.GetNormalMax(j), m_streamType); + } + bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetNormalPerVertex() + bstream.WriteUChar((unsigned char) params.GetNormalQuantBits(), m_streamType); + } + for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) + { + bstream.WriteUInt32(ifs.GetNFloatAttribute(a), m_streamType); + if (ifs.GetNFloatAttribute(a) > 0) + { + assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8); + bstream.WriteUInt32(0, m_streamType); + unsigned char d = (unsigned char) ifs.GetFloatAttributeDim(a); + bstream.WriteUChar(d, m_streamType); + for(unsigned char j = 0 ; j < d ; ++j) + { + bstream.WriteFloat32((float) ifs.GetFloatAttributeMin(a, j), m_streamType); + bstream.WriteFloat32((float) ifs.GetFloatAttributeMax(a, j), m_streamType); + } + bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetFloatAttributePerVertex(a) + bstream.WriteUChar((unsigned char) ifs.GetFloatAttributeType(a), m_streamType); + bstream.WriteUChar((unsigned char) params.GetFloatAttributeQuantBits(a), m_streamType); + } + } + for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) + { + bstream.WriteUInt32(ifs.GetNIntAttribute(a), m_streamType); + if (ifs.GetNIntAttribute(a) > 0) + { + assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8); + bstream.WriteUInt32(0, m_streamType); + bstream.WriteUChar((unsigned char) ifs.GetIntAttributeDim(a), m_streamType); + bstream.WriteUChar(true, m_streamType); // (unsigned char) ifs.GetIntAttributePerVertex(a) + bstream.WriteUChar((unsigned char) ifs.GetIntAttributeType(a), m_streamType); + } + } + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCEncoder::QuantizeFloatArray(const Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits) + { + const unsigned long size = numFloatArray * dimFloatArray; + Real delta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; + Real r; + for(unsigned long d = 0; d < dimFloatArray; d++) + { + r = maxFloatArray[d] - minFloatArray[d]; + if (r > 0.0f) + { + delta[d] = (float)((1 << nQBits) - 1) / r; + } + else + { + delta[d] = 1.0f; + } + } + if (m_quantFloatArraySize < size) + { + delete [] m_quantFloatArray; + m_quantFloatArraySize = size; + m_quantFloatArray = new long [size]; + } + for(unsigned long v = 0; v < numFloatArray; ++v) + { + for(unsigned long d = 0; d < dimFloatArray; ++d) + { + m_quantFloatArray[v * stride + d] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta[d] + 0.5f); + } + } + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCEncoder::EncodeFloatArray(const Real * const floatArray, + unsigned long numFloatArray, + unsigned long dimFloatArray, + unsigned long stride, + const Real * const minFloatArray, + const Real * const maxFloatArray, + unsigned long nQBits, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode predMode, + BinaryStream & bstream) + { + assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + long predResidual, v, uPredResidual; + unsigned long nPred; + Arithmetic_Codec ace; + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + + const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle(); + const long * const vmap = m_triangleListEncoder.GetVMap(); + const long * const invVMap = m_triangleListEncoder.GetInvVMap(); + const T * const triangles = ifs.GetCoordIndex(); + const long nvert = (long) numFloatArray; + unsigned long start = bstream.GetSize(); + unsigned char mask = predMode & 7; + const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1; + unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS; + unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS; + + + Adaptive_Data_Model mModelValues(M+2); + Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); + + memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS); + memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS); + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4; + m_predictors.Allocate(nvert); + m_predictors.Clear(); + } + else + { + mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4; + const unsigned int NMAX = numFloatArray * dimFloatArray * 8 + 100; + if ( m_sizeBufferAC < NMAX ) + { + delete [] m_bufferAC; + m_sizeBufferAC = NMAX; + m_bufferAC = new unsigned char [m_sizeBufferAC]; + } + ace.set_buffer(NMAX, m_bufferAC); + ace.start_encoder(); + ace.ExpGolombEncode(0, 0, bModel0, bModel1); + ace.ExpGolombEncode(M, 0, bModel0, bModel1); + } + bstream.WriteUInt32(0, m_streamType); + bstream.WriteUChar(mask, m_streamType); + +#ifdef DEBUG_VERBOSE + printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); + fprintf(g_fileDebugSC3DMCEnc, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); +#endif //DEBUG_VERBOSE + + if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) + { + const Real minFloatArray[2] = {(Real)(-2.0),(Real)(-2.0)}; + const Real maxFloatArray[2] = {(Real)(2.0),(Real)(2.0)}; + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + for(unsigned long i = 0; i < numFloatArray; ++i) + { + bstream.WriteIntASCII(m_predictors[i]); + } + } + else + { + Adaptive_Data_Model dModel(12); + for(unsigned long i = 0; i < numFloatArray; ++i) + { + ace.encode(IntToUInt(m_predictors[i]), dModel); + } + } + QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits+1); + } + else + { + QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits); + } + + for (long vm=0; vm < nvert; ++vm) + { + nPred = 0; + v = invVMap[vm]; + assert( v >= 0 && v < nvert); + if ( v2T.GetNumNeighbors(v) > 0 && + predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + int u0 = v2T.Begin(v); + int u1 = v2T.End(v); + for (long u = u0; u < u1; u++) + { + long ta = v2T.GetNeighbor(u); + if ( predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ) + { + long a,b; + if ((long) triangles[ta*3] == v) + { + a = triangles[ta*3 + 1]; + b = triangles[ta*3 + 2]; + } + else if ((long) triangles[ta*3 + 1] == v) + { + a = triangles[ta*3 + 0]; + b = triangles[ta*3 + 2]; + } + else + { + a = triangles[ta*3 + 0]; + b = triangles[ta*3 + 1]; + } + if ( vmap[a] < vm && vmap[b] < vm) + { + int u0 = v2T.Begin(a); + int u1 = v2T.End(a); + for (long u = u0; u < u1; u++) + { + long tb = v2T.GetNeighbor(u); + long c = -1; + bool foundB = false; + for(long k = 0; k < 3; ++k) + { + long x = triangles[tb*3 + k]; + if (x == b) + { + foundB = true; + } + if (vmap[x] < vm && x != a && x != b) + { + c = x; + } + } + if (c != -1 && foundB) + { + SC3DMCTriplet id = {min(vmap[a], vmap[b]), max(vmap[a], vmap[b]), -vmap[c]-1}; + unsigned long p = Insert(id, nPred, m_neighbors); + if (p != 0xFFFFFFFF) + { + for (unsigned long i = 0; i < dimFloatArray; i++) + { + m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] + + m_quantFloatArray[b*stride+i] - + m_quantFloatArray[c*stride+i]; + } + } + } + } + } + } + if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION || + predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION || + predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION ) + { + for(long k = 0; k < 3; ++k) + { + long w = triangles[ta*3 + k]; + if ( vmap[w] < vm ) + { + SC3DMCTriplet id = {-1, -1, vmap[w]}; + unsigned long p = Insert(id, nPred, m_neighbors); + if (p != 0xFFFFFFFF) + { + for (unsigned long i = 0; i < dimFloatArray; i++) + { + m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i]; + } + } + } + } + } + } + } + if (nPred > 1) + { + // find best predictor + unsigned long bestPred = 0xFFFFFFFF; + double bestCost = O3DGC_MAX_DOUBLE; + double cost; +#ifdef DEBUG_VERBOSE1 + printf("\t\t vm %i\n", vm); + fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm); +#endif //DEBUG_VERBOSE + + for (unsigned long p = 0; p < nPred; ++p) + { +#ifdef DEBUG_VERBOSE1 + printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); + fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); +#endif //DEBUG_VERBOSE + cost = -log2((m_freqPreds[p]+1.0) / nPredictors ); + for (unsigned long i = 0; i < dimFloatArray; ++i) + { +#ifdef DEBUG_VERBOSE1 + printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); + fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); +#endif //DEBUG_VERBOSE + + predResidual = (long) IntToUInt(m_quantFloatArray[v*stride+i] - m_neighbors[p].m_pred[i]); + if (predResidual < (long) M) + { + cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols ); + } + else + { + cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M)); + } + } + if (cost < bestCost) + { + bestCost = cost; + bestPred = p; + } + } + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + m_predictors.PushBack((unsigned char) bestPred); + } + else + { + ace.encode(bestPred, mModelPreds); + } +#ifdef DEBUG_VERBOSE1 + printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); + fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); +#endif //DEBUG_VERBOSE + // use best predictor + for (unsigned long i = 0; i < dimFloatArray; ++i) + { + predResidual = m_quantFloatArray[v*stride+i] - m_neighbors[bestPred].m_pred[i]; + uPredResidual = IntToUInt(predResidual); + ++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M]; + +#ifdef DEBUG_VERBOSE + printf("%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); + fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); +#endif //DEBUG_VERBOSE + + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bstream.WriteIntASCII(predResidual); + } + else + { + EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); + } + } + ++m_freqPreds[bestPred]; + nSymbols += dimFloatArray; + ++nPredictors; + } + else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + long prev = invVMap[vm-1]; + for (unsigned long i = 0; i < dimFloatArray; i++) + { + predResidual = m_quantFloatArray[v*stride+i] - m_quantFloatArray[prev*stride+i]; + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bstream.WriteIntASCII(predResidual); + } + else + { + EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); + } +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", vm*dimFloatArray+i, predResidual); + fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + else + { + for (unsigned long i = 0; i < dimFloatArray; i++) + { + predResidual = m_quantFloatArray[v*stride+i]; + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bstream.WriteUIntASCII(predResidual); + } + else + { + EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); + } +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", vm*dimFloatArray+i, predResidual); + fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + } + if (m_streamType != O3DGC_STREAM_TYPE_ASCII) + { + unsigned long encodedBytes = ace.stop_encoder(); + for(unsigned long i = 0; i < encodedBytes; ++i) + { + bstream.WriteUChar8Bin(m_bufferAC[i]); + } + } + bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType); + + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + unsigned long start = bstream.GetSize(); + bstream.WriteUInt32ASCII(0); + const unsigned long size = m_predictors.GetSize(); + for(unsigned long i = 0; i < size; ++i) + { + bstream.WriteUCharASCII((unsigned char) m_predictors[i]); + } + bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); + } +#ifdef DEBUG_VERBOSE + fflush(g_fileDebugSC3DMCEnc); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } + + template + O3DGCErrorCode SC3DMCEncoder::EncodeIntArray(const long * const intArray, + unsigned long numIntArray, + unsigned long dimIntArray, + unsigned long stride, + const IndexedFaceSet & ifs, + O3DGCSC3DMCPredictionMode predMode, + BinaryStream & bstream) + { + assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); + long predResidual, v, uPredResidual; + unsigned long nPred; + Arithmetic_Codec ace; + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + + const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle(); + const long * const vmap = m_triangleListEncoder.GetVMap(); + const long * const invVMap = m_triangleListEncoder.GetInvVMap(); + const T * const triangles = ifs.GetCoordIndex(); + const long nvert = (long) numIntArray; + unsigned long start = bstream.GetSize(); + unsigned char mask = predMode & 7; + const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1; + unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS; + unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS; + + + Adaptive_Data_Model mModelValues(M+2); + Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); + + memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS); + memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS); + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4; + m_predictors.Allocate(nvert); + m_predictors.Clear(); + } + else + { + mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4; + const unsigned int NMAX = numIntArray * dimIntArray * 8 + 100; + if ( m_sizeBufferAC < NMAX ) + { + delete [] m_bufferAC; + m_sizeBufferAC = NMAX; + m_bufferAC = new unsigned char [m_sizeBufferAC]; + } + ace.set_buffer(NMAX, m_bufferAC); + ace.start_encoder(); + ace.ExpGolombEncode(0, 0, bModel0, bModel1); + ace.ExpGolombEncode(M, 0, bModel0, bModel1); + } + bstream.WriteUInt32(0, m_streamType); + bstream.WriteUChar(mask, m_streamType); + +#ifdef DEBUG_VERBOSE + printf("IntArray (%i, %i)\n", numIntArray, dimIntArray); + fprintf(g_fileDebugSC3DMCEnc, "IntArray (%i, %i)\n", numIntArray, dimIntArray); +#endif //DEBUG_VERBOSE + + for (long vm=0; vm < nvert; ++vm) + { + nPred = 0; + v = invVMap[vm]; + assert( v >= 0 && v < nvert); + if ( v2T.GetNumNeighbors(v) > 0 && + predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + int u0 = v2T.Begin(v); + int u1 = v2T.End(v); + for (long u = u0; u < u1; u++) + { + long ta = v2T.GetNeighbor(u); + for(long k = 0; k < 3; ++k) + { + long w = triangles[ta*3 + k]; + if ( vmap[w] < vm ) + { + SC3DMCTriplet id = {-1, -1, vmap[w]}; + unsigned long p = Insert(id, nPred, m_neighbors); + if (p != 0xFFFFFFFF) + { + for (unsigned long i = 0; i < dimIntArray; i++) + { + m_neighbors[p].m_pred[i] = intArray[w*stride+i]; + } + } + } + } + } + } + if (nPred > 1) + { + // find best predictor + unsigned long bestPred = 0xFFFFFFFF; + double bestCost = O3DGC_MAX_DOUBLE; + double cost; +#ifdef DEBUG_VERBOSE1 + printf("\t\t vm %i\n", vm); + fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm); +#endif //DEBUG_VERBOSE + + for (unsigned long p = 0; p < nPred; ++p) + { +#ifdef DEBUG_VERBOSE1 + printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); + fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); +#endif //DEBUG_VERBOSE + cost = -log2((m_freqPreds[p]+1.0) / nPredictors ); + for (unsigned long i = 0; i < dimIntArray; ++i) + { +#ifdef DEBUG_VERBOSE1 + printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); + fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); +#endif //DEBUG_VERBOSE + + predResidual = (long) IntToUInt(intArray[v*stride+i] - m_neighbors[p].m_pred[i]); + if (predResidual < (long) M) + { + cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols ); + } + else + { + cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M)); + } + } + if (cost < bestCost) + { + bestCost = cost; + bestPred = p; + } + } + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + m_predictors.PushBack((unsigned char) bestPred); + } + else + { + ace.encode(bestPred, mModelPreds); + } +#ifdef DEBUG_VERBOSE1 + printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); + fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); +#endif //DEBUG_VERBOSE + // use best predictor + for (unsigned long i = 0; i < dimIntArray; ++i) + { + predResidual = intArray[v*stride+i] - m_neighbors[bestPred].m_pred[i]; + uPredResidual = IntToUInt(predResidual); + ++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M]; + +#ifdef DEBUG_VERBOSE + printf("%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); + fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); +#endif //DEBUG_VERBOSE + + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bstream.WriteIntASCII(predResidual); + } + else + { + EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); + } + } + ++m_freqPreds[bestPred]; + nSymbols += dimIntArray; + ++nPredictors; + } + else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) + { + long prev = invVMap[vm-1]; + for (unsigned long i = 0; i < dimIntArray; i++) + { + predResidual = intArray[v*stride+i] - intArray[prev*stride+i]; + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bstream.WriteIntASCII(predResidual); + } + else + { + EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); + } +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", vm*dimIntArray+i, predResidual); + fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + else + { + for (unsigned long i = 0; i < dimIntArray; i++) + { + predResidual = intArray[v*stride+i]; + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + bstream.WriteUIntASCII(predResidual); + } + else + { + EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); + } +#ifdef DEBUG_VERBOSE + printf("%i \t %i\n", vm*dimIntArray+i, predResidual); + fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual); +#endif //DEBUG_VERBOSE + } + } + } + if (m_streamType != O3DGC_STREAM_TYPE_ASCII) + { + unsigned long encodedBytes = ace.stop_encoder(); + for(unsigned long i = 0; i < encodedBytes; ++i) + { + bstream.WriteUChar8Bin(m_bufferAC[i]); + } + } + bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType); + + if (m_streamType == O3DGC_STREAM_TYPE_ASCII) + { + unsigned long start = bstream.GetSize(); + bstream.WriteUInt32ASCII(0); + const unsigned long size = m_predictors.GetSize(); + for(unsigned long i = 0; i < size; ++i) + { + bstream.WriteUCharASCII((unsigned char) m_predictors[i]); + } + bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); + } +#ifdef DEBUG_VERBOSE + fflush(g_fileDebugSC3DMCEnc); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } + template + O3DGCErrorCode SC3DMCEncoder::ProcessNormals(const IndexedFaceSet & ifs) + { + const long nvert = (long) ifs.GetNNormal(); + const unsigned long normalSize = ifs.GetNNormal() * 2; + if (m_normalsSize < normalSize) + { + delete [] m_normals; + m_normalsSize = normalSize; + m_normals = new Real [normalSize]; + } + const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle(); + const long * const invVMap = m_triangleListEncoder.GetInvVMap(); + const T * const triangles = ifs.GetCoordIndex(); + const Real * const originalNormals = ifs.GetNormal(); + Vec3 p1, p2, p3, n0, nt; + Vec3 n1; + long na0, nb0; + Real rna0, rnb0, na1, nb1, norm0, norm1; + char ni0 = 0, ni1 = 0; + long a, b, c, v; + m_predictors.Clear(); + for (long i=0; i < nvert; ++i) + { + v = invVMap[i]; + n0.X() = 0; + n0.Y() = 0; + n0.Z() = 0; + int u0 = v2T.Begin(v); + int u1 = v2T.End(v); + for (long u = u0; u < u1; u++) + { + long ta = v2T.GetNeighbor(u); + a = triangles[ta*3 + 0]; + b = triangles[ta*3 + 1]; + c = triangles[ta*3 + 2]; + p1.X() = m_quantFloatArray[3*a]; + p1.Y() = m_quantFloatArray[3*a+1]; + p1.Z() = m_quantFloatArray[3*a+2]; + p2.X() = m_quantFloatArray[3*b]; + p2.Y() = m_quantFloatArray[3*b+1]; + p2.Z() = m_quantFloatArray[3*b+2]; + p3.X() = m_quantFloatArray[3*c]; + p3.Y() = m_quantFloatArray[3*c+1]; + p3.Z() = m_quantFloatArray[3*c+2]; + nt = (p2-p1)^(p3-p1); + n0 += nt; + } + norm0 = (Real) n0.GetNorm(); + if (norm0 == 0.0) + { + norm0 = 1.0; + } + SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0); + rna0 = na0 / norm0; + rnb0 = nb0 / norm0; + + n1.X() = originalNormals[3*v]; + n1.Y() = originalNormals[3*v+1]; + n1.Z() = originalNormals[3*v+2]; + norm1 = (Real) n1.GetNorm(); + if (norm1 != 0.0) + { + n1.X() /= norm1; + n1.Y() /= norm1; + n1.Z() /= norm1; + } + SphereToCube(n1.X(), n1.Y(), n1.Z(), na1, nb1, ni1); + m_predictors.PushBack(ni1 - ni0); + if ( (ni1 >> 1) != (ni0 >> 1) ) + { + rna0 = (Real)0.0; + rnb0 = (Real)0.0; + } + m_normals[2*v] = na1 - rna0; + m_normals[2*v+1] = nb1 - rnb0; + +#ifdef DEBUG_VERBOSE1 + printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); + fprintf(g_fileDebugSC3DMCEnc,"n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); +#endif //DEBUG_VERBOSE + +#ifdef DEBUG_VERBOSE1 + printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0); + fprintf(g_fileDebugSC3DMCEnc, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0); +#endif //DEBUG_VERBOSE + + } + return O3DGC_OK; + } + + template + O3DGCErrorCode SC3DMCEncoder::EncodePayload(const SC3DMCEncodeParams & params, + const IndexedFaceSet & ifs, + BinaryStream & bstream) + { +#ifdef DEBUG_VERBOSE + g_fileDebugSC3DMCEnc = fopen("tfans_enc_main.txt", "w"); +#endif //DEBUG_VERBOSE + + // encode triangle list + m_triangleListEncoder.SetStreamType(params.GetStreamType()); + m_stats.m_streamSizeCoordIndex = bstream.GetSize(); + Timer timer; + timer.Tic(); + m_triangleListEncoder.Encode(ifs.GetCoordIndex(), ifs.GetIndexBufferID(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream); + timer.Toc(); + m_stats.m_timeCoordIndex = timer.GetElapsedTime(); + m_stats.m_streamSizeCoordIndex = bstream.GetSize() - m_stats.m_streamSizeCoordIndex; + + // encode coord + m_stats.m_streamSizeCoord = bstream.GetSize(); + timer.Tic(); + if (ifs.GetNCoord() > 0) + { + EncodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(), + params.GetCoordQuantBits(), ifs, params.GetCoordPredMode(), bstream); + } + timer.Toc(); + m_stats.m_timeCoord = timer.GetElapsedTime(); + m_stats.m_streamSizeCoord = bstream.GetSize() - m_stats.m_streamSizeCoord; + + + // encode Normal + m_stats.m_streamSizeNormal = bstream.GetSize(); + timer.Tic(); + if (ifs.GetNNormal() > 0) + { + if (params.GetNormalPredMode() == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) + { + ProcessNormals(ifs); + EncodeFloatArray(m_normals, ifs.GetNNormal(), 2, 2, ifs.GetNormalMin(), ifs.GetNormalMax(), + params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream); + } + else + { + EncodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(), + params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream); + } + } + timer.Toc(); + m_stats.m_timeNormal = timer.GetElapsedTime(); + m_stats.m_streamSizeNormal = bstream.GetSize() - m_stats.m_streamSizeNormal; + + + // encode FloatAttribute + for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) + { + m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize(); + timer.Tic(); + EncodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), + ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a), + ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a), + params.GetFloatAttributeQuantBits(a), ifs, + params.GetFloatAttributePredMode(a), bstream); + timer.Toc(); + m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime(); + m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeFloatAttribute[a]; + } + + // encode IntAttribute + for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) + { + m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize(); + timer.Tic(); + EncodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), + ifs.GetIntAttributeDim(a), ifs, params.GetIntAttributePredMode(a), bstream); + timer.Toc(); + m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime(); + m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeIntAttribute[a]; + } +#ifdef DEBUG_VERBOSE + fclose(g_fileDebugSC3DMCEnc); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } +} +#endif // O3DGC_SC3DMC_ENCODER_INL + + diff --git a/contrib/Open3DGC/o3dgcTimer.h b/contrib/Open3DGC/o3dgcTimer.h new file mode 100644 index 000000000..303d4f790 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTimer.h @@ -0,0 +1,132 @@ +/* +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 +#include +#elif __MACH__ +#include +#include +#else +#include +#include +#endif + + + +namespace o3dgc +{ +#ifdef WIN32 + class Timer + { + public: + Timer(void) + { + m_start.QuadPart = 0; + m_stop.QuadPart = 0; + QueryPerformanceFrequency( &m_freq ) ; + }; + ~Timer(void){}; + void Tic() + { + QueryPerformanceCounter(&m_start) ; + } + void Toc() + { + QueryPerformanceCounter(&m_stop); + } + double GetElapsedTime() // in ms + { + LARGE_INTEGER delta; + delta.QuadPart = m_stop.QuadPart - m_start.QuadPart; + return (1000.0 * delta.QuadPart) / (double)m_freq.QuadPart; + } + private: + LARGE_INTEGER m_start; + LARGE_INTEGER m_stop; + LARGE_INTEGER m_freq; + + }; +#elif __MACH__ + class Timer + { + public: + Timer(void) + { + memset(this, 0, sizeof(Timer)); + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, & m_cclock); + }; + ~Timer(void) + { + mach_port_deallocate(mach_task_self(), m_cclock); + }; + void Tic() + { + clock_get_time( m_cclock, &m_start); + } + void Toc() + { + clock_get_time( m_cclock, &m_stop); + } + double GetElapsedTime() // in ms + { + return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec)); + } + private: + clock_serv_t m_cclock; + mach_timespec_t m_start; + mach_timespec_t m_stop; + }; +#else + class Timer + { + public: + Timer(void) + { + memset(this, 0, sizeof(Timer)); + }; + ~Timer(void){}; + void Tic() + { + clock_gettime(CLOCK_REALTIME, &m_start); + } + void Toc() + { + clock_gettime(CLOCK_REALTIME, &m_stop); + } + double GetElapsedTime() // in ms + { + return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec)); + } + private: + struct timespec m_start; + struct timespec m_stop; + }; +#endif + +} +#endif // O3DGC_TIMER_H diff --git a/contrib/Open3DGC/o3dgcTools.cpp b/contrib/Open3DGC/o3dgcTools.cpp new file mode 100644 index 000000000..52b552304 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTools.cpp @@ -0,0 +1,22 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + diff --git a/contrib/Open3DGC/o3dgcTriangleFans.cpp b/contrib/Open3DGC/o3dgcTriangleFans.cpp new file mode 100644 index 000000000..078ed16e6 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTriangleFans.cpp @@ -0,0 +1,475 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "o3dgcTriangleFans.h" +#include "o3dgcArithmeticCodec.h" + +//#define DEBUG_VERBOSE + +namespace o3dgc +{ +#ifdef DEBUG_VERBOSE + FILE* g_fileDebugTF = NULL; +#endif //DEBUG_VERBOSE + + O3DGCErrorCode SaveUIntData(const Vector & data, + BinaryStream & bstream) + { + unsigned long start = bstream.GetSize(); + bstream.WriteUInt32ASCII(0); + const unsigned long size = data.GetSize(); + bstream.WriteUInt32ASCII(size); + for(unsigned long i = 0; i < size; ++i) + { + bstream.WriteUIntASCII(data[i]); + } + bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); + return O3DGC_OK; + } + O3DGCErrorCode SaveIntData(const Vector & data, + BinaryStream & bstream) + { + unsigned long start = bstream.GetSize(); + bstream.WriteUInt32ASCII(0); + const unsigned long size = data.GetSize(); + bstream.WriteUInt32ASCII(size); + for(unsigned long i = 0; i < size; ++i) + { + bstream.WriteIntASCII(data[i]); + } + bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); + return O3DGC_OK; + } + O3DGCErrorCode SaveBinData(const Vector & data, + BinaryStream & bstream) + { + unsigned long start = bstream.GetSize(); + bstream.WriteUInt32ASCII(0); + const unsigned long size = data.GetSize(); + long symbol; + bstream.WriteUInt32ASCII(size); + for(unsigned long i = 0; i < size; ) + { + symbol = 0; + for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0 && i < size; ++h) + { + symbol += (data[i] << h); + ++i; + } + bstream.WriteUCharASCII((unsigned char) symbol); + } + bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); + return O3DGC_OK; + } + O3DGCErrorCode CompressedTriangleFans::SaveUIntAC(const Vector & data, + const unsigned long M, + BinaryStream & bstream) + { + unsigned long start = bstream.GetSize(); + const unsigned int NMAX = data.GetSize() * 8 + 100; + const unsigned long size = data.GetSize(); + long minValue = O3DGC_MAX_LONG; + bstream.WriteUInt32Bin(0); + bstream.WriteUInt32Bin(size); + if (size > 0) + { + #ifdef DEBUG_VERBOSE + printf("-----------\nsize %i, start %i\n", size, start); + fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start); + #endif //DEBUG_VERBOSE + + for(unsigned long i = 0; i < size; ++i) + { + if (minValue > data[i]) + { + minValue = data[i]; + } + #ifdef DEBUG_VERBOSE + printf("%i\t%i\n", i, data[i]); + fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); + #endif //DEBUG_VERBOSE + } + bstream.WriteUInt32Bin(minValue); + if ( m_sizeBufferAC < NMAX ) + { + delete [] m_bufferAC; + m_sizeBufferAC = NMAX; + m_bufferAC = new unsigned char [m_sizeBufferAC]; + } + Arithmetic_Codec ace; + ace.set_buffer(NMAX, m_bufferAC); + ace.start_encoder(); + Adaptive_Data_Model mModelValues(M+1); + for(unsigned long i = 0; i < size; ++i) + { + ace.encode(data[i]-minValue, mModelValues); + } + unsigned long encodedBytes = ace.stop_encoder(); + for(unsigned long i = 0; i < encodedBytes; ++i) + { + bstream.WriteUChar8Bin(m_bufferAC[i]); + } + } + bstream.WriteUInt32Bin(start, bstream.GetSize() - start); + return O3DGC_OK; + } + O3DGCErrorCode CompressedTriangleFans::SaveBinAC(const Vector & data, + BinaryStream & bstream) + { + unsigned long start = bstream.GetSize(); + const unsigned int NMAX = data.GetSize() * 8 + 100; + const unsigned long size = data.GetSize(); + bstream.WriteUInt32Bin(0); + bstream.WriteUInt32Bin(size); + if (size > 0) + { + if ( m_sizeBufferAC < NMAX ) + { + delete [] m_bufferAC; + m_sizeBufferAC = NMAX; + m_bufferAC = new unsigned char [m_sizeBufferAC]; + } + Arithmetic_Codec ace; + ace.set_buffer(NMAX, m_bufferAC); + ace.start_encoder(); + Adaptive_Bit_Model bModel; + #ifdef DEBUG_VERBOSE + printf("-----------\nsize %i, start %i\n", size, start); + fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start); + #endif //DEBUG_VERBOSE + for(unsigned long i = 0; i < size; ++i) + { + ace.encode(data[i], bModel); + #ifdef DEBUG_VERBOSE + printf("%i\t%i\n", i, data[i]); + fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); + #endif //DEBUG_VERBOSE + } + unsigned long encodedBytes = ace.stop_encoder(); + for(unsigned long i = 0; i < encodedBytes; ++i) + { + bstream.WriteUChar8Bin(m_bufferAC[i]); + } + } + bstream.WriteUInt32Bin(start, bstream.GetSize() - start); + return O3DGC_OK; + } + + O3DGCErrorCode CompressedTriangleFans::SaveIntACEGC(const Vector & data, + const unsigned long M, + BinaryStream & bstream) + { + unsigned long start = bstream.GetSize(); + const unsigned int NMAX = data.GetSize() * 8 + 100; + const unsigned long size = data.GetSize(); + long minValue = 0; + bstream.WriteUInt32Bin(0); + bstream.WriteUInt32Bin(size); + if (size > 0) + { +#ifdef DEBUG_VERBOSE + printf("-----------\nsize %i, start %i\n", size, start); + fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start); +#endif //DEBUG_VERBOSE + for(unsigned long i = 0; i < size; ++i) + { + if (minValue > data[i]) + { + minValue = data[i]; + } +#ifdef DEBUG_VERBOSE + printf("%i\t%i\n", i, data[i]); + fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); +#endif //DEBUG_VERBOSE + } + bstream.WriteUInt32Bin(minValue + O3DGC_MAX_LONG); + if ( m_sizeBufferAC < NMAX ) + { + delete [] m_bufferAC; + m_sizeBufferAC = NMAX; + m_bufferAC = new unsigned char [m_sizeBufferAC]; + } + Arithmetic_Codec ace; + ace.set_buffer(NMAX, m_bufferAC); + ace.start_encoder(); + Adaptive_Data_Model mModelValues(M+2); + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + unsigned long value; + for(unsigned long i = 0; i < size; ++i) + { + value = data[i]-minValue; + if (value < M) + { + ace.encode(value, mModelValues); + } + else + { + ace.encode(M, mModelValues); + ace.ExpGolombEncode(value-M, 0, bModel0, bModel1); + } + } + unsigned long encodedBytes = ace.stop_encoder(); + for(unsigned long i = 0; i < encodedBytes; ++i) + { + bstream.WriteUChar8Bin(m_bufferAC[i]); + } + } + bstream.WriteUInt32Bin(start, bstream.GetSize() - start); + return O3DGC_OK; + } + O3DGCErrorCode CompressedTriangleFans::Save(BinaryStream & bstream, bool encodeTrianglesOrder, O3DGCStreamType streamType) + { +#ifdef DEBUG_VERBOSE + g_fileDebugTF = fopen("SaveIntACEGC_new.txt", "w"); +#endif //DEBUG_VERBOSE + + if (streamType == O3DGC_STREAM_TYPE_ASCII) + { + SaveUIntData(m_numTFANs , bstream); + SaveUIntData(m_degrees , bstream); + SaveUIntData(m_configs , bstream); + SaveBinData (m_operations, bstream); + SaveIntData (m_indices , bstream); + if (encodeTrianglesOrder) + { + SaveUIntData(m_trianglesOrder, bstream); + } + } + else + { + SaveIntACEGC(m_numTFANs , 4 , bstream); + SaveIntACEGC(m_degrees , 16, bstream); + SaveUIntAC (m_configs , 10, bstream); + SaveBinAC (m_operations, bstream); + SaveIntACEGC(m_indices , 8 , bstream); + if (encodeTrianglesOrder) + { + SaveIntACEGC(m_trianglesOrder , 16, bstream); + } + } +#ifdef DEBUG_VERBOSE + fclose(g_fileDebugTF); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } + O3DGCErrorCode LoadUIntData(Vector & data, + const BinaryStream & bstream, + unsigned long & iterator) + { + bstream.ReadUInt32ASCII(iterator); + const unsigned long size = bstream.ReadUInt32ASCII(iterator); + data.Allocate(size); + data.Clear(); + for(unsigned long i = 0; i < size; ++i) + { + data.PushBack(bstream.ReadUIntASCII(iterator)); + } + return O3DGC_OK; + } + O3DGCErrorCode LoadIntData(Vector & data, + const BinaryStream & bstream, + unsigned long & iterator) + { + bstream.ReadUInt32ASCII(iterator); + const unsigned long size = bstream.ReadUInt32ASCII(iterator); + data.Allocate(size); + data.Clear(); + for(unsigned long i = 0; i < size; ++i) + { + data.PushBack(bstream.ReadIntASCII(iterator)); + } + return O3DGC_OK; + } + O3DGCErrorCode LoadBinData(Vector & data, + const BinaryStream & bstream, + unsigned long & iterator) + { + bstream.ReadUInt32ASCII(iterator); + const unsigned long size = bstream.ReadUInt32ASCII(iterator); + long symbol; + data.Allocate(size * O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0); + data.Clear(); + for(unsigned long i = 0; i < size;) + { + symbol = bstream.ReadUCharASCII(iterator); + for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; ++h) + { + data.PushBack(symbol & 1); + symbol >>= 1; + ++i; + } + } + return O3DGC_OK; + } + O3DGCErrorCode LoadUIntAC(Vector & data, + const unsigned long M, + const BinaryStream & bstream, + unsigned long & iterator) + { + unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12; + unsigned long size = bstream.ReadUInt32Bin(iterator); + if (size == 0) + { + return O3DGC_OK; + } + long minValue = bstream.ReadUInt32Bin(iterator); + unsigned char * buffer = 0; + bstream.GetBuffer(iterator, buffer); + iterator += sizeSize; + data.Allocate(size); + Arithmetic_Codec acd; + acd.set_buffer(sizeSize, buffer); + acd.start_decoder(); + Adaptive_Data_Model mModelValues(M+1); +#ifdef DEBUG_VERBOSE + printf("-----------\nsize %i\n", size); + fprintf(g_fileDebugTF, "size %i\n", size); +#endif //DEBUG_VERBOSE + for(unsigned long i = 0; i < size; ++i) + { + data.PushBack(acd.decode(mModelValues)+minValue); +#ifdef DEBUG_VERBOSE + printf("%i\t%i\n", i, data[i]); + fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); +#endif //DEBUG_VERBOSE + } + return O3DGC_OK; + } + O3DGCErrorCode LoadIntACEGC(Vector & data, + const unsigned long M, + const BinaryStream & bstream, + unsigned long & iterator) + { + unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12; + unsigned long size = bstream.ReadUInt32Bin(iterator); + if (size == 0) + { + return O3DGC_OK; + } + long minValue = bstream.ReadUInt32Bin(iterator) - O3DGC_MAX_LONG; + unsigned char * buffer = 0; + bstream.GetBuffer(iterator, buffer); + iterator += sizeSize; + data.Allocate(size); + Arithmetic_Codec acd; + acd.set_buffer(sizeSize, buffer); + acd.start_decoder(); + Adaptive_Data_Model mModelValues(M+2); + Static_Bit_Model bModel0; + Adaptive_Bit_Model bModel1; + unsigned long value; + +#ifdef DEBUG_VERBOSE + printf("-----------\nsize %i\n", size); + fprintf(g_fileDebugTF, "size %i\n", size); +#endif //DEBUG_VERBOSE + for(unsigned long i = 0; i < size; ++i) + { + value = acd.decode(mModelValues); + if ( value == M) + { + value += acd.ExpGolombDecode(0, bModel0, bModel1); + } + data.PushBack(value + minValue); +#ifdef DEBUG_VERBOSE + printf("%i\t%i\n", i, data[i]); + fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); +#endif //DEBUG_VERBOSE + } +#ifdef DEBUG_VERBOSE + fflush(g_fileDebugTF); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } + O3DGCErrorCode LoadBinAC(Vector & data, + const BinaryStream & bstream, + unsigned long & iterator) + { + unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 8; + unsigned long size = bstream.ReadUInt32Bin(iterator); + if (size == 0) + { + return O3DGC_OK; + } + unsigned char * buffer = 0; + bstream.GetBuffer(iterator, buffer); + iterator += sizeSize; + data.Allocate(size); + Arithmetic_Codec acd; + acd.set_buffer(sizeSize, buffer); + acd.start_decoder(); + Adaptive_Bit_Model bModel; +#ifdef DEBUG_VERBOSE + printf("-----------\nsize %i\n", size); + fprintf(g_fileDebugTF, "size %i\n", size); +#endif //DEBUG_VERBOSE + for(unsigned long i = 0; i < size; ++i) + { + data.PushBack(acd.decode(bModel)); +#ifdef DEBUG_VERBOSE + printf("%i\t%i\n", i, data[i]); + fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); +#endif //DEBUG_VERBOSE + } + return O3DGC_OK; + } + O3DGCErrorCode CompressedTriangleFans::Load(const BinaryStream & bstream, + unsigned long & iterator, + bool decodeTrianglesOrder, + O3DGCStreamType streamType) + { +#ifdef DEBUG_VERBOSE + g_fileDebugTF = fopen("Load_new.txt", "w"); +#endif //DEBUG_VERBOSE + if (streamType == O3DGC_STREAM_TYPE_ASCII) + { + LoadUIntData(m_numTFANs , bstream, iterator); + LoadUIntData(m_degrees , bstream, iterator); + LoadUIntData(m_configs , bstream, iterator); + LoadBinData (m_operations, bstream, iterator); + LoadIntData (m_indices , bstream, iterator); + if (decodeTrianglesOrder) + { + LoadUIntData(m_trianglesOrder , bstream, iterator); + } + } + else + { + LoadIntACEGC(m_numTFANs , 4 , bstream, iterator); + LoadIntACEGC(m_degrees , 16, bstream, iterator); + LoadUIntAC (m_configs , 10, bstream, iterator); + LoadBinAC (m_operations, bstream, iterator); + LoadIntACEGC(m_indices , 8 , bstream, iterator); + if (decodeTrianglesOrder) + { + LoadIntACEGC(m_trianglesOrder , 16, bstream, iterator); + } + } + +#ifdef DEBUG_VERBOSE + fclose(g_fileDebugTF); +#endif //DEBUG_VERBOSE + return O3DGC_OK; + } +} + diff --git a/contrib/Open3DGC/o3dgcTriangleFans.h b/contrib/Open3DGC/o3dgcTriangleFans.h new file mode 100644 index 000000000..861836428 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTriangleFans.h @@ -0,0 +1,291 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_TRIANGLE_FANS_H +#define O3DGC_TRIANGLE_FANS_H + +#include "o3dgcCommon.h" +#include "o3dgcVector.h" +#include "o3dgcBinaryStream.h" + + +namespace o3dgc +{ + const long O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER = 128; + const long O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER = 8; + + class CompressedTriangleFans + { + public: + //! Constructor. + CompressedTriangleFans(void) + { + m_streamType = O3DGC_STREAM_TYPE_UNKOWN; + m_bufferAC = 0; + m_sizeBufferAC = 0; + }; + //! Destructor. + ~CompressedTriangleFans(void) + { + delete [] m_bufferAC; + }; + O3DGCStreamType GetStreamType() const { return m_streamType; } + void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } + + O3DGCErrorCode Allocate(long numVertices, long numTriangles) + { + assert(numVertices > 0); + m_numTFANs.Allocate(numVertices); + m_degrees.Allocate(2*numVertices); + m_configs.Allocate(2*numVertices); + m_operations.Allocate(2*numVertices); + m_indices.Allocate(2*numVertices); + m_trianglesOrder.Allocate(numTriangles); + Clear(); + return O3DGC_OK; + } + O3DGCErrorCode PushNumTFans(long numTFans) + { + m_numTFANs.PushBack(numTFans); + return O3DGC_OK; + } + long ReadNumTFans(unsigned long & iterator) const + { + assert(iterator < m_numTFANs.GetSize()); + return m_numTFANs[iterator++]; + } + O3DGCErrorCode PushDegree(long degree) + { + m_degrees.PushBack(degree); + return O3DGC_OK; + } + long ReadDegree(unsigned long & iterator) const + { + assert(iterator < m_degrees.GetSize()); + return m_degrees[iterator++]; + } + O3DGCErrorCode PushConfig(long config) + { + m_configs.PushBack(config); + return O3DGC_OK; + } + long ReadConfig(unsigned long & iterator) const + { + assert(iterator < m_configs.GetSize()); + return m_configs[iterator++]; + } + O3DGCErrorCode PushOperation(long op) + { + m_operations.PushBack(op); + return O3DGC_OK; + } + long ReadOperation(unsigned long & iterator) const + { + assert(iterator < m_operations.GetSize()); + return m_operations[iterator++]; + } + O3DGCErrorCode PushIndex(long index) + { + m_indices.PushBack(index); + return O3DGC_OK; + } + long ReadIndex(unsigned long & iterator) const + { + assert(iterator < m_indices.GetSize()); + return m_indices[iterator++]; + } + O3DGCErrorCode PushTriangleIndex(long index) + { + m_trianglesOrder.PushBack(IntToUInt(index)); + return O3DGC_OK; + } + long ReadTriangleIndex(unsigned long & iterator) const + { + assert(iterator < m_trianglesOrder.GetSize()); + return UIntToInt(m_trianglesOrder[iterator++]); + } + O3DGCErrorCode Clear() + { + m_numTFANs.Clear(); + m_degrees.Clear(); + m_configs.Clear(); + m_operations.Clear(); + m_indices.Clear(); + return O3DGC_OK; + } + O3DGCErrorCode Save(BinaryStream & bstream, + bool encodeTrianglesOrder, + O3DGCStreamType streamType); + O3DGCErrorCode Load(const BinaryStream & bstream, + unsigned long & iterator, + bool decodeTrianglesOrder, + O3DGCStreamType streamType); + + private: + O3DGCErrorCode SaveBinAC(const Vector & data, + BinaryStream & bstream); + O3DGCErrorCode SaveUIntAC(const Vector & data, + const unsigned long M, + BinaryStream & bstream); + O3DGCErrorCode SaveIntACEGC(const Vector & data, + const unsigned long M, + BinaryStream & bstream); + + Vector m_numTFANs; + Vector m_degrees; + Vector m_configs; + Vector m_operations; + Vector m_indices; + Vector m_trianglesOrder; + unsigned char * m_bufferAC; + unsigned long m_sizeBufferAC; + O3DGCStreamType m_streamType; + }; + + //! + class TriangleFans + { + public: + //! Constructor. + TriangleFans(long sizeTFAN = O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER, + long verticesSize = O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER) + { + assert(sizeTFAN > 0); + assert(verticesSize > 0); + m_numTFANs = 0; + m_numVertices = 0; + m_verticesAllocatedSize = verticesSize; + m_sizeTFANAllocatedSize = sizeTFAN; + m_sizeTFAN = new long [m_sizeTFANAllocatedSize]; + m_vertices = new long [m_verticesAllocatedSize]; + }; + //! Destructor. + ~TriangleFans(void) + { + delete [] m_vertices; + delete [] m_sizeTFAN; + }; + + O3DGCErrorCode Allocate(long sizeTFAN, long verticesSize) + { + assert(sizeTFAN > 0); + assert(verticesSize > 0); + m_numTFANs = 0; + m_numVertices = 0; + if (m_verticesAllocatedSize < verticesSize) + { + delete [] m_vertices; + m_verticesAllocatedSize = verticesSize; + m_vertices = new long [m_verticesAllocatedSize]; + } + if (m_sizeTFANAllocatedSize < sizeTFAN) + { + delete [] m_sizeTFAN; + m_sizeTFANAllocatedSize = sizeTFAN; + m_sizeTFAN = new long [m_sizeTFANAllocatedSize]; + } + return O3DGC_OK; + }; + O3DGCErrorCode Clear() + { + m_numTFANs = 0; + m_numVertices = 0; + return O3DGC_OK; + } + O3DGCErrorCode AddVertex(long vertex) + { + assert(m_numTFANs >= 0); + assert(m_numTFANs < m_sizeTFANAllocatedSize); + assert(m_numVertices >= 0); + ++m_numVertices; + if (m_numVertices == m_verticesAllocatedSize) + { + m_verticesAllocatedSize *= 2; + long * tmp = m_vertices; + m_vertices = new long [m_verticesAllocatedSize]; + memcpy(m_vertices, tmp, sizeof(long) * m_numVertices); + delete [] tmp; + } + m_vertices[m_numVertices-1] = vertex; + ++m_sizeTFAN[m_numTFANs-1]; + return O3DGC_OK; + } + O3DGCErrorCode AddTFAN() + { + assert(m_numTFANs >= 0); + ++m_numTFANs; + if (m_numTFANs == m_sizeTFANAllocatedSize) + { + m_sizeTFANAllocatedSize *= 2; + long * tmp = m_sizeTFAN; + m_sizeTFAN = new long [m_sizeTFANAllocatedSize]; + memcpy(m_sizeTFAN, tmp, sizeof(long) * m_numTFANs); + delete [] tmp; + } + m_sizeTFAN[m_numTFANs-1] = (m_numTFANs > 1) ? m_sizeTFAN[m_numTFANs-2] : 0; + return O3DGC_OK; + } + long Begin(long tfan) const + { + assert(tfan < m_numTFANs); + assert(tfan >= 0); + return (tfan>0)?m_sizeTFAN[tfan-1]:0; + } + long End(long tfan) const + { + assert(tfan < m_numTFANs); + assert(tfan >= 0); + return m_sizeTFAN[tfan]; + } + long GetVertex(long vertex) const + { + assert(vertex < m_numVertices); + assert(vertex >= 0); + return m_vertices[vertex]; + } + long GetTFANSize(long tfan) const + { + return End(tfan) - Begin(tfan); + } + long GetNumTFANs() const + { + return m_numTFANs; + } + long GetNumVertices() const + { + return m_numVertices; + } + + private: + long m_verticesAllocatedSize; + long m_sizeTFANAllocatedSize; + long m_numTFANs; + long m_numVertices; + long * m_vertices; + long * m_sizeTFAN; + + }; +} +#endif // O3DGC_TRIANGLE_FANS_H + diff --git a/contrib/Open3DGC/o3dgcTriangleListDecoder.h b/contrib/Open3DGC/o3dgcTriangleListDecoder.h new file mode 100644 index 000000000..65df526d1 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTriangleListDecoder.h @@ -0,0 +1,133 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_TRIANGLE_LIST_DECODER_H +#define O3DGC_TRIANGLE_LIST_DECODER_H + +#include "o3dgcCommon.h" +#include "o3dgcTriangleFans.h" +#include "o3dgcBinaryStream.h" +#include "o3dgcAdjacencyInfo.h" + +namespace o3dgc +{ + + //! + template + class TriangleListDecoder + { + public: + //! Constructor. + TriangleListDecoder(void) + { + m_vertexCount = 0; + m_triangleCount = 0; + m_numTriangles = 0; + m_numVertices = 0; + m_triangles = 0; + m_numConqueredTriangles = 0; + m_numVisitedVertices = 0; + m_visitedVertices = 0; + m_visitedVerticesValence = 0; + m_maxNumVertices = 0; + m_maxNumTriangles = 0; + m_itNumTFans = 0; + m_itDegree = 0; + m_itConfig = 0; + m_itOperation = 0; + m_itIndex = 0; + m_tempTriangles = 0; + m_tempTrianglesSize = 0; + m_decodeTrianglesOrder = false; + m_decodeVerticesOrder = false; + }; + //! Destructor. + ~TriangleListDecoder(void) + { + delete [] m_tempTriangles; + }; + + O3DGCStreamType GetStreamType() const { return m_streamType; } + bool GetReorderTriangles() const { return m_decodeTrianglesOrder; } + bool GetReorderVertices() const { return m_decodeVerticesOrder; } + void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } + const AdjacencyInfo & GetVertexToTriangle() const { return m_vertexToTriangle;} + O3DGCErrorCode Decode(T * const triangles, + const long numTriangles, + const long numVertices, + const BinaryStream & bstream, + unsigned long & iterator) + { + unsigned char compressionMask = bstream.ReadUChar(iterator, m_streamType); + m_decodeTrianglesOrder = ( (compressionMask&2) != 0); + m_decodeVerticesOrder = ( (compressionMask&1) != 0); + if (m_decodeVerticesOrder) // vertices reordering not supported + { + return O3DGC_ERROR_NON_SUPPORTED_FEATURE; + } + unsigned long maxSizeV2T = bstream.ReadUInt32(iterator, m_streamType); + Init(triangles, numTriangles, numVertices, maxSizeV2T); + m_ctfans.Load(bstream, iterator, m_decodeTrianglesOrder, m_streamType); + Decompress(); + return O3DGC_OK; + } + O3DGCErrorCode Reorder(); + + private: + O3DGCErrorCode Init(T * const triangles, + const long numTriangles, + const long numVertices, + const long maxSizeV2T); + O3DGCErrorCode Decompress(); + O3DGCErrorCode CompueLocalConnectivityInfo(const long focusVertex); + O3DGCErrorCode DecompressTFAN(const long focusVertex); + + unsigned long m_itNumTFans; + unsigned long m_itDegree; + unsigned long m_itConfig; + unsigned long m_itOperation; + unsigned long m_itIndex; + long m_maxNumVertices; + long m_maxNumTriangles; + long m_numTriangles; + long m_numVertices; + long m_tempTrianglesSize; + T * m_triangles; + T * m_tempTriangles; + long m_vertexCount; + long m_triangleCount; + long m_numConqueredTriangles; + long m_numVisitedVertices; + long * m_visitedVertices; + long * m_visitedVerticesValence; + AdjacencyInfo m_vertexToTriangle; + CompressedTriangleFans m_ctfans; + TriangleFans m_tfans; + O3DGCStreamType m_streamType; + bool m_decodeTrianglesOrder; + bool m_decodeVerticesOrder; + }; +} +#include "o3dgcTriangleListDecoder.inl" // template implementation +#endif // O3DGC_TRIANGLE_LIST_DECODER_H + diff --git a/contrib/Open3DGC/o3dgcTriangleListDecoder.inl b/contrib/Open3DGC/o3dgcTriangleListDecoder.inl new file mode 100644 index 000000000..dd3af4aa7 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTriangleListDecoder.inl @@ -0,0 +1,364 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_TRIANGLE_LIST_DECODER_INL +#define O3DGC_TRIANGLE_LIST_DECODER_INL + +namespace o3dgc +{ + template + O3DGCErrorCode TriangleListDecoder::Init(T * const triangles, + const long numTriangles, + const long numVertices, + const long maxSizeV2T) + { + assert(numVertices > 0); + assert(numTriangles > 0); + m_numTriangles = numTriangles; + m_numVertices = numVertices; + m_triangles = triangles; + m_vertexCount = 0; + m_triangleCount = 0; + m_itNumTFans = 0; + m_itDegree = 0; + m_itConfig = 0; + m_itOperation = 0; + m_itIndex = 0; + if (m_numVertices > m_maxNumVertices) + { + m_maxNumVertices = m_numVertices; + delete [] m_visitedVerticesValence; + delete [] m_visitedVertices; + m_visitedVerticesValence = new long [m_numVertices]; + m_visitedVertices = new long [m_numVertices]; + } + + if (m_decodeTrianglesOrder && m_tempTrianglesSize < m_numTriangles) + { + delete [] m_tempTriangles; + m_tempTrianglesSize = m_numTriangles; + m_tempTriangles = new T [3*m_tempTrianglesSize]; + } + + m_ctfans.SetStreamType(m_streamType); + m_ctfans.Allocate(m_numVertices, m_numTriangles); + m_tfans.Allocate(2 * m_numVertices, 8 * m_numVertices); + + // compute vertex-to-triangle adjacency information + m_vertexToTriangle.AllocateNumNeighborsArray(numVertices); + long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer(); + for(long i = 0; i < numVertices; ++i) + { + numNeighbors[i] = maxSizeV2T; + } + m_vertexToTriangle.AllocateNeighborsArray(); + m_vertexToTriangle.ClearNeighborsArray(); + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListDecoder::Decompress() + { + for(long focusVertex = 0; focusVertex < m_numVertices; ++focusVertex) + { + if (focusVertex == m_vertexCount) + { + m_vertexCount++; // insert focusVertex + } + CompueLocalConnectivityInfo(focusVertex); + DecompressTFAN(focusVertex); + } + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListDecoder::Reorder() + { + if (m_decodeTrianglesOrder) + { + unsigned long itTriangleIndex = 0; + long prevTriangleIndex = 0; + long t; + memcpy(m_tempTriangles, m_triangles, m_numTriangles * 3 * sizeof(T)); + for(long i = 0; i < m_numTriangles; ++i) + { + t = m_ctfans.ReadTriangleIndex(itTriangleIndex) + prevTriangleIndex; + assert( t >= 0 && t < m_numTriangles); + memcpy(m_triangles + 3 * t, m_tempTriangles + 3 * i, sizeof(T) * 3); + prevTriangleIndex = t + 1; + } + } + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListDecoder::CompueLocalConnectivityInfo(const long focusVertex) + { + long t = 0; + long p, v; + m_numConqueredTriangles = 0; + m_numVisitedVertices = 0; + for(long i = m_vertexToTriangle.Begin(focusVertex); (t >= 0) && (i < m_vertexToTriangle.End(focusVertex)); ++i) + { + t = m_vertexToTriangle.GetNeighbor(i); + if ( t >= 0) + { + ++m_numConqueredTriangles; + p = 3*t; + // extract visited vertices + for(long k = 0; k < 3; ++k) + { + v = m_triangles[p+k]; + if (v > focusVertex) // vertices are insertices by increasing traversal order + { + bool foundOrInserted = false; + for (long j = 0; j < m_numVisitedVertices; ++j) + { + if (v == m_visitedVertices[j]) + { + m_visitedVerticesValence[j]++; + foundOrInserted = true; + break; + } + else if (v < m_visitedVertices[j]) + { + ++m_numVisitedVertices; + for (long h = m_numVisitedVertices-1; h > j; --h) + { + m_visitedVertices[h] = m_visitedVertices[h-1]; + m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1]; + } + m_visitedVertices[j] = v; + m_visitedVerticesValence[j] = 1; + foundOrInserted = true; + break; + } + } + if (!foundOrInserted) + { + m_visitedVertices[m_numVisitedVertices] = v; + m_visitedVerticesValence[m_numVisitedVertices] = 1; + m_numVisitedVertices++; + } + } + } + } + } + // re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex) + // in order to avoid config. 9 + if (m_numVisitedVertices > 2) + { + long y; + for(long x = 1; x < m_numVisitedVertices; ++x) + { + + if (m_visitedVerticesValence[x] == 1) + { + y = x; + while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) ) + { + swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]); + swap(m_visitedVertices[y], m_visitedVertices[y-1]); + --y; + } + } + } + } + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListDecoder::DecompressTFAN(const long focusVertex) + { + long ntfans; + long degree, config; + long op; + long index; + long k0, k1; + long b, c, t; + + ntfans = m_ctfans.ReadNumTFans(m_itNumTFans); + if (ntfans > 0) + { + for(long f = 0; f != ntfans; f++) + { + m_tfans.AddTFAN(); + degree = m_ctfans.ReadDegree(m_itDegree) +2 - m_numConqueredTriangles; + config = m_ctfans.ReadConfig(m_itConfig); + k0 = m_tfans.GetNumVertices(); + m_tfans.AddVertex(focusVertex); + switch(config) + { + case 0:// ops: 1000001 vertices: -1 -2 + m_tfans.AddVertex(m_visitedVertices[0]); + for(long u = 1; u < degree-1; u++) + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + m_tfans.AddVertex(m_visitedVertices[1]); + break; + case 1: // ops: 1xxxxxx1 vertices: -1 x x x x x -2 + m_tfans.AddVertex(m_visitedVertices[0]); + for(long u = 1; u < degree-1; u++) + { + op = m_ctfans.ReadOperation(m_itOperation); + if (op == 1) + { + index = m_ctfans.ReadIndex(m_itIndex); + if ( index < 0) + { + m_tfans.AddVertex(m_visitedVertices[-index-1]); + } + else + { + m_tfans.AddVertex(index + focusVertex); + } + } + else + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + } + m_tfans.AddVertex(m_visitedVertices[1]); + break; + case 2: // ops: 00000001 vertices: -1 + for(long u = 0; u < degree-1; u++) + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + m_tfans.AddVertex(m_visitedVertices[0]); + break; + case 3: // ops: 00000001 vertices: -2 + for(long u=0; u < degree-1; u++) + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + m_tfans.AddVertex(m_visitedVertices[1]); + break; + case 4: // ops: 10000000 vertices: -1 + m_tfans.AddVertex(m_visitedVertices[0]); + for(long u = 1; u < degree; u++) + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + break; + case 5: // ops: 10000000 vertices: -2 + m_tfans.AddVertex(m_visitedVertices[1]); + for(long u = 1; u < degree; u++) + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + break; + case 6:// ops: 00000000 vertices: + for(long u = 0; u < degree; u++) + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + break; + case 7: // ops: 1000001 vertices: -2 -1 + m_tfans.AddVertex(m_visitedVertices[1]); + for(long u = 1; u < degree-1; u++) + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + m_tfans.AddVertex(m_visitedVertices[0]); + break; + case 8: // ops: 1xxxxxx1 vertices: -2 x x x x x -1 + m_tfans.AddVertex(m_visitedVertices[1]); + for(long u = 1; u < degree-1; u++) + { + op = m_ctfans.ReadOperation(m_itOperation); + if (op == 1) + { + index = m_ctfans.ReadIndex(m_itIndex); + if ( index < 0) + { + m_tfans.AddVertex(m_visitedVertices[-index-1]); + } + else + { + m_tfans.AddVertex(index + focusVertex); + } + } + else + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + } + m_tfans.AddVertex(m_visitedVertices[0]); + break; + case 9: // general case + for(long u = 0; u < degree; u++) + { + op = m_ctfans.ReadOperation(m_itOperation); + if (op == 1) + { + index = m_ctfans.ReadIndex(m_itIndex); + if ( index < 0) + { + m_tfans.AddVertex(m_visitedVertices[-index-1]); + } + else + { + m_tfans.AddVertex(index + focusVertex); + } + } + else + { + m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; + m_tfans.AddVertex(m_vertexCount++); + } + } + break; + + } + //logger.write_2_log("\t degree=%i \t cas = %i\n", degree, cas); + k1 = m_tfans.GetNumVertices(); + b = m_tfans.GetVertex(k0+1); + for (long k = k0+2; k < k1; k++) + { + c = m_tfans.GetVertex(k); + t = m_triangleCount*3; + + m_triangles[t++] = (T) focusVertex; + m_triangles[t++] = (T) b; + m_triangles[t ] = (T) c; + + m_vertexToTriangle.AddNeighbor(focusVertex, m_triangleCount); + m_vertexToTriangle.AddNeighbor(b , m_triangleCount); + m_vertexToTriangle.AddNeighbor(c , m_triangleCount); + b=c; + m_triangleCount++; + } + } + } + return O3DGC_OK; + } +} +#endif //O3DGC_TRIANGLE_LIST_DECODER_INL + diff --git a/contrib/Open3DGC/o3dgcTriangleListEncoder.h b/contrib/Open3DGC/o3dgcTriangleListEncoder.h new file mode 100644 index 000000000..cf790ecc3 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTriangleListEncoder.h @@ -0,0 +1,101 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#pragma once +#ifndef O3DGC_TRIANGLE_LIST_ENCODER_H +#define O3DGC_TRIANGLE_LIST_ENCODER_H + +#include "o3dgcCommon.h" +#include "o3dgcAdjacencyInfo.h" +#include "o3dgcBinaryStream.h" +#include "o3dgcFIFO.h" +#include "o3dgcTriangleFans.h" + +namespace o3dgc +{ + //! + template + class TriangleListEncoder + { + public: + //! Constructor. + TriangleListEncoder(void); + //! Destructor. + ~TriangleListEncoder(void); + //! + O3DGCErrorCode Encode(const T * const triangles, + const unsigned long * const indexBufferIDs, + const long numTriangles, + const long numVertices, + BinaryStream & bstream); + O3DGCStreamType GetStreamType() const { return m_streamType; } + void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } + const long * const GetInvVMap() const { return m_invVMap;} + const long * const GetInvTMap() const { return m_invTMap;} + const long * const GetVMap() const { return m_vmap;} + const long * const GetTMap() const { return m_tmap;} + const AdjacencyInfo & GetVertexToTriangle() const { return m_vertexToTriangle;} + + private: + O3DGCErrorCode Init(const T * const triangles, + long numTriangles, + long numVertices); + O3DGCErrorCode CompueLocalConnectivityInfo(const long focusVertex); + O3DGCErrorCode ProcessVertex( long focusVertex); + O3DGCErrorCode ComputeTFANDecomposition(const long focusVertex); + O3DGCErrorCode CompressTFAN(const long focusVertex); + + long m_vertexCount; + long m_triangleCount; + long m_maxNumVertices; + long m_maxNumTriangles; + long m_numNonConqueredTriangles; + long m_numConqueredTriangles; + long m_numVisitedVertices; + long m_numTriangles; + long m_numVertices; + long m_maxSizeVertexToTriangle; + T const * m_triangles; + long * m_vtags; + long * m_ttags; + long * m_vmap; + long * m_invVMap; + long * m_tmap; + long * m_invTMap; + long * m_count; + long * m_nonConqueredTriangles; + long * m_nonConqueredEdges; + long * m_visitedVertices; + long * m_visitedVerticesValence; + FIFO m_vfifo; + AdjacencyInfo m_vertexToTriangle; + AdjacencyInfo m_triangleToTriangle; + AdjacencyInfo m_triangleToTriangleInv; + TriangleFans m_tfans; + CompressedTriangleFans m_ctfans; + O3DGCStreamType m_streamType; + }; +} +#include "o3dgcTriangleListEncoder.inl" // template implementation +#endif // O3DGC_TRIANGLE_LIST_ENCODER_H + diff --git a/contrib/Open3DGC/o3dgcTriangleListEncoder.inl b/contrib/Open3DGC/o3dgcTriangleListEncoder.inl new file mode 100644 index 000000000..d499f6dc9 --- /dev/null +++ b/contrib/Open3DGC/o3dgcTriangleListEncoder.inl @@ -0,0 +1,719 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_TRIANGLE_LIST_ENCODER_INL +#define O3DGC_TRIANGLE_LIST_ENCODER_INL + +namespace o3dgc +{ + // extract opposite edge + template + inline void CompueOppositeEdge(const long focusVertex, + const T * triangle, + long & a, long & b) + { + if ((long) triangle[0] == focusVertex) + { + a = triangle[1]; + b = triangle[2]; + } + else if ((long) triangle[1] == focusVertex) + { + a = triangle[2]; + b = triangle[0]; + } + else + { + a = triangle[0]; + b = triangle[1]; + } + } + inline bool IsCase0(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 1000001 vertices: -1 -2 + if ((numIndices != 2) || (degree < 2)) { + return false; + } + if ((indices[0] != -1) ||(indices[1] != -2) || + (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; + for (long u = 1; u < degree-1; u++) { + if (ops[u] != 0) return false; + } + return true; + } + inline bool IsCase1(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 1xxxxxx1 indices: -1 x x x x x -2 + if ((degree < 2) || (numIndices < 1)) + { + return false; + } + if ((indices[0] != -1) ||(indices[numIndices-1] != -2) || + (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; + return true; + } + inline bool IsCase2(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 00000001 indices: -1 + if ((degree < 2) || (numIndices!= 1)) + { + return false; + } + if ((indices[0] != -1) || (ops[degree-1] != 1) ) return false; + for (long u = 0; u < degree-1; u++) { + if (ops[u] != 0) return false; + } + return true; + } + inline bool IsCase3(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 00000001 indices: -2 + if ((degree < 2) || (numIndices!= 1)) + { + return false; + } + if ((indices[0] != -2) || (ops[degree-1] != 1) ) return false; + for (long u = 0; u < degree-1; u++) { + if (ops[u] != 0) return false; + } + return true; + } + inline bool IsCase4(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 10000000 indices: -1 + if ((degree < 2) || (numIndices!= 1)) + { + return false; + } + if ((indices[0] != -1) || (ops[0] != 1) ) return false; + for (long u = 1; u < degree; u++) + { + if (ops[u] != 0) return false; + } + return true; + } + inline bool IsCase5(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 10000000 indices: -2 + if ((degree < 2) || (numIndices!= 1)) + { + return false; + } + if ((indices[0] != -2) || (ops[0] != 1) ) return false; + for (long u = 1; u < degree; u++) { + if (ops[u] != 0) return false; + } + return true; + } + inline bool IsCase6(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 0000000 indices: + if (numIndices!= 0) + { + return false; + } + for (long u = 0; u < degree; u++) + { + if (ops[u] != 0) return false; + } + return true; + } + inline bool IsCase7(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 1000001 indices: -2 -1 + if ((numIndices!= 2) || (degree < 2)) + { + return false; + } + if ((indices[0] != -2) ||(indices[1] != -1) || + (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; + for (long u = 1; u < degree-1; u++) + { + if (ops[u] != 0) return false; + } + return true; + } + inline bool IsCase8(long degree, long numIndices, const long * const ops, const long * const indices) + { + // ops: 1xxxxxx1 indices: -1 x x x x x -2 + if ((degree < 2) || (numIndices < 1)) + { + return false; + } + if ((indices[0] != -2) ||(indices[numIndices-1] != -1) || + (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; + return true; + } + template + TriangleListEncoder::TriangleListEncoder(void) + { + m_vtags = 0; + m_ttags = 0; + m_tmap = 0; + m_vmap = 0; + m_count = 0; + m_invVMap = 0; + m_invTMap = 0; + m_nonConqueredTriangles = 0; + m_nonConqueredEdges = 0; + m_visitedVertices = 0; + m_visitedVerticesValence = 0; + m_vertexCount = 0; + m_triangleCount = 0; + m_maxNumVertices = 0; + m_maxNumTriangles = 0; + m_numTriangles = 0; + m_numVertices = 0; + m_triangles = 0; + m_maxSizeVertexToTriangle = 0; + m_streamType = O3DGC_STREAM_TYPE_UNKOWN; + } + template + TriangleListEncoder::~TriangleListEncoder() + { + delete [] m_vtags; + delete [] m_vmap; + delete [] m_invVMap; + delete [] m_invTMap; + delete [] m_visitedVerticesValence; + delete [] m_visitedVertices; + delete [] m_ttags; + delete [] m_tmap; + delete [] m_count; + delete [] m_nonConqueredTriangles; + delete [] m_nonConqueredEdges; + } + template + O3DGCErrorCode TriangleListEncoder::Init(const T * const triangles, + long numTriangles, + long numVertices) + { + assert(numVertices > 0); + assert(numTriangles > 0); + + m_numTriangles = numTriangles; + m_numVertices = numVertices; + m_triangles = triangles; + m_vertexCount = 0; + m_triangleCount = 0; + + if (m_numVertices > m_maxNumVertices) + { + delete [] m_vtags; + delete [] m_vmap; + delete [] m_invVMap; + delete [] m_visitedVerticesValence; + delete [] m_visitedVertices; + m_maxNumVertices = m_numVertices; + m_vtags = new long [m_numVertices]; + m_vmap = new long [m_numVertices]; + m_invVMap = new long [m_numVertices]; + m_visitedVerticesValence = new long [m_numVertices]; + m_visitedVertices = new long [m_numVertices]; + } + + if (m_numTriangles > m_maxNumTriangles) + { + delete [] m_ttags; + delete [] m_tmap; + delete [] m_invTMap; + delete [] m_nonConqueredTriangles; + delete [] m_nonConqueredEdges; + delete [] m_count; + m_maxNumTriangles = m_numTriangles; + m_ttags = new long [m_numTriangles]; + m_tmap = new long [m_numTriangles]; + m_invTMap = new long [m_numTriangles]; + m_count = new long [m_numTriangles+1]; + m_nonConqueredTriangles = new long [m_numTriangles]; + m_nonConqueredEdges = new long [2*m_numTriangles]; + } + + memset(m_vtags , 0x00, sizeof(long) * m_numVertices ); + memset(m_vmap , 0xFF, sizeof(long) * m_numVertices ); + memset(m_invVMap, 0xFF, sizeof(long) * m_numVertices ); + memset(m_ttags , 0x00, sizeof(long) * m_numTriangles); + memset(m_tmap , 0xFF, sizeof(long) * m_numTriangles); + memset(m_invTMap, 0xFF, sizeof(long) * m_numTriangles); + memset(m_count , 0x00, sizeof(long) * (m_numTriangles+1)); + + m_vfifo.Allocate(m_numVertices); + m_ctfans.SetStreamType(m_streamType); + m_ctfans.Allocate(m_numVertices, m_numTriangles); + + // compute vertex-to-triangle adjacency information + m_vertexToTriangle.AllocateNumNeighborsArray(numVertices); + m_vertexToTriangle.ClearNumNeighborsArray(); + long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer(); + for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3) + { + ++numNeighbors[ triangles[t ] ]; + ++numNeighbors[ triangles[t+1] ]; + ++numNeighbors[ triangles[t+2] ]; + } + m_maxSizeVertexToTriangle = 0; + for(long i = 0; i < numVertices; ++i) + { + if (m_maxSizeVertexToTriangle < numNeighbors[i]) + { + m_maxSizeVertexToTriangle = numNeighbors[i]; + } + } + m_vertexToTriangle.AllocateNeighborsArray(); + m_vertexToTriangle.ClearNeighborsArray(); + for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3) + { + m_vertexToTriangle.AddNeighbor(triangles[t ], i); + m_vertexToTriangle.AddNeighbor(triangles[t+1], i); + m_vertexToTriangle.AddNeighbor(triangles[t+2], i); + } + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListEncoder::Encode(const T * const triangles, + const unsigned long * const indexBufferIDs, + const long numTriangles, + const long numVertices, + BinaryStream & bstream) + { + assert(numVertices > 0); + assert(numTriangles > 0); + + Init(triangles, numTriangles, numVertices); + unsigned char mask = 0; + bool encodeTrianglesOrder = (indexBufferIDs != 0); + + + if (encodeTrianglesOrder) + { + long numBufferIDs = 0; + for (long t = 0; t < numTriangles; t++) + { + if (numBufferIDs <= (long) indexBufferIDs[t]) + { + ++numBufferIDs; + assert(numBufferIDs <= numTriangles); + } + ++m_count[indexBufferIDs[t]+1]; + } + for (long i = 2; i <= numBufferIDs; i++) + { + m_count[i] += m_count[i-1]; + } + mask += 2; // preserved triangles order + } + bstream.WriteUChar(mask, m_streamType); + bstream.WriteUInt32(m_maxSizeVertexToTriangle, m_streamType); + + long v0; + for (long v = 0; v < m_numVertices; v++) + { + if (!m_vtags[v]) + { + m_vfifo.PushBack(v); + m_vtags[v] = 1; + m_vmap[v] = m_vertexCount++; + m_invVMap[m_vmap[v]] = v; + while (m_vfifo.GetSize() > 0 ) + { + v0 = m_vfifo.PopFirst(); + ProcessVertex(v0); + } + } + } + if (encodeTrianglesOrder) + { + long t, prev = 0; + long pred; + for (long i = 0; i < numTriangles; ++i) + { + t = m_invTMap[i]; + m_tmap[t] = m_count[ indexBufferIDs[t] ]++; + pred = m_tmap[t] - prev; + m_ctfans.PushTriangleIndex(pred); + prev = m_tmap[t] + 1; + } + for (long t = 0; t < numTriangles; ++t) + { + m_invTMap[m_tmap[t]] = t; + } + } + m_ctfans.Save(bstream, encodeTrianglesOrder, m_streamType); + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListEncoder::CompueLocalConnectivityInfo(const long focusVertex) + { + long t, v, p; + m_numNonConqueredTriangles = 0; + m_numConqueredTriangles = 0; + m_numVisitedVertices = 0; + for(long i = m_vertexToTriangle.Begin(focusVertex); i < m_vertexToTriangle.End(focusVertex); ++i) + { + t = m_vertexToTriangle.GetNeighbor(i); + + if ( m_ttags[t] == 0) // non-processed triangle + { + m_nonConqueredTriangles[m_numNonConqueredTriangles] = t; + CompueOppositeEdge( focusVertex, + m_triangles + (3*t), + m_nonConqueredEdges[m_numNonConqueredTriangles*2], + m_nonConqueredEdges[m_numNonConqueredTriangles*2+1]); + ++m_numNonConqueredTriangles; + } + else // triangle already processed + { + m_numConqueredTriangles++; + p = 3*t; + // extract visited vertices + for(long k = 0; k < 3; ++k) + { + v = m_triangles[p+k]; + if (m_vmap[v] > m_vmap[focusVertex]) // vertices are insertices by increasing traversal order + { + bool foundOrInserted = false; + for (long j = 0; j < m_numVisitedVertices; ++j) + { + + if (m_vmap[v] == m_visitedVertices[j]) + { + m_visitedVerticesValence[j]++; + foundOrInserted = true; + break; + } + else if (m_vmap[v] < m_visitedVertices[j]) + { + ++m_numVisitedVertices; + for (long h = m_numVisitedVertices-1; h > j; --h) + { + m_visitedVertices[h] = m_visitedVertices[h-1]; + m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1]; + } + m_visitedVertices[j] = m_vmap[v]; + m_visitedVerticesValence[j] = 1; + foundOrInserted = true; + break; + } + } + if (!foundOrInserted) + { + m_visitedVertices[m_numVisitedVertices] = m_vmap[v]; + m_visitedVerticesValence[m_numVisitedVertices] = 1; + m_numVisitedVertices++; + } + } + } + } + } + // re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex) + // in order to avoid config. 9 + if (m_numVisitedVertices > 2) + { + long y; + for(long x = 1; x < m_numVisitedVertices; ++x) + { + + if (m_visitedVerticesValence[x] == 1) + { + y = x; + while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) ) + { + swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]); + swap(m_visitedVertices[y], m_visitedVertices[y-1]); + --y; + } + } + } + } + if (m_numNonConqueredTriangles > 0) + { + // compute triangle-to-triangle adjacency information + m_triangleToTriangle.AllocateNumNeighborsArray(m_numNonConqueredTriangles); + m_triangleToTriangle.ClearNumNeighborsArray(); + m_triangleToTriangleInv.AllocateNumNeighborsArray(m_numNonConqueredTriangles); + m_triangleToTriangleInv.ClearNumNeighborsArray(); + long * const numNeighbors = m_triangleToTriangle.GetNumNeighborsBuffer(); + long * const invNumNeighbors = m_triangleToTriangleInv.GetNumNeighborsBuffer(); + for(long i = 0; i < m_numNonConqueredTriangles; ++i) + { + for(long j = i+1; j < m_numNonConqueredTriangles; ++j) + { + if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j + { + ++numNeighbors[i]; + ++invNumNeighbors[j]; + } + if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j + { + ++numNeighbors[j]; + ++invNumNeighbors[i]; + } + } + } + m_triangleToTriangle.AllocateNeighborsArray(); + m_triangleToTriangle.ClearNeighborsArray(); + m_triangleToTriangleInv.AllocateNeighborsArray(); + m_triangleToTriangleInv.ClearNeighborsArray(); + for(long i = 0; i < m_numNonConqueredTriangles; ++i) + { + for(long j = 1; j < m_numNonConqueredTriangles; ++j) + { + if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j + { + m_triangleToTriangle.AddNeighbor(i, j); + m_triangleToTriangleInv.AddNeighbor(j, i); + } + if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j + { + m_triangleToTriangle.AddNeighbor(j, i); + m_triangleToTriangleInv.AddNeighbor(i, j); + } + } + } + } + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListEncoder::ComputeTFANDecomposition(const long focusVertex) + { + long processedTriangles = 0; + long minNumInputEdges; + long numInputEdges; + long indexSeedTriangle; + long seedTriangle; + long currentIndex; + long currentTriangle; + long i0, i1, index; + + m_tfans.Clear(); + while (processedTriangles != m_numNonConqueredTriangles) + { + // find non processed triangle with lowest number of inputs + minNumInputEdges = m_numTriangles; + indexSeedTriangle = -1; + for(long i = 0; i < m_numNonConqueredTriangles; ++i) + { + numInputEdges = m_triangleToTriangleInv.GetNumNeighbors(i); + if ( !m_ttags[m_nonConqueredTriangles[i]] && + numInputEdges < minNumInputEdges ) + { + minNumInputEdges = numInputEdges; + indexSeedTriangle = i; + if (minNumInputEdges == 0) // found boundary triangle + { + break; + } + } + } + assert(indexSeedTriangle >= 0); + seedTriangle = m_nonConqueredTriangles[indexSeedTriangle]; + m_tfans.AddTFAN(); + m_tfans.AddVertex( focusVertex ); + m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2] ); + m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2 + 1] ); + m_ttags[ seedTriangle ] = 1; // mark triangle as processed + m_tmap[seedTriangle] = m_triangleCount++; + m_invTMap[m_tmap[seedTriangle]] = seedTriangle; + ++processedTriangles; + currentIndex = indexSeedTriangle; + currentTriangle = seedTriangle; + do + { + // find next triangle + i0 = m_triangleToTriangle.Begin(currentIndex); + i1 = m_triangleToTriangle.End(currentIndex); + currentIndex = -1; + for(long i = i0; i < i1; ++i) + { + index = m_triangleToTriangle.GetNeighbor(i); + currentTriangle = m_nonConqueredTriangles[index]; + if ( !m_ttags[currentTriangle] ) + { + currentIndex = index; + m_tfans.AddVertex( m_nonConqueredEdges[currentIndex*2+1] ); + m_ttags[currentTriangle] = 1; // mark triangle as processed + m_tmap [currentTriangle] = m_triangleCount++; + m_invTMap[m_tmap [currentTriangle]] = currentTriangle; + ++processedTriangles; + break; + } + } + } while (currentIndex != -1); + } + + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListEncoder::CompressTFAN(const long focusVertex) + { + m_ctfans.PushNumTFans(m_tfans.GetNumTFANs()); + + const long ntfans = m_tfans.GetNumTFANs(); + long degree; + long k0, k1; + long v0; + long ops[O3DGC_MAX_TFAN_SIZE]; + long indices[O3DGC_MAX_TFAN_SIZE]; + + long numOps; + long numIndices; + long pos; + long found; + + if (m_tfans.GetNumTFANs() > 0) + { + for(long f = 0; f != ntfans; f++) + { + degree = m_tfans.GetTFANSize(f) - 1; + m_ctfans.PushDegree(degree-2+ m_numConqueredTriangles); + numOps = 0; + numIndices = 0; + k0 = 1 + m_tfans.Begin(f); + k1 = m_tfans.End(f); + for(long k = k0; k < k1; k++) + { + v0 = m_tfans.GetVertex(k); + if (m_vtags[v0] == 0) + { + ops[numOps++] = 0; + m_vtags[v0] = 1; + m_vmap[v0] = m_vertexCount++; + m_invVMap[m_vmap[v0]] = v0; + m_vfifo.PushBack(v0); + m_visitedVertices[m_numVisitedVertices++] = m_vmap[v0]; + } + else + { + ops[numOps++] = 1; + pos = 0; + found = 0; + for(long u=0; u < m_numVisitedVertices; ++u) + { + pos++; + if (m_visitedVertices[u] == m_vmap[v0]) + { + found = 1; + break; + } + } + if (found == 1) + { + indices[numIndices++] = -pos; + } + else + { + indices[numIndices++] = m_vmap[v0] - m_vmap[focusVertex]; + } + } + } + //----------------------------------------------- + if (IsCase0(degree, numIndices, ops, indices)) + { + // ops: 1000001 vertices: -1 -2 + m_ctfans.PushConfig(0); + } + else if (IsCase1(degree, numIndices, ops, indices)) + { + // ops: 1xxxxxx1 vertices: -1 x x x x x -2 + long u = 1; + for(u = 1; u < degree-1; u++) + { + m_ctfans.PushOperation(ops[u]); + } + for(u =1; u < numIndices-1; u++) + { + m_ctfans.PushIndex(indices[u]); + } + m_ctfans.PushConfig(1); + } + else if (IsCase2(degree, numIndices, ops, indices)) + { + // ops: 00000001 vertices: -1 + m_ctfans.PushConfig(2); + } + else if (IsCase3(degree, numIndices, ops, indices)) + { + // ops: 00000001 vertices: -2 + m_ctfans.PushConfig(3); + } + else if (IsCase4(degree, numIndices, ops, indices)) + { + // ops: 10000000 vertices: -1 + m_ctfans.PushConfig(4); + } + else if (IsCase5(degree, numIndices, ops, indices)) + { + // ops: 10000000 vertices: -2 + m_ctfans.PushConfig(5); + } + else if (IsCase6(degree, numIndices, ops, indices)) + { + // ops: 00000000 vertices: + m_ctfans.PushConfig(6); + } + else if (IsCase7(degree, numIndices, ops, indices)) + { + // ops: 1000001 vertices: -1 -2 + m_ctfans.PushConfig(7); + } + else if (IsCase8(degree, numIndices, ops, indices)) + { + // ops: 1xxxxxx1 vertices: -2 x x x x x -1 + long u = 1; + for(u =1; u < degree-1; u++) + { + m_ctfans.PushOperation(ops[u]); + } + for(u =1; u < numIndices-1; u++) + { + m_ctfans.PushIndex(indices[u]); + } + m_ctfans.PushConfig(8); + } + else + { + long u = 0; + for(u =0; u < degree; u++) + { + m_ctfans.PushOperation(ops[u]); + } + for(u =0; u < numIndices; u++) + { + m_ctfans.PushIndex(indices[u]); + } + m_ctfans.PushConfig(9); + } + } + } + return O3DGC_OK; + } + template + O3DGCErrorCode TriangleListEncoder::ProcessVertex(const long focusVertex) + { + CompueLocalConnectivityInfo(focusVertex); + ComputeTFANDecomposition(focusVertex); + CompressTFAN(focusVertex); + return O3DGC_OK; + } +} +#endif //O3DGC_TRIANGLE_LIST_ENCODER_INL diff --git a/contrib/Open3DGC/o3dgcVector.h b/contrib/Open3DGC/o3dgcVector.h new file mode 100644 index 000000000..e766e2b7f --- /dev/null +++ b/contrib/Open3DGC/o3dgcVector.h @@ -0,0 +1,184 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_VECTOR_H +#define O3DGC_VECTOR_H + +#include "o3dgcCommon.h" + +namespace o3dgc +{ + const unsigned long O3DGC_DEFAULT_VECTOR_SIZE = 32; + + //! + template < typename T > class Vector + { + public: + //! Constructor. + Vector() + { + m_allocated = 0; + m_size = 0; + m_buffer = 0; + }; + //! Destructor. + ~Vector(void) + { + delete [] m_buffer; + }; + T & operator[](unsigned long i) + { + return m_buffer[i]; + } + const T & operator[](unsigned long i) const + { + return m_buffer[i]; + } + void Allocate(unsigned long size) + { + if (size > m_allocated) + { + m_allocated = size; + T * tmp = new T [m_allocated]; + if (m_size > 0) + { + memcpy(tmp, m_buffer, m_size * sizeof(T) ); + delete [] m_buffer; + } + m_buffer = tmp; + } + }; + void PushBack(const T & value) + { + if (m_size == m_allocated) + { + m_allocated *= 2; + if (m_allocated < O3DGC_DEFAULT_VECTOR_SIZE) + { + m_allocated = O3DGC_DEFAULT_VECTOR_SIZE; + } + T * tmp = new T [m_allocated]; + if (m_size > 0) + { + memcpy(tmp, m_buffer, m_size * sizeof(T) ); + delete [] m_buffer; + } + m_buffer = tmp; + } + assert(m_size < m_allocated); + m_buffer[m_size++] = value; + } + const T * const GetBuffer() const { return m_buffer;}; + T * const GetBuffer() { return m_buffer;}; + unsigned long GetSize() const { return m_size;}; + void SetSize(unsigned long size) + { + assert(size <= m_allocated); + m_size = size; + }; + unsigned long GetAllocatedSize() const { return m_allocated;}; + void Clear(){ m_size = 0;}; + + private: + T * m_buffer; + unsigned long m_allocated; + unsigned long m_size; + }; + + + + + //! Vector dim 3. + template < typename T > class Vec3 + { + public: + T & operator[](unsigned long i) { return m_data[i];} + const T & operator[](unsigned long i) const { return m_data[i];} + T & X(); + T & Y(); + T & Z(); + const T & X() const; + const T & Y() const; + const T & Z() const; + double GetNorm() const; + void operator= (const Vec3 & rhs); + void operator+=(const Vec3 & rhs); + void operator-=(const Vec3 & rhs); + void operator-=(T a); + void operator+=(T a); + void operator/=(T a); + void operator*=(T a); + Vec3 operator^ (const Vec3 & rhs) const; + T operator* (const Vec3 & rhs) const; + Vec3 operator+ (const Vec3 & rhs) const; + Vec3 operator- (const Vec3 & rhs) const; + Vec3 operator- () const; + Vec3 operator* (T rhs) const; + Vec3 operator/ (T rhs) const; + Vec3(); + Vec3(T a); + Vec3(T x, T y, T z); + Vec3(const Vec3 & rhs); + ~Vec3(void); + + private: + T m_data[3]; + }; + //! Vector dim 2. + template < typename T > class Vec2 + { + public: + T & operator[](unsigned long i) { return m_data[i];} + const T & operator[](unsigned long i) const { return m_data[i];} + T & X(); + T & Y(); + const T & X() const; + const T & Y() const; + double GetNorm() const; + void operator= (const Vec2 & rhs); + void operator+=(const Vec2 & rhs); + void operator-=(const Vec2 & rhs); + void operator-=(T a); + void operator+=(T a); + void operator/=(T a); + void operator*=(T a); + T operator^ (const Vec2 & rhs) const; + T operator* (const Vec2 & rhs) const; + Vec2 operator+ (const Vec2 & rhs) const; + Vec2 operator- (const Vec2 & rhs) const; + Vec2 operator- () const; + Vec2 operator* (T rhs) const; + Vec2 operator/ (T rhs) const; + Vec2(); + Vec2(T a); + Vec2(T x, T y); + Vec2(const Vec2 & rhs); + ~Vec2(void); + + private: + T m_data[2]; + }; +} +#include "o3dgcVector.inl" // template implementation +#endif // O3DGC_VECTOR_H + diff --git a/contrib/Open3DGC/o3dgcVector.inl b/contrib/Open3DGC/o3dgcVector.inl new file mode 100644 index 000000000..5549b00ce --- /dev/null +++ b/contrib/Open3DGC/o3dgcVector.inl @@ -0,0 +1,317 @@ +/* +Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#ifndef O3DGC_VECTOR_INL +#define O3DGC_VECTOR_INL +namespace o3dgc +{ + template + inline Vec3 operator*(T lhs, const Vec3 & rhs) + { + return Vec3(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z()); + } + template + inline T & Vec3::X() + { + return m_data[0]; + } + template + inline T & Vec3::Y() + { + return m_data[1]; + } + template + inline T & Vec3::Z() + { + return m_data[2]; + } + template + inline const T & Vec3::X() const + { + return m_data[0]; + } + template + inline const T & Vec3::Y() const + { + return m_data[1]; + } + template + inline const T & Vec3::Z() const + { + return m_data[2]; + } + template + inline double Vec3::GetNorm() const + { + double a = (double) (m_data[0]); + double b = (double) (m_data[1]); + double c = (double) (m_data[2]); + return sqrt(a*a+b*b+c*c); + } + template + inline void Vec3::operator= (const Vec3 & rhs) + { + this->m_data[0] = rhs.m_data[0]; + this->m_data[1] = rhs.m_data[1]; + this->m_data[2] = rhs.m_data[2]; + } + template + inline void Vec3::operator+=(const Vec3 & rhs) + { + this->m_data[0] += rhs.m_data[0]; + this->m_data[1] += rhs.m_data[1]; + this->m_data[2] += rhs.m_data[2]; + } + template + inline void Vec3::operator-=(const Vec3 & rhs) + { + this->m_data[0] -= rhs.m_data[0]; + this->m_data[1] -= rhs.m_data[1]; + this->m_data[2] -= rhs.m_data[2]; + } + template + inline void Vec3::operator-=(T a) + { + this->m_data[0] -= a; + this->m_data[1] -= a; + this->m_data[2] -= a; + } + template + inline void Vec3::operator+=(T a) + { + this->m_data[0] += a; + this->m_data[1] += a; + this->m_data[2] += a; + } + template + inline void Vec3::operator/=(T a) + { + this->m_data[0] /= a; + this->m_data[1] /= a; + this->m_data[2] /= a; + } + template + inline void Vec3::operator*=(T a) + { + this->m_data[0] *= a; + this->m_data[1] *= a; + this->m_data[2] *= a; + } + template + inline Vec3 Vec3::operator^ (const Vec3 & rhs) const + { + return Vec3(m_data[1] * rhs.m_data[2] - m_data[2] * rhs.m_data[1], + m_data[2] * rhs.m_data[0] - m_data[0] * rhs.m_data[2], + m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]); + } + template + inline T Vec3::operator*(const Vec3 & rhs) const + { + return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1] + m_data[2] * rhs.m_data[2]); + } + template + inline Vec3 Vec3::operator+(const Vec3 & rhs) const + { + return Vec3(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]); + } + template + inline Vec3 Vec3::operator-(const Vec3 & rhs) const + { + return Vec3(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]); + } + template + inline Vec3 Vec3::operator-() const + { + return Vec3(-m_data[0],-m_data[1],-m_data[2]); + } + + template + inline Vec3 Vec3::operator*(T rhs) const + { + return Vec3(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]); + } + template + inline Vec3 Vec3::operator/ (T rhs) const + { + return Vec3(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs); + } + template + inline Vec3::Vec3(T a) + { + m_data[0] = m_data[1] = m_data[2] = a; + } + template + inline Vec3::Vec3(T x, T y, T z) + { + m_data[0] = x; + m_data[1] = y; + m_data[2] = z; + } + template + inline Vec3::Vec3(const Vec3 & rhs) + { + m_data[0] = rhs.m_data[0]; + m_data[1] = rhs.m_data[1]; + m_data[2] = rhs.m_data[2]; + } + template + inline Vec3::~Vec3(void){}; + + template + inline Vec3::Vec3() {} + + template + inline Vec2 operator*(T lhs, const Vec2 & rhs) + { + return Vec2(lhs * rhs.X(), lhs * rhs.Y()); + } + template + inline T & Vec2::X() + { + return m_data[0]; + } + template + inline T & Vec2::Y() + { + return m_data[1]; + } + template + inline const T & Vec2::X() const + { + return m_data[0]; + } + template + inline const T & Vec2::Y() const + { + return m_data[1]; + } + template + inline double Vec2::GetNorm() const + { + double a = (double) (m_data[0]); + double b = (double) (m_data[1]); + return sqrt(a*a+b*b); + } + template + inline void Vec2::operator= (const Vec2 & rhs) + { + this->m_data[0] = rhs.m_data[0]; + this->m_data[1] = rhs.m_data[1]; + } + template + inline void Vec2::operator+=(const Vec2 & rhs) + { + this->m_data[0] += rhs.m_data[0]; + this->m_data[1] += rhs.m_data[1]; + } + template + inline void Vec2::operator-=(const Vec2 & rhs) + { + this->m_data[0] -= rhs.m_data[0]; + this->m_data[1] -= rhs.m_data[1]; + } + template + inline void Vec2::operator-=(T a) + { + this->m_data[0] -= a; + this->m_data[1] -= a; + } + template + inline void Vec2::operator+=(T a) + { + this->m_data[0] += a; + this->m_data[1] += a; + } + template + inline void Vec2::operator/=(T a) + { + this->m_data[0] /= a; + this->m_data[1] /= a; + } + template + inline void Vec2::operator*=(T a) + { + this->m_data[0] *= a; + this->m_data[1] *= a; + } + template + inline T Vec2::operator^ (const Vec2 & rhs) const + { + return m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]; + } + template + inline T Vec2::operator*(const Vec2 & rhs) const + { + return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1]); + } + template + inline Vec2 Vec2::operator+(const Vec2 & rhs) const + { + return Vec2(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1]); + } + template + inline Vec2 Vec2::operator-(const Vec2 & rhs) const + { + return Vec2(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1]); + } + template + inline Vec2 Vec2::operator-() const + { + return Vec2(-m_data[0],-m_data[1]) ; + } + + template + inline Vec2 Vec2::operator*(T rhs) const + { + return Vec2(rhs * this->m_data[0], rhs * this->m_data[1]); + } + template + inline Vec2 Vec2::operator/ (T rhs) const + { + return Vec2(m_data[0] / rhs, m_data[1] / rhs); + } + template + inline Vec2::Vec2(T a) + { + m_data[0] = m_data[1] = a; + } + template + inline Vec2::Vec2(T x, T y) + { + m_data[0] = x; + m_data[1] = y; + } + template + inline Vec2::Vec2(const Vec2 & rhs) + { + m_data[0] = rhs.m_data[0]; + m_data[1] = rhs.m_data[1]; + } + template + inline Vec2::~Vec2(void){}; + + template + inline Vec2::Vec2() {} +} +#endif //O3DGC_VECTOR_INL + From 2e452205aa0ad1b7e110c25e956530e66c6a18c2 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Wed, 3 Aug 2016 03:40:53 +0300 Subject: [PATCH 02/32] [+] Building of Open3DGC codec. --- code/CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 35ecf5020..23456d13d 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -701,7 +701,18 @@ SET ( openddl_parser_SRCS ) SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS}) +SET ( open3dgc_SRCS + ../contrib/Open3DGC/o3dgcArithmeticCodec.cpp + ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp + ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp + ../contrib/Open3DGC/o3dgcTools.cpp + ../contrib/Open3DGC/o3dgcTriangleFans.cpp +) +SOURCE_GROUP( open3dgc FILES ${open3dgc_SRCS}) + + INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) +INCLUDE_DIRECTORIES( "../contrib" ) # VC2010 fixes if(MSVC10) @@ -747,6 +758,7 @@ SET( assimp_src ${Poly2Tri_SRCS} ${Clipper_SRCS} ${openddl_parser_SRCS} + ${open3dgc_SRCS} # Necessary to show the headers in the project when using the VC++ generator: ${PUBLIC_HEADERS} From 5e4fd5fa3cd51f6e4edbd068a665256d9938c89a Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Wed, 3 Aug 2016 03:46:04 +0300 Subject: [PATCH 03/32] [+] glTF. Support for import meshes with Open3DGC compression. --- code/glTFAsset.h | 24 +++++++- code/glTFAsset.inl | 150 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 165 insertions(+), 9 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 6d5ac1a71..c5c7d1349 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -477,6 +477,15 @@ namespace glTF bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); + /// \fn void ReplaceData(uint8_t* pBufferData_Offset, size_t pBufferData_Count, uint8_t pPrepend_Data, size_t pPrepend_Count) + /// Replace part of buffer data. For example: decoded/encoded data. + /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. + /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. + /// \param [in] pReplace_Data - pointer to array with new data for buffer. + /// \param [in] pReplace_Count - count of bytes in new data. + /// \return true - if successfully replaced, false if input arguments is out of range. + bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); + size_t AppendData(uint8_t* data, size_t length); void Grow(size_t amount); @@ -634,7 +643,18 @@ namespace glTF std::vector primitives; Mesh() {} - void Read(Value& obj, Asset& r); + + /// \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); + + /// \fn void Decode_O3DGC(Value& pJSON_Object_CompressedData, Asset& pAsset_Root) + /// Decode part of "bufferView" which encoded with Open3DGC algorythm. + /// \param [in] pJSON_Object_CompressedData - reference to JSON-object which is "compressedData" block. + /// \param [out] pAsset_Root - reference to root assed where data will be stored. + void Decode_O3DGC(Value& pJSON_Object_CompressedData, Asset& pAsset_Root); }; struct Node : public Object diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index d52c825c4..60af03ee3 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -40,6 +40,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StringUtils.h" +// Header files, Open3DGC.h, +#include + namespace glTF { namespace { @@ -324,6 +327,26 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO return true; } +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; +} + inline size_t Buffer::AppendData(uint8_t* data, size_t length) { size_t offset = this->byteLength; @@ -676,9 +699,35 @@ namespace { } } -inline void Mesh::Read(Value& obj, Asset& r) -{ - if (Value* primitives = FindArray(obj, "primitives")) { +inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) +{ + // + // Mesh extensions + // + // At first check for extensions. They can affect on interpretaion of mesh data. + Value* extensions = FindObject(pJSON_Object, "extensions"); + + if(extensions != nullptr) + { + // At first check if data of mesh is compressed. Because buffer data must be decoded before another get data from it. + // Only Open3DGC supported at now. + Value* o3dgc = FindObject(*extensions, "Open3DGC-compression"); + + if(o3dgc != nullptr) + { + // Search compressed data + Value* comp_data = FindObject(*o3dgc, "compressedData"); + + if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\"."); + + Decode_O3DGC(*comp_data, pAsset_Root); + }// if(o3dgc == nullptr) + }// if(extensions != nullptr) + + // + // Mesh primitives. + // + if (Value* primitives = FindArray(pJSON_Object, "primitives")) { this->primitives.resize(primitives->Size()); for (unsigned int i = 0; i < primitives->Size(); ++i) { Value& primitive = (*primitives)[i]; @@ -698,22 +747,109 @@ inline void Mesh::Read(Value& obj, Asset& r) if (GetAttribVector(prim, attr, vec, undPos)) { size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0; if ((*vec).size() <= idx) (*vec).resize(idx + 1); - (*vec)[idx] = r.accessors.Get(it->value.GetString()); + (*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString()); } } } if (Value* indices = FindString(primitive, "indices")) { - prim.indices = r.accessors.Get(indices->GetString()); + prim.indices = pAsset_Root.accessors.Get(indices->GetString()); } if (Value* material = FindString(primitive, "material")) { - prim.material = r.materials.Get(material->GetString()); + prim.material = pAsset_Root.materials.Get(material->GetString()); } } } } +inline void Mesh::Decode_O3DGC(Value& pJSON_Object_CompressedData, Asset& pAsset_Root) +{ +// Compressed data contain description of part of "bufferView" which is encoded. This part must be decoded and +// new data must replace old encoded part. In fact \"compressedData\" is similar to "accessor" structure. +const char* bufview_id; +uint32_t byte_offset, count, count_indices, count_vertices; +const char* mode_str; +const char* type_str; +ComponentType component_type; + + #define MESH_READ_COMPRESSEDDATA_MEMBER(pID, pOut) \ + if(!ReadMember(pJSON_Object_CompressedData, pID, pOut)) { throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pID + "\"."); } + + MESH_READ_COMPRESSEDDATA_MEMBER("bufferView", bufview_id); + MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", byte_offset); + MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type); + MESH_READ_COMPRESSEDDATA_MEMBER("count", count); + MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", count_indices); + MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", count_vertices); + MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str); + MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str); + + #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."); + if((strcmp(mode_str, "binary") != 0) && (strcmp(mode_str, "ascii") != 0)) + { + throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\"."); + } + + // Search for "bufferView" by ID. + Ref bufview = pAsset_Root.bufferViews.Get(bufview_id); + + // + // Decode data. Adapted piece of code from COLLADA2GLTF converter. + // + // void testDecode(shared_ptr mesh, BinaryStream &bstream) + o3dgc::SC3DMCDecoder decoder; + o3dgc::IndexedFaceSet ifs; + uint8_t* output_data; + size_t size_vertex, size_normal, size_texcoord, size_indices, output_data_size; + o3dgc::BinaryStream bstream; + + // Read data from buffer and place it in BinaryStream for decoder. + bstream.LoadFromBuffer(&bufview->buffer->GetPointer()[bufview->byteOffset + byte_offset], 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."); + + size_vertex = ifs.GetNCoord() * 3 * sizeof(float); + size_normal = ifs.GetNNormal() * 3 * sizeof(float); + size_texcoord = ifs.GetNFloatAttribute(0) * 2 * sizeof(float); + size_indices = ifs.GetNCoordIndex() * 3 * sizeof(unsigned short); + + output_data_size = size_vertex + size_normal + size_texcoord + size_indices; + output_data = new uint8_t[output_data_size]; + + float* uncompressed_vertices = (float* const)(output_data + size_indices);// size_indices => vertex offset + + ifs.SetCoordIndex((uint16_t* const)output_data); + ifs.SetCoord((float* const)uncompressed_vertices); + + if(ifs.GetNNormal() > 0) ifs.SetNormal((float* const)(output_data + size_indices + size_vertex)); + + if(ifs.GetNFloatAttribute(0)) ifs.SetFloatAttribute(0, (float* const)(output_data + size_indices + size_vertex + size_normal)); + + // Decode data + if(decoder.DecodePlayload(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC data."); + + // Set/extend buffer + bufview->buffer->ReplaceData(byte_offset, count, output_data, output_data_size); + // Also correct size of current "bufferView" ... + bufview->byteLength = output_data_size; + // and offset for all other "bufferViews" which are placed after edited. + const size_t difference = output_data_size - count; + + for(size_t idx_bv = 0; idx_bv < pAsset_Root.bufferViews.Size(); idx_bv++) + { + size_t off = pAsset_Root.bufferViews[idx_bv].byteOffset; + + if(off > (byte_offset + count)) pAsset_Root.bufferViews[idx_bv].byteOffset += difference; + } + + delete [] output_data; +} inline void Camera::Read(Value& obj, Asset& r) { From c024beadba926fe7873d9c6301df2db41d428493 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Wed, 3 Aug 2016 11:16:30 +0300 Subject: [PATCH 04/32] [+] Put information to log about decompressing. --- code/glTFAsset.inl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 60af03ee3..3e644c5c3 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -40,7 +40,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StringUtils.h" -// Header files, Open3DGC.h, +// Header files, Assimp +#include + +// Header files, Open3DGC. #include namespace glTF { @@ -720,6 +723,7 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\"."); + Assimp::DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data."); Decode_O3DGC(*comp_data, pAsset_Root); }// if(o3dgc == nullptr) }// if(extensions != nullptr) From 29e982e1851e72c1feead2d9e591434c29cec889 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Wed, 3 Aug 2016 18:06:38 +0300 Subject: [PATCH 05/32] [F] Fixed problem with more then one mesh in scene. More detaily read at line 529 in glTFAsset.inl. --- code/glTFAsset.h | 79 ++++++++++++++++++++++++++---- code/glTFAsset.inl | 111 +++++++++++++++++++++++++++--------------- code/glTFImporter.cpp | 30 +++++++++--- 3 files changed, 165 insertions(+), 55 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index c5c7d1349..860ba8df0 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -477,15 +478,6 @@ namespace glTF bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); - /// \fn void ReplaceData(uint8_t* pBufferData_Offset, size_t pBufferData_Count, uint8_t pPrepend_Data, size_t pPrepend_Count) - /// Replace part of buffer data. For example: decoded/encoded data. - /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. - /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. - /// \param [in] pReplace_Data - pointer to array with new data for buffer. - /// \param [in] pReplace_Count - count of bytes in new data. - /// \return true - if successfully replaced, false if input arguments is out of range. - bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); - size_t AppendData(uint8_t* data, size_t length); void Grow(size_t amount); @@ -501,6 +493,31 @@ namespace glTF static const char* TranslateId(Asset& r, const char* id); }; + /// \struct SEncodedRegion + /// Descriptor of encoded region in "bufferView". + struct SEncodedRegion + { + const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes. + const size_t EncodedData_Length;///< Size of encoded region, in bytes. + uint8_t* const DecodedData;///< Cached encoded data. + const size_t DecodedData_Length;///< Size of decoded region, in bytes. + const std::string ID;///< ID of the region. + + /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) + /// Constructor. + /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. + /// \param [in] pEncodedData_Length - size of encoded region, in bytes. + /// \param [in] pDecodedData - pointer to decoded data array. + /// \param [in] pDecodedData_Length - size of encoded region, in bytes. + /// \param [in] pID - ID of the region. + SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) + : Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) + {} + + /// \fn ~SEncodedRegion() + /// Destructor. + ~SEncodedRegion() { delete [] DecodedData; } + }; //! A view into a buffer generally representing a subset of the buffer. struct BufferView : public Object @@ -509,10 +526,52 @@ namespace glTF size_t byteOffset; //! The offset into the buffer in bytes. (required) size_t byteLength; //! The length of the bufferView in bytes. (default: 0) + /// \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. + SEncodedRegion* EncodedRegion_Current; + + /// \var EncodedRegion_List + /// List of encoded regions. + std::list EncodedRegion_List; + BufferViewTarget target; //! The target that the WebGL buffer should be bound to. - BufferView() {} + BufferView() + : EncodedRegion_Current(nullptr) + {} + + ~BufferView() { for(SEncodedRegion* reg : EncodedRegion_List) delete reg; } + void Read(Value& obj, Asset& r); + + /// \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); }; diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 3e644c5c3..b9e5c6e13 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -330,26 +330,6 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO return true; } -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; -} - inline size_t Buffer::AppendData(uint8_t* data, size_t length) { size_t offset = this->byteLength; @@ -367,6 +347,9 @@ inline void Buffer::Grow(size_t amount) byteLength += amount; } +// +// struct BufferView +// inline void BufferView::Read(Value& obj, Asset& r) { @@ -379,7 +362,58 @@ inline void BufferView::Read(Value& obj, Asset& r) byteLength = MemberOrDefault(obj, "byteLength", 0u); } +inline void BufferView::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) +{ +const size_t last = byteOffset + byteLength; + // 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 < byteOffset) || (pOffset > last)) + { + constexpr 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) > last) + { + constexpr 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 BufferView::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 void Accessor::Read(Value& obj, Asset& r) { @@ -419,7 +453,17 @@ inline uint8_t* Accessor::GetPointer() if (!basePtr) return 0; size_t offset = byteOffset + bufferView->byteOffset; - return basePtr + offset; + + // Check if region is encoded. + if(bufferView->EncodedRegion_Current != nullptr) + { + const size_t begin = bufferView->EncodedRegion_Current->Offset; + const size_t end = bufferView->EncodedRegion_Current->Offset + bufferView->EncodedRegion_Current->DecodedData_Length; + + if((offset >= begin) && (offset < end)) return &bufferView->EncodedRegion_Current->DecodedData[offset - begin]; + } + + return basePtr + offset; } namespace { @@ -777,8 +821,8 @@ const char* mode_str; const char* type_str; ComponentType component_type; - #define MESH_READ_COMPRESSEDDATA_MEMBER(pID, pOut) \ - if(!ReadMember(pJSON_Object_CompressedData, pID, pOut)) { throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pID + "\"."); } + #define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \ + if(!ReadMember(pJSON_Object_CompressedData, pFieldName, pOut)) { throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); } MESH_READ_COMPRESSEDDATA_MEMBER("bufferView", bufview_id); MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", byte_offset); @@ -838,21 +882,12 @@ ComponentType component_type; // Decode data if(decoder.DecodePlayload(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC data."); - // Set/extend buffer - bufview->buffer->ReplaceData(byte_offset, count, output_data, output_data_size); - // Also correct size of current "bufferView" ... - bufview->byteLength = output_data_size; - // and offset for all other "bufferViews" which are placed after edited. - const size_t difference = output_data_size - count; - - for(size_t idx_bv = 0; idx_bv < pAsset_Root.bufferViews.Size(); idx_bv++) - { - size_t off = pAsset_Root.bufferViews[idx_bv].byteOffset; - - if(off > (byte_offset + count)) pAsset_Root.bufferViews[idx_bv].byteOffset += difference; - } - - delete [] output_data; + // Set encoded region for bufferView. + bufview->EncodedRegion_Mark(byte_offset, count, output_data, output_data_size, name); + // Ans set is current + bufview->EncodedRegion_SetCurrent(name); + // No. Do not delete "output_data". After calling "EncodedRegion_Mark" bufferView is owner of "output_data". + // "delete [] output_data;" } inline void Camera::Read(Value& obj, Asset& r) diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index 6a6619b81..c2fcd488b 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -294,17 +294,30 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) } Mesh::Primitive::Attributes& attr = prim.attributes; - if (attr.position.size() > 0 && attr.position[0]) { + + // if "bufferView" of current accessor is containing encoded data then set ID of region. + if(attr.position[0]->bufferView->EncodedRegion_List.size() > 0) attr.position[0]->bufferView->EncodedRegion_SetCurrent(mesh.name); + + if (attr.position.size() > 0 && attr.position[0]) { aim->mNumVertices = attr.position[0]->count; attr.position[0]->ExtractData(aim->mVertices); } - if (attr.normal.size() > 0 && attr.normal[0]) { - attr.normal[0]->ExtractData(aim->mNormals); + // if "bufferView" of current accessor is containing encoded data then set ID of region. + if(attr.normal[0]->bufferView->EncodedRegion_List.size() > 0) attr.normal[0]->bufferView->EncodedRegion_SetCurrent(mesh.name); + + if (attr.normal.size() > 0 && attr.normal[0]) { + attr.normal[0]->ExtractData(aim->mNormals); } - for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { - attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); + // if "bufferView" of current accessor is containing encoded data then set ID of region. + if((attr.texcoord.size() > 0) && (attr.texcoord[0]->bufferView->EncodedRegion_List.size() > 0)) + { + attr.texcoord[0]->bufferView->EncodedRegion_SetCurrent(mesh.name); + } + + for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { + attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); aiVector3D* values = aim->mTextureCoords[tc]; @@ -315,7 +328,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) if (prim.indices) { - aiFace* faces = 0; + // if "bufferView" of current accessor is containing encoded data then set ID of region. + if(prim.indices->bufferView->EncodedRegion_List.size() > 0) prim.indices->bufferView->EncodedRegion_SetCurrent(mesh.name); + + aiFace* faces = 0; unsigned int nFaces = 0; unsigned int count = prim.indices->count; From e61fc06c405149ba74e207be883cf32dbf43ed3a Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Mon, 8 Aug 2016 19:04:37 +0300 Subject: [PATCH 06/32] [F] Comparison between signed and unsigned integer. --- contrib/Open3DGC/o3dgcSC3DMCDecoder.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.h b/contrib/Open3DGC/o3dgcSC3DMCDecoder.h index c8ca70ff6..1200c855a 100644 --- a/contrib/Open3DGC/o3dgcSC3DMCDecoder.h +++ b/contrib/Open3DGC/o3dgcSC3DMCDecoder.h @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy @@ -63,7 +63,7 @@ namespace o3dgc 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;} + O3DGCErrorCode SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; } private: From a6ec0e4c7aac15db229b7eac9e63698b09bbb42e Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Mon, 8 Aug 2016 19:06:17 +0300 Subject: [PATCH 07/32] [*] Style. Intermediate commit. --- code/glTFImporter.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index c2fcd488b..5fdad1261 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -301,14 +301,12 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) if (attr.position.size() > 0 && attr.position[0]) { aim->mNumVertices = attr.position[0]->count; attr.position[0]->ExtractData(aim->mVertices); - } + } // if "bufferView" of current accessor is containing encoded data then set ID of region. if(attr.normal[0]->bufferView->EncodedRegion_List.size() > 0) attr.normal[0]->bufferView->EncodedRegion_SetCurrent(mesh.name); - if (attr.normal.size() > 0 && attr.normal[0]) { - attr.normal[0]->ExtractData(aim->mNormals); - } + if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals); // if "bufferView" of current accessor is containing encoded data then set ID of region. if((attr.texcoord.size() > 0) && (attr.texcoord[0]->bufferView->EncodedRegion_List.size() > 0)) @@ -318,7 +316,7 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); - aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); + aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); aiVector3D* values = aim->mTextureCoords[tc]; for (unsigned int i = 0; i < aim->mNumVertices; ++i) { From 41ed74beb6cad0d6e56d5a2f5c0fa4f487dba4b1 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Mon, 8 Aug 2016 19:07:30 +0300 Subject: [PATCH 08/32] [*] Style. Intermediate commit. --- code/glTFAssetWriter.inl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index 0fa8556c0..00c907bcb 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -56,7 +56,7 @@ namespace glTF { inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(N, al); - for (int i = 0; i < N; ++i) { + for (decltype(N) i = 0; i < N; ++i) { val.PushBack(r[i], al); } return val; From 507668229fa7f07d48fa0882f1f9e613ca24e1df Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Mon, 8 Aug 2016 19:24:50 +0300 Subject: [PATCH 09/32] [+] Support Open3DGC for glTF import/export. Intermediate commit. --- code/glTFAsset.h | 3 + code/glTFAsset.inl | 87 +++++++++++++++++++++++++-- code/glTFExporter.cpp | 137 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 207 insertions(+), 20 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 860ba8df0..3b3c513a2 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -543,6 +543,9 @@ namespace glTF /// 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; /// \var EncodedRegion_List diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index b9e5c6e13..40740bacc 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -820,6 +820,11 @@ uint32_t byte_offset, count, count_indices, count_vertices; const char* mode_str; const char* type_str; ComponentType component_type; +std::list float_attributes_indices;// See above about "floatAttributesIndexes". + + /**********************************************************/ + /************** Read data from JSON-document **************/ + /**********************************************************/ #define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \ if(!ReadMember(pJSON_Object_CompressedData, pFieldName, pOut)) { throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); } @@ -835,6 +840,40 @@ ComponentType component_type; #undef MESH_READ_COMPRESSEDDATA_MEMBER + // + // Check for float attributes + // + // Object example: + // "floatAttributesIndexes": { + // "accessor_1356": 0, + // "accessor_1358": 1, + // "accessor_1360": 2 + // }, + // + // Find object "floatAttributesIndexes" + Value* float_attr_ind = FindObject(pJSON_Object_CompressedData, "floatAttributesIndexes"); + + if(float_attr_ind != nullptr) + { + size_t attr_num = 0; + + // Walk thru children and get accessors and numbers of attributes. + for(Value::MemberIterator memb_it = float_attr_ind->MemberBegin(); memb_it != float_attr_ind->MemberEnd(); ++memb_it) + { + if(!memb_it->name.IsString()) throw DeadlyImportError("GLTF: name of the member of \"floatAttributesIndexes\" must be a string."); + if(!memb_it->value.IsUint()) throw DeadlyImportError(std::string("GLTF: value of the member (\"") + memb_it->name.GetString() + \ + "\") in \"floatAttributesIndexes\" must be an unsigned integer."); + /*if(attr_num != memb_it->value.GetUint()) throw DeadlyImportError(std::string("GLTF: invalid number of float attribute index. Member (\"") + \ + memb_it->name.GetString() + "\".");*/ + + attr_num++; + // Checks passed, extract data. + Ref attr_cur_acc = pAsset_Root.accessors.Get(memb_it->name.GetString()); + + float_attributes_indices.push_back((float*)attr_cur_acc->GetPointer()); + } + }// if(float_attr_ind != nullptr) + // 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."); @@ -843,6 +882,10 @@ ComponentType component_type; throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\"."); } + /**********************************************************/ + /********************* Decoding data **********************/ + /**********************************************************/ + // Search for "bufferView" by ID. Ref bufview = pAsset_Root.bufferViews.Get(bufview_id); @@ -851,10 +894,11 @@ ComponentType component_type; // // void testDecode(shared_ptr mesh, BinaryStream &bstream) o3dgc::SC3DMCDecoder decoder; - o3dgc::IndexedFaceSet ifs; + o3dgc::IndexedFaceSet ifs; uint8_t* output_data; - size_t size_vertex, size_normal, size_texcoord, size_indices, output_data_size; + size_t size_vertex, size_normal, size_indices, output_data_size; o3dgc::BinaryStream bstream; + float* tarrays[6]; // Read data from buffer and place it in BinaryStream for decoder. bstream.LoadFromBuffer(&bufview->buffer->GetPointer()[bufview->byteOffset + byte_offset], count); @@ -862,12 +906,43 @@ ComponentType component_type; // 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."); + size_indices = ifs.GetNCoordIndex() * 3 * sizeof(unsigned short); size_vertex = ifs.GetNCoord() * 3 * sizeof(float); size_normal = ifs.GetNNormal() * 3 * sizeof(float); - size_texcoord = ifs.GetNFloatAttribute(0) * 2 * sizeof(float); - size_indices = ifs.GetNCoordIndex() * 3 * sizeof(unsigned short); - output_data_size = size_vertex + size_normal + size_texcoord + size_indices; + for(size_t idx_attr = 0, idx_attr_end = ifs.GetNumFloatAttributes(); idx_attr < idx_attr_end; idx_attr++) + { + size_t qty_attr = ifs.GetNFloatAttribute(idx_attr); + + if(qty_attr == 0) continue; + + tarrays[idx_attr] = new float[qty_attr * ifs.GetFloatAttributeDim(idx_attr)]; + ifs.SetFloatAttribute(idx_attr, tarrays[idx_attr]); + /* + switch(ifs.GetFloatAttributeType(idx_attr)) + { + // Unknown for Open3DGC, + // but not for COLLADA2GLTF - GLTF::Semantic::JOINT. What's mean "JOINT"? Good question, but lim(comments in COLLADA2GLTF) = 0. + case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_UNKOWN:// 0 + break; + case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_POSITION:// 1 + break; + case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_NORMAL:// 2 + break; + case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_COLOR:// 3 + break; + case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:// 4 + break; + case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_WEIGHT:// 5 + break; + default: + throw DeadlyImportError("GLTF: Unknown type of float attribute (" + std::to_string(idx_attr) + ") for Open3DGC encoding."); + }*/ + } + + //size_texcoord = ifs.GetNFloatAttribute(0) * 2 * sizeof(float); + + output_data_size = size_vertex + size_normal + /*size_texcoord*/ + size_indices; output_data = new uint8_t[output_data_size]; float* uncompressed_vertices = (float* const)(output_data + size_indices);// size_indices => vertex offset @@ -877,7 +952,7 @@ ComponentType component_type; if(ifs.GetNNormal() > 0) ifs.SetNormal((float* const)(output_data + size_indices + size_vertex)); - if(ifs.GetNFloatAttribute(0)) ifs.SetFloatAttribute(0, (float* const)(output_data + size_indices + size_vertex + size_normal)); + //if(ifs.GetNFloatAttribute(0)) ifs.SetFloatAttribute(0, (float* const)(output_data + size_indices + size_vertex + size_normal)); // Decode data if(decoder.DecodePlayload(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC data."); diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 7f0c086cf..ff5c25675 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -1,4 +1,4 @@ -/* +/* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -55,10 +55,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +// Header files, standart library. #include +#include #include "glTFAssetWriter.h" +// Header files, Open3DGC. +#include + using namespace rapidjson; using namespace Assimp; @@ -252,9 +257,36 @@ void glTFExporter::ExportMaterials() void glTFExporter::ExportMeshes() { +// Not for +// using IndicesType = decltype(aiFace::mNumIndices); +// But yes for +// using IndicesType = unsigned short; +// because "ComponentType_UNSIGNED_SHORT" used for indices. And its maximal type according to glTF specification. +using IndicesType = unsigned short; + +// Variables needed for compression. BEGIN. +// Indices, not pointers - because pointer to buffer is changin while writing to it. +size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer. +size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals. +std::vector idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer. +size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer. +bool comp_allow;// Point that data of current mesh can be compressed. +// Variables needed for compression. END. + for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { const aiMesh* aim = mScene->mMeshes[i]; + // Check if compressing requested and mesh can be encoded. + if((aim->mPrimitiveTypes == aiPrimitiveType_TRIANGLE) && (aim->mNumVertices > 0))///TODO: export properties if(compression is needed) + { + comp_allow = true; + idx_srcdata_tc.reserve(AI_MAX_NUMBER_OF_TEXTURECOORDS); + } + else + { + comp_allow = false; + } + std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh"); Ref m = mAsset->meshes.Create(meshId); m->primitives.resize(1); @@ -269,31 +301,46 @@ void glTFExporter::ExportMeshes() b = mAsset->buffers.Create(bufferId); } + /******************* Vertices ********************/ + // If compression is used then you need parameters of uncompressed region: begin and size. At this step "begin" is stored. + if(comp_allow) idx_srcdata_begin = b->byteLength; + Ref v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); - if (v) p.attributes.position.push_back(v); + if (v) p.attributes.position.push_back(v); - Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); - if (n) p.attributes.normal.push_back(n); + /******************** Normals ********************/ + if(comp_allow && (aim->mNormals > 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array. + Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + if (n) p.attributes.normal.push_back(n); + + /************** Texture coordinates **************/ for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { if (aim->mNumUVComponents[i] > 0) { AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3; - Ref tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true); - if (tc) p.attributes.texcoord.push_back(tc); - } - } - if (aim->mNumFaces > 0) { - unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices; - std::vector indices; + if(comp_allow) idx_srcdata_tc.push_back(b->byteLength);// Store index of texture coordinates array. + + Ref tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true); + if (tc) p.attributes.texcoord.push_back(tc); + } + } + + /*************** Vertices indices ****************/ + idx_srcdata_ind = b->byteLength;// Store index of indices array. + + if (aim->mNumFaces > 0) { + std::vector indices; + unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices; indices.resize(aim->mNumFaces * nIndicesPerFace); for (size_t i = 0; i < aim->mNumFaces; ++i) { for (size_t j = 0; j < nIndicesPerFace; ++j) { indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]); } } - p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT, true); - } + + p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT, true); + } switch (aim->mPrimitiveTypes) { case aiPrimitiveType_POLYGON: @@ -305,7 +352,69 @@ void glTFExporter::ExportMeshes() default: // aiPrimitiveType_TRIANGLE p.mode = PrimitiveMode_TRIANGLES; } - } + + /****************** Compression ******************/ + ///TODO: animation: weights, joints. + if(comp_allow) + { + o3dgc::BinaryStream bs; + o3dgc::SC3DMCEncoder encoder; + o3dgc::IndexedFaceSet comp_o3dgc_ifs; + o3dgc::SC3DMCEncodeParams comp_o3dgc_params; + unsigned qcoord = 12;///TODO: dbg + unsigned qnormal = 10;///TODO: dbg + unsigned qtexCoord = 10;///TODO: dbg + + o3dgc::O3DGCSC3DMCPredictionMode positionPrediction = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;///TODO: dbg + o3dgc::O3DGCSC3DMCPredictionMode normalPrediction = o3dgc::O3DGC_SC3DMC_SURF_NORMALS_PREDICTION;///TODO: dbg + o3dgc::O3DGCSC3DMCPredictionMode texcoordPrediction = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;///TODO: dbg + + // 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(qcoord);///TODO: IME + comp_o3dgc_params.SetCoordPredMode(positionPrediction);///TODO: IME + 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(qnormal);///TODO: IME + comp_o3dgc_params.SetNormalPredMode(normalPrediction);///TODO: IME + 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, qtexCoord);///TODO: IME + comp_o3dgc_params.SetFloatAttributePredMode(num, texcoordPrediction);///TODO: IME + comp_o3dgc_ifs.SetNFloatAttribute(num, aim->mNumVertices);// number of elements. + comp_o3dgc_ifs.SetFloatAttributeDim(num, aim->mNumUVComponents[i]);// 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()); + comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_BINARY);///TODO: exporter params + // Encoding + encoder.Encode(comp_o3dgc_params, comp_o3dgc_ifs, bs); + + ///TODO: replace data in buffer + }// if(comp_allow) + }// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { + + ///TODO: export properties if(compression is used) } unsigned int glTFExporter::ExportNode(const aiNode* n) From 9a4fa1321b99328aff52793af556fbc4cc718730 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Tue, 9 Aug 2016 13:26:57 +0300 Subject: [PATCH 10/32] [+] Save parameters of mesh extension: Open3DGC-compression. --- code/glTFAsset.h | 58 ++++++++++++++++++++++++++++++++++++++-- code/glTFAsset.inl | 22 +++++++++++++++ code/glTFAssetWriter.inl | 47 ++++++++++++++++++++++++++++++++ code/glTFExporter.cpp | 24 ++++++++++++++++- 4 files changed, 148 insertions(+), 3 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 3b3c513a2..80a2d0008 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -362,8 +362,6 @@ namespace glTF { return id; } }; - - // // Classes for each glTF top-level object type // @@ -478,6 +476,15 @@ namespace glTF bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); + /// \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. For example: decoded/encoded data. + /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. + /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. + /// \param [in] pReplace_Data - pointer to array with new data for buffer. + /// \param [in] pReplace_Count - count of bytes in new data. + /// \return true - if successfully replaced, false if input arguments is out of range. + bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); + size_t AppendData(uint8_t* data, size_t length); void Grow(size_t amount); @@ -702,10 +709,57 @@ namespace glTF Ref material; }; + /// \struct SExtension + /// Extension used for mesh. + struct SExtension + { + /// \enum EType + /// Type of extension. + enum class EType + { + Compression_Open3DGC ///< Compression of mesh data using Open3DGC algorythm. + }; + + EType Type;///< Type of extension. + + /// \fn SExtension + /// Constructor. + /// \param [in] pType - type of extension. + SExtension(const EType pType) + : Type(pType) + {} + }; + + /// \struct SCompression_Open3DGC + /// Compression of mesh data using Open3DGC algorythm. + struct SCompression_Open3DGC final : public SExtension + { + using SExtension::Type; + + std::string BufferView;///< Name of "bufferView" 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". + 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(EType::Compression_Open3DGC) + {} + }; + std::vector primitives; + std::list Extension;///< List of extensions used in mesh. Mesh() {} + /// \fn ~Mesh() + /// Destructor. + ~Mesh() { for(auto e : Extension) { delete e; }; } + /// \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. diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 40740bacc..de9c16575 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -330,6 +330,28 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO return true; } +inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count) +{ +const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count; + +uint8_t* new_data; + + if((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false; + + new_data = new uint8_t[new_data_size]; + // Copy data which place before replacing part. + memcpy(new_data, mData.get(), pBufferData_Offset); + // Copy new data. + memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count); + // Copy data which place after replacing part. + memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset); + // Apply new data + mData.reset(new_data); + byteLength = new_data_size; + + return true; +} + inline size_t Buffer::AppendData(uint8_t* data, size_t length) { size_t offset = this->byteLength; diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index 00c907bcb..e8ca28bb5 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -199,6 +199,53 @@ namespace glTF { inline void Write(Value& obj, Mesh& m, AssetWriter& w) { + /********************* Name **********************/ + obj.AddMember("name", m.name, w.mAl); + + /**************** Mesh extensions ****************/ + if(m.Extension.size() > 0) + { + Value json_extensions; + + json_extensions.SetObject(); + for(Mesh::SExtension* ptr_ext : m.Extension) + { + switch(ptr_ext->Type) + { + 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("bufferView", ptr_ext_comp->BufferView, 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); + 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; + default: + throw DeadlyImportError("GLTF: Unknown mesh extension, Only Open3DGC is supported."); + }// switch(ptr_ext->Type) + }// for(Mesh::SExtension* ptr_ext : m.Extension) + + // Add extensions to mesh + obj.AddMember("extensions", json_extensions, w.mAl); + }// if(m.Extension.size() > 0) + + /****************** Primitives *******************/ Value primitives; primitives.SetArray(); primitives.Reserve(unsigned(m.primitives.size()), w.mAl); diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index ff5c25675..2f30cd579 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -357,10 +357,16 @@ bool comp_allow;// Point that data of current mesh can be compressed. ///TODO: animation: weights, joints. if(comp_allow) { + // Only one type of compression supported at now - Open3DGC. + // o3dgc::BinaryStream bs; o3dgc::SC3DMCEncoder encoder; o3dgc::IndexedFaceSet comp_o3dgc_ifs; o3dgc::SC3DMCEncodeParams comp_o3dgc_params; + + // + // Fill data for encoder. + // unsigned qcoord = 12;///TODO: dbg unsigned qnormal = 10;///TODO: dbg unsigned qtexCoord = 10;///TODO: dbg @@ -407,10 +413,26 @@ bool comp_allow;// Point that data of current mesh can be compressed. // Prepare to enconding comp_o3dgc_params.SetNumFloatAttributes(comp_o3dgc_ifs.GetNumFloatAttributes()); comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_BINARY);///TODO: exporter params + // // 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; - ///TODO: replace data in buffer + // Fill it. + ext->BufferView = p.indices->bufferView->id; + ext->Offset = idx_srcdata_begin; + ext->Count = b->byteLength - idx_srcdata_begin; + ext->IndicesCount = comp_o3dgc_ifs.GetNCoordIndex(); + ext->VerticesCount = comp_o3dgc_ifs.GetNCoord(); + // And assign to mesh. + m->Extension.push_back(ext); }// if(comp_allow) }// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { From 778ad7f06f3b98847ed5d73a533faf84ad44bd0f Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Tue, 9 Aug 2016 13:37:32 +0300 Subject: [PATCH 11/32] [+] Use "buffer" ID against "bufferView" ID for Open3DGC-compression. --- code/glTFAsset.h | 2 +- code/glTFAssetWriter.inl | 2 +- code/glTFExporter.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 80a2d0008..5f4f933d9 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -736,7 +736,7 @@ namespace glTF { using SExtension::Type; - std::string BufferView;///< Name of "bufferView" used for storing compressed data. + 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". size_t IndicesCount;///< Count of indices in mesh. diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index e8ca28bb5..f30e8cf89 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -219,7 +219,7 @@ namespace glTF { // filling object "compressedData" json_comp_data.SetObject(); - json_comp_data.AddMember("bufferView", ptr_ext_comp->BufferView, w.mAl); + 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); diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 2f30cd579..1dc35b5cd 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -426,7 +426,7 @@ bool comp_allow;// Point that data of current mesh can be compressed. Mesh::SCompression_Open3DGC* ext = new Mesh::SCompression_Open3DGC; // Fill it. - ext->BufferView = p.indices->bufferView->id; + ext->Buffer = b->id; ext->Offset = idx_srcdata_begin; ext->Count = b->byteLength - idx_srcdata_begin; ext->IndicesCount = comp_o3dgc_ifs.GetNCoordIndex(); From 0dcf4dcd16a7979f81dd9189ded4742dc0fba947 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Thu, 11 Aug 2016 01:02:32 +0300 Subject: [PATCH 12/32] [F] Typo. --- contrib/Open3DGC/o3dgcSC3DMCDecoder.h | 2 +- contrib/Open3DGC/o3dgcSC3DMCDecoder.inl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.h b/contrib/Open3DGC/o3dgcSC3DMCDecoder.h index 1200c855a..f3f1617c4 100644 --- a/contrib/Open3DGC/o3dgcSC3DMCDecoder.h +++ b/contrib/Open3DGC/o3dgcSC3DMCDecoder.h @@ -59,7 +59,7 @@ namespace o3dgc O3DGCErrorCode DecodeHeader(IndexedFaceSet & ifs, const BinaryStream & bstream); //! - O3DGCErrorCode DecodePlayload(IndexedFaceSet & ifs, + O3DGCErrorCode DecodePayload(IndexedFaceSet & ifs, const BinaryStream & bstream); const SC3DMCStats & GetStats() const { return m_stats;} unsigned long GetIterator() const { return m_iterator;} diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl index 040b405be..d36b62f2b 100644 --- a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl +++ b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy @@ -136,7 +136,7 @@ namespace o3dgc return O3DGC_OK; } template - O3DGCErrorCode SC3DMCDecoder::DecodePlayload(IndexedFaceSet & ifs, + O3DGCErrorCode SC3DMCDecoder::DecodePayload(IndexedFaceSet & ifs, const BinaryStream & bstream) { O3DGCErrorCode ret = O3DGC_OK; From 0ad2f2247aa5a4afdcb12ca8efc9d29905f0f1aa Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Thu, 11 Aug 2016 01:04:30 +0300 Subject: [PATCH 13/32] [+] glTF import/export. Support for Open3DGC-compression of mesh primitives. --- code/glTFAsset.h | 179 +++++++-------- code/glTFAsset.inl | 474 ++++++++++++++++++++++----------------- code/glTFAssetWriter.inl | 7 +- code/glTFExporter.cpp | 60 +++-- code/glTFImporter.cpp | 46 ++-- 5 files changed, 427 insertions(+), 339 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 5f4f933d9..90335f52f 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -450,88 +450,49 @@ namespace glTF //! A buffer points to binary geometry, animation, or skins. struct Buffer : public Object - { - public: - - enum Type - { - Type_arraybuffer, - Type_text - }; - - //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) - size_t byteLength; //!< The length of the buffer in bytes. (default: 0) - //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") - - Type type; - - private: - shared_ptr mData; //!< Pointer to the data - bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) - - public: - Buffer(); - - void Read(Value& obj, Asset& r); - - bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); - - /// \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. For example: decoded/encoded data. - /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. - /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. - /// \param [in] pReplace_Data - pointer to array with new data for buffer. - /// \param [in] pReplace_Count - count of bytes in new data. - /// \return true - if successfully replaced, false if input arguments is out of range. - bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); - - size_t AppendData(uint8_t* data, size_t length); - void Grow(size_t amount); - - uint8_t* GetPointer() - { return mData.get(); } - - void MarkAsSpecial() - { mIsSpecial = true; } - - bool IsSpecial() const - { return mIsSpecial; } - - static const char* TranslateId(Asset& r, const char* id); - }; - - /// \struct SEncodedRegion - /// Descriptor of encoded region in "bufferView". - struct SEncodedRegion { - const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes. - const size_t EncodedData_Length;///< Size of encoded region, in bytes. - uint8_t* const DecodedData;///< Cached encoded data. - const size_t DecodedData_Length;///< Size of decoded region, in bytes. - const std::string ID;///< ID of the region. + /********************* Types *********************/ + public: - /// \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) - {} + enum Type + { + Type_arraybuffer, + Type_text + }; - /// \fn ~SEncodedRegion() - /// Destructor. - ~SEncodedRegion() { delete [] DecodedData; } - }; + /// \struct SEncodedRegion + /// Descriptor of encoded region in "bufferView". + struct SEncodedRegion + { + const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes. + const size_t EncodedData_Length;///< Size of encoded region, in bytes. + uint8_t* const DecodedData;///< Cached encoded data. + const size_t DecodedData_Length;///< Size of decoded region, in bytes. + const std::string ID;///< ID of the region. - //! A view into a buffer generally representing a subset of the buffer. - struct BufferView : public Object - { - Ref buffer; //! The ID of the buffer. (required) - size_t byteOffset; //! The offset into the buffer in bytes. (required) - size_t byteLength; //! The length of the bufferView in bytes. (default: 0) + /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) + /// Constructor. + /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. + /// \param [in] pEncodedData_Length - size of encoded region, in bytes. + /// \param [in] pDecodedData - pointer to decoded data array. + /// \param [in] pDecodedData_Length - size of encoded region, in bytes. + /// \param [in] pID - ID of the region. + SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) + : Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) + {} + + /// \fn ~SEncodedRegion() + /// Destructor. + ~SEncodedRegion() { delete [] DecodedData; } + }; + + /******************* Variables *******************/ + + //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) + size_t byteLength; //!< The length of the buffer in bytes. (default: 0) + //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") + + Type type; /// \var EncodedRegion_Current /// Pointer to currently active encoded region. @@ -555,19 +516,25 @@ namespace glTF /// exporter and importer. And, thanks to such way, there is no need to load whole file into memory. SEncodedRegion* EncodedRegion_Current; + private: + + shared_ptr mData; //!< Pointer to the data + bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) + /// \var EncodedRegion_List /// List of encoded regions. std::list EncodedRegion_List; - BufferViewTarget target; //! The target that the WebGL buffer should be bound to. + /******************* Functions *******************/ - BufferView() - : EncodedRegion_Current(nullptr) - {} + public: - ~BufferView() { for(SEncodedRegion* reg : EncodedRegion_List) delete reg; } + Buffer(); + ~Buffer(); - void Read(Value& obj, Asset& r); + void Read(Value& obj, Asset& r); + + bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); /// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data. @@ -582,8 +549,42 @@ namespace glTF /// Select current encoded region by ID. \sa EncodedRegion_Current. /// \param [in] pID - ID of the region. void EncodedRegion_SetCurrent(const std::string& pID); + + /// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count) + /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions. + /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. + /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. + /// \param [in] pReplace_Data - pointer to array with new data for buffer. + /// \param [in] pReplace_Count - count of bytes in new data. + /// \return true - if successfully replaced, false if input arguments is out of range. + bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); + + size_t AppendData(uint8_t* data, size_t length); + void Grow(size_t amount); + + uint8_t* GetPointer() + { return mData.get(); } + + void MarkAsSpecial() + { mIsSpecial = true; } + + bool IsSpecial() const + { return mIsSpecial; } + + static const char* TranslateId(Asset& r, const char* id); }; + //! A view into a buffer generally representing a subset of the buffer. + struct BufferView : public Object + { + Ref buffer; //! The ID of the buffer. (required) + size_t byteOffset; //! The offset into the buffer in bytes. (required) + size_t byteLength; //! The length of the bufferView in bytes. (default: 0) + + BufferViewTarget target; //! The target that the WebGL buffer should be bound to. + + void Read(Value& obj, Asset& r); + }; struct Camera : public Object { @@ -739,6 +740,7 @@ namespace glTF 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". @@ -766,11 +768,11 @@ namespace glTF /// \param [out] pAsset_Root - reference to root assed where data will be stored. void Read(Value& pJSON_Object, Asset& pAsset_Root); - /// \fn void Decode_O3DGC(Value& pJSON_Object_CompressedData, Asset& pAsset_Root) - /// Decode part of "bufferView" which encoded with Open3DGC algorythm. - /// \param [in] pJSON_Object_CompressedData - reference to JSON-object which is "compressedData" block. + /// \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(Value& pJSON_Object_CompressedData, Asset& pAsset_Root); + void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root); }; struct Node : public Object @@ -941,6 +943,7 @@ namespace glTF Ref Get(const char* id); Ref Get(unsigned int i); + Ref Get(const std::string& pID) { return Get(pID.c_str()); } Ref Create(const char* id); Ref Create(const std::string& id) diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index de9c16575..339717146 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -247,9 +247,14 @@ Ref LazyDict::Create(const char* id) inline Buffer::Buffer() -: byteLength(0), type(Type_arraybuffer), mIsSpecial(false) + : byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false) { } +inline Buffer::~Buffer() +{ + for(SEncodedRegion* reg : EncodedRegion_List) delete reg; +} + inline const char* Buffer::TranslateId(Asset& r, const char* id) { // Compatibility with old spec @@ -330,6 +335,57 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO return true; } +inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) +{ + // Check pointer to data + if(pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided."); + + // Check offset + if(pOffset > byteLength) + { + constexpr 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) + { + constexpr 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; @@ -384,58 +440,9 @@ inline void BufferView::Read(Value& obj, Asset& r) byteLength = MemberOrDefault(obj, "byteLength", 0u); } -inline void BufferView::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) -{ -const size_t last = byteOffset + byteLength; - - // 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 < byteOffset) || (pOffset > last)) - { - constexpr 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) > last) - { - constexpr 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 BufferView::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."); -} +// +// struct Accessor +// inline void Accessor::Read(Value& obj, Asset& r) { @@ -477,12 +484,12 @@ inline uint8_t* Accessor::GetPointer() size_t offset = byteOffset + bufferView->byteOffset; // Check if region is encoded. - if(bufferView->EncodedRegion_Current != nullptr) + if(bufferView->buffer->EncodedRegion_Current != nullptr) { - const size_t begin = bufferView->EncodedRegion_Current->Offset; - const size_t end = bufferView->EncodedRegion_Current->Offset + bufferView->EncodedRegion_Current->DecodedData_Length; + const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset; + const size_t end = bufferView->buffer->EncodedRegion_Current->Offset + bufferView->buffer->EncodedRegion_Current->DecodedData_Length; - if((offset >= begin) && (offset < end)) return &bufferView->EncodedRegion_Current->DecodedData[offset - begin]; + if((offset >= begin) && (offset < end)) return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin]; } return basePtr + offset; @@ -770,33 +777,7 @@ namespace { inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) { - // - // Mesh extensions - // - // At first check for extensions. They can affect on interpretaion of mesh data. - Value* extensions = FindObject(pJSON_Object, "extensions"); - - if(extensions != nullptr) - { - // At first check if data of mesh is compressed. Because buffer data must be decoded before another get data from it. - // Only Open3DGC supported at now. - Value* o3dgc = FindObject(*extensions, "Open3DGC-compression"); - - if(o3dgc != nullptr) - { - // Search compressed data - Value* comp_data = FindObject(*o3dgc, "compressedData"); - - if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\"."); - - Assimp::DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data."); - Decode_O3DGC(*comp_data, pAsset_Root); - }// if(o3dgc == nullptr) - }// if(extensions != nullptr) - - // - // Mesh primitives. - // + /****************** Mesh primitives ******************/ if (Value* primitives = FindArray(pJSON_Object, "primitives")) { this->primitives.resize(primitives->Size()); for (unsigned int i = 0; i < primitives->Size(); ++i) { @@ -831,158 +812,229 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) } } } + + /****************** 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++) + { + 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\"."); + + Assimp::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 + { + 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. } -inline void Mesh::Decode_O3DGC(Value& pJSON_Object_CompressedData, Asset& pAsset_Root) +inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root) { -// Compressed data contain description of part of "bufferView" which is encoded. This part must be decoded and -// new data must replace old encoded part. In fact \"compressedData\" is similar to "accessor" structure. -const char* bufview_id; -uint32_t byte_offset, count, count_indices, count_vertices; -const char* mode_str; -const char* type_str; -ComponentType component_type; -std::list float_attributes_indices;// See above about "floatAttributesIndexes". +using IndicesType = unsigned short;///< \sa glTFExporter::ExportMeshes. - /**********************************************************/ - /************** Read data from JSON-document **************/ - /**********************************************************/ - - #define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \ - if(!ReadMember(pJSON_Object_CompressedData, pFieldName, pOut)) { throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); } - - MESH_READ_COMPRESSEDDATA_MEMBER("bufferView", bufview_id); - MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", byte_offset); - MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type); - MESH_READ_COMPRESSEDDATA_MEMBER("count", count); - MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", count_indices); - MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", count_vertices); - MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str); - MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str); - - #undef MESH_READ_COMPRESSEDDATA_MEMBER - - // - // Check for float attributes - // - // Object example: - // "floatAttributesIndexes": { - // "accessor_1356": 0, - // "accessor_1358": 1, - // "accessor_1360": 2 - // }, - // - // Find object "floatAttributesIndexes" - Value* float_attr_ind = FindObject(pJSON_Object_CompressedData, "floatAttributesIndexes"); - - if(float_attr_ind != nullptr) - { - size_t attr_num = 0; - - // Walk thru children and get accessors and numbers of attributes. - for(Value::MemberIterator memb_it = float_attr_ind->MemberBegin(); memb_it != float_attr_ind->MemberEnd(); ++memb_it) - { - if(!memb_it->name.IsString()) throw DeadlyImportError("GLTF: name of the member of \"floatAttributesIndexes\" must be a string."); - if(!memb_it->value.IsUint()) throw DeadlyImportError(std::string("GLTF: value of the member (\"") + memb_it->name.GetString() + \ - "\") in \"floatAttributesIndexes\" must be an unsigned integer."); - /*if(attr_num != memb_it->value.GetUint()) throw DeadlyImportError(std::string("GLTF: invalid number of float attribute index. Member (\"") + \ - memb_it->name.GetString() + "\".");*/ - - attr_num++; - // Checks passed, extract data. - Ref attr_cur_acc = pAsset_Root.accessors.Get(memb_it->name.GetString()); - - float_attributes_indices.push_back((float*)attr_cur_acc->GetPointer()); - } - }// if(float_attr_ind != nullptr) - - // 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."); - if((strcmp(mode_str, "binary") != 0) && (strcmp(mode_str, "ascii") != 0)) - { - throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\"."); - } - - /**********************************************************/ - /********************* Decoding data **********************/ - /**********************************************************/ - - // Search for "bufferView" by ID. - Ref bufview = pAsset_Root.bufferViews.Get(bufview_id); - - // - // Decode data. Adapted piece of code from COLLADA2GLTF converter. - // - // void testDecode(shared_ptr mesh, BinaryStream &bstream) - o3dgc::SC3DMCDecoder decoder; - o3dgc::IndexedFaceSet ifs; - uint8_t* output_data; - size_t size_vertex, size_normal, size_indices, output_data_size; - o3dgc::BinaryStream bstream; - float* tarrays[6]; +o3dgc::SC3DMCDecoder decoder; +o3dgc::IndexedFaceSet ifs; +o3dgc::BinaryStream bstream; +uint8_t* decoded_data; +size_t decoded_data_size = 0; +Ref buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer); // Read data from buffer and place it in BinaryStream for decoder. - bstream.LoadFromBuffer(&bufview->buffer->GetPointer()[bufview->byteOffset + byte_offset], count); + // 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 + // 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."); - size_indices = ifs.GetNCoordIndex() * 3 * sizeof(unsigned short); - size_vertex = ifs.GetNCoord() * 3 * sizeof(float); - size_normal = ifs.GetNNormal() * 3 * sizeof(float); + /****************** Get sizes of arrays and check sizes ******************/ + // Note. See "Limitations for meshes when using Open3DGC-compression". - for(size_t idx_attr = 0, idx_attr_end = ifs.GetNumFloatAttributes(); idx_attr < idx_attr_end; idx_attr++) + // Indices + size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note. + + if(primitives[0].indices->count != size_coordindex) + throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + std::to_string(size_coordindex) + + ") not equal to uncompressed (" + std::to_string(primitives[0].indices->count) + ")."); + + size_coordindex *= sizeof(IndicesType); + // Coordinates + size_t size_coord = ifs.GetNCoord();// See float attributes note. + + if(primitives[0].attributes.position[0]->count != size_coord) + throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + std::to_string(size_coord) + + ") not equal to uncompressed (" + std::to_string(primitives[0].attributes.position[0]->count) + ")."); + + size_coord *= 3 * sizeof(float); + // Normals + size_t size_normal = ifs.GetNNormal();// See float attributes note. + + if(primitives[0].attributes.normal[0]->count != size_normal) + throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + std::to_string(size_normal) + + ") not equal to uncompressed (" + std::to_string(primitives[0].attributes.normal[0]->count) + ")."); + + size_normal *= 3 * sizeof(float); + // Additional attributes. + std::vector size_floatattr; + std::vector size_intattr; + + size_floatattr.resize(ifs.GetNumFloatAttributes()); + size_intattr.resize(ifs.GetNumIntAttributes()); + + decoded_data_size = size_coordindex + size_coord + size_normal; + for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) { - size_t qty_attr = ifs.GetNFloatAttribute(idx_attr); + // 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); - if(qty_attr == 0) continue; - - tarrays[idx_attr] = new float[qty_attr * ifs.GetFloatAttributeDim(idx_attr)]; - ifs.SetFloatAttribute(idx_attr, tarrays[idx_attr]); - /* - switch(ifs.GetFloatAttributeType(idx_attr)) + switch(ifs.GetFloatAttributeType(idx)) { - // Unknown for Open3DGC, - // but not for COLLADA2GLTF - GLTF::Semantic::JOINT. What's mean "JOINT"? Good question, but lim(comments in COLLADA2GLTF) = 0. - case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_UNKOWN:// 0 - break; - case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_POSITION:// 1 - break; - case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_NORMAL:// 2 - break; - case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_COLOR:// 3 - break; - case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:// 4 - break; - case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_WEIGHT:// 5 + 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: Unknown type of float attribute (" + std::to_string(idx_attr) + ") for Open3DGC encoding."); - }*/ + 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; } - //size_texcoord = ifs.GetNFloatAttribute(0) * 2 * sizeof(float); + 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); - output_data_size = size_vertex + size_normal + /*size_texcoord*/ + size_indices; - output_data = new uint8_t[output_data_size]; + switch(ifs.GetIntAttributeType(idx)) + { + default: + throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + std::to_string(ifs.GetIntAttributeType(idx))); + } - float* uncompressed_vertices = (float* const)(output_data + size_indices);// size_indices => vertex offset + tval *= ifs.GetIntAttributeDim(idx) * sizeof(long);// See float attributes note. + size_intattr[idx] = tval; + decoded_data_size += tval; + } - ifs.SetCoordIndex((uint16_t* const)output_data); - ifs.SetCoord((float* const)uncompressed_vertices); + // Create array for decoded data. + decoded_data = new uint8_t[decoded_data_size]; - if(ifs.GetNNormal() > 0) ifs.SetNormal((float* const)(output_data + size_indices + size_vertex)); + /****************** Set right array regions for decoder ******************/ - //if(ifs.GetNFloatAttribute(0)) ifs.SetFloatAttribute(0, (float* const)(output_data + size_indices + size_vertex + size_normal)); + auto get_buf_offset = [](Ref& pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; }; + // Indices + ifs.SetCoordIndex((IndicesType* const)(decoded_data + get_buf_offset(primitives[0].indices))); + // Coordinates + ifs.SetCoord((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.position[0]))); + // Normals + if(size_normal) + { + ifs.SetNormal((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0]))); + } + + for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) + { + switch(ifs.GetFloatAttributeType(idx)) + { + case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD: + if(idx_texcoord < primitives[0].attributes.texcoord.size()) + { + // See above about absent attributes. + ifs.SetFloatAttribute(idx, (o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx]))); + idx_texcoord++; + } + + break; + default: + throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + std::to_string(ifs.GetFloatAttributeType(idx))); + } + } + + for(size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) + { + switch(ifs.GetIntAttributeType(idx)) + { + // ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint))); + default: + throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + std::to_string(ifs.GetIntAttributeType(idx))); + } + } + + // // Decode data - if(decoder.DecodePlayload(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC data."); + // + if(decoder.DecodePayload(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC data."); - // Set encoded region for bufferView. - bufview->EncodedRegion_Mark(byte_offset, count, output_data, output_data_size, name); - // Ans set is current - bufview->EncodedRegion_SetCurrent(name); + // 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;" } diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index f30e8cf89..d76bb5df4 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -224,6 +224,11 @@ namespace glTF { 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" @@ -237,7 +242,7 @@ namespace glTF { break; default: - throw DeadlyImportError("GLTF: Unknown mesh extension, Only Open3DGC is supported."); + 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) diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 1dc35b5cd..48ab099ed 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -261,7 +261,7 @@ void glTFExporter::ExportMeshes() // using IndicesType = decltype(aiFace::mNumIndices); // But yes for // using IndicesType = unsigned short; -// because "ComponentType_UNSIGNED_SHORT" used for indices. And its maximal type according to glTF specification. +// because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification. using IndicesType = unsigned short; // Variables needed for compression. BEGIN. @@ -273,18 +273,26 @@ size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer. bool comp_allow;// Point that data of current mesh can be compressed. // Variables needed for compression. END. - for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { - const aiMesh* aim = mScene->mMeshes[i]; + for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) { + const aiMesh* aim = mScene->mMeshes[idx_mesh]; // Check if compressing requested and mesh can be encoded. - if((aim->mPrimitiveTypes == aiPrimitiveType_TRIANGLE) && (aim->mNumVertices > 0))///TODO: export properties if(compression is needed) + comp_allow = mProperties->GetPropertyBool("extensions.Open3DGC.use", false); + if(comp_allow && (aim->mPrimitiveTypes == aiPrimitiveType_TRIANGLE) && (aim->mNumVertices > 0) && (aim->mNumFaces > 0)) { - comp_allow = true; + idx_srcdata_tc.clear(); idx_srcdata_tc.reserve(AI_MAX_NUMBER_OF_TEXTURECOORDS); } else { - comp_allow = false; + 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); } std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh"); @@ -367,28 +375,30 @@ bool comp_allow;// Point that data of current mesh can be compressed. // // Fill data for encoder. // - unsigned qcoord = 12;///TODO: dbg - unsigned qnormal = 10;///TODO: dbg - unsigned qtexCoord = 10;///TODO: dbg + // 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); - o3dgc::O3DGCSC3DMCPredictionMode positionPrediction = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;///TODO: dbg - o3dgc::O3DGCSC3DMCPredictionMode normalPrediction = o3dgc::O3DGC_SC3DMC_SURF_NORMALS_PREDICTION;///TODO: dbg - o3dgc::O3DGCSC3DMCPredictionMode texcoordPrediction = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;///TODO: dbg + // 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(qcoord);///TODO: IME - comp_o3dgc_params.SetCoordPredMode(positionPrediction);///TODO: IME + 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(qnormal);///TODO: IME - comp_o3dgc_params.SetNormalPredMode(normalPrediction);///TODO: IME + 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]); } @@ -398,10 +408,10 @@ bool comp_allow;// Point that data of current mesh can be compressed. { size_t num = comp_o3dgc_ifs.GetNumFloatAttributes(); - comp_o3dgc_params.SetFloatAttributeQuantBits(num, qtexCoord);///TODO: IME - comp_o3dgc_params.SetFloatAttributePredMode(num, texcoordPrediction);///TODO: IME + 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[i]);// components per element: aiVector3D => x * float + 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); @@ -412,7 +422,12 @@ bool comp_allow;// Point that data of current mesh can be compressed. comp_o3dgc_ifs.SetCoordIndex((IndicesType* const)&b->GetPointer()[idx_srcdata_ind]); // Prepare to enconding comp_o3dgc_params.SetNumFloatAttributes(comp_o3dgc_ifs.GetNumFloatAttributes()); - comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_BINARY);///TODO: exporter params + 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 // @@ -429,14 +444,13 @@ bool comp_allow;// Point that data of current mesh can be compressed. ext->Buffer = b->id; ext->Offset = idx_srcdata_begin; ext->Count = b->byteLength - idx_srcdata_begin; - ext->IndicesCount = comp_o3dgc_ifs.GetNCoordIndex(); + 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); }// if(comp_allow) }// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { - - ///TODO: export properties if(compression is used) } unsigned int glTFExporter::ExportNode(const aiNode* n) diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index 5fdad1261..5cdd8562a 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -259,7 +259,36 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) for (unsigned int m = 0; m < r.meshes.Size(); ++m) { Mesh& mesh = r.meshes[m]; - meshOffsets.push_back(k); + // Check if mesh extensions is used + if(mesh.Extension.size() > 0) + { + for(Mesh::SExtension* cur_ext : mesh.Extension) + { + if(cur_ext->Type == Mesh::SExtension::EType::Compression_Open3DGC) + { + // Limitations for meshes when using Open3DGC-compression. + // It's a current limitation of sp... Specification have not this part still - about mesh compression. Why only one primitive? + // Because glTF is very flexibly. But in fact it ugly flexible. Every primitive can has own set of accessors and accessors can + // point to a-a-a-a-any part of buffer (thru bufferview ofcourse) and even to another buffer. We know that "Open3DGC-compression" + // is applicable only to part of buffer. As we can't guaranty continuity of the data for decoder, we will limit quantity of primitives. + // Yes indices, coordinates etc. still can br stored in different buffers, but with current specification it's a exporter problem. + // Also primitive can has only one of "POSITION", "NORMAL" and less then "AI_MAX_NUMBER_OF_TEXTURECOORDS" of "TEXCOORD". All accessor + // of primitive must point to one continuous region of the buffer. + if(mesh.primitives.size() > 2) throw DeadlyImportError("GLTF: When using Open3DGC compression then only one primitive per mesh are allowed."); + + Mesh::SCompression_Open3DGC* o3dgc_ext = (Mesh::SCompression_Open3DGC*)cur_ext; + Ref buf = r.buffers.Get(o3dgc_ext->Buffer); + + buf->EncodedRegion_SetCurrent(mesh.id); + } + else + { + throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension, only Open3DGC is supported."); + } + } + }// if(mesh.Extension.size() > 0) + + meshOffsets.push_back(k); k += unsigned(mesh.primitives.size()); for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { @@ -295,25 +324,13 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) Mesh::Primitive::Attributes& attr = prim.attributes; - // if "bufferView" of current accessor is containing encoded data then set ID of region. - if(attr.position[0]->bufferView->EncodedRegion_List.size() > 0) attr.position[0]->bufferView->EncodedRegion_SetCurrent(mesh.name); - if (attr.position.size() > 0 && attr.position[0]) { aim->mNumVertices = attr.position[0]->count; attr.position[0]->ExtractData(aim->mVertices); } - // if "bufferView" of current accessor is containing encoded data then set ID of region. - if(attr.normal[0]->bufferView->EncodedRegion_List.size() > 0) attr.normal[0]->bufferView->EncodedRegion_SetCurrent(mesh.name); - if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals); - // if "bufferView" of current accessor is containing encoded data then set ID of region. - if((attr.texcoord.size() > 0) && (attr.texcoord[0]->bufferView->EncodedRegion_List.size() > 0)) - { - attr.texcoord[0]->bufferView->EncodedRegion_SetCurrent(mesh.name); - } - for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); @@ -326,9 +343,6 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) if (prim.indices) { - // if "bufferView" of current accessor is containing encoded data then set ID of region. - if(prim.indices->bufferView->EncodedRegion_List.size() > 0) prim.indices->bufferView->EncodedRegion_SetCurrent(mesh.name); - aiFace* faces = 0; unsigned int nFaces = 0; From 1844665693139e941935e4ba2ce2ff54786a170e Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sat, 13 Aug 2016 16:09:21 +0300 Subject: [PATCH 14/32] [*] Few C++11 constructions are removed. --- code/glTFAsset.h | 3 ++- code/glTFAsset.inl | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 90335f52f..3adfb127b 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #define RAPIDJSON_HAS_STDSTRING 1 #include @@ -733,7 +734,7 @@ namespace glTF /// \struct SCompression_Open3DGC /// Compression of mesh data using Open3DGC algorythm. - struct SCompression_Open3DGC final : public SExtension + struct SCompression_Open3DGC : public SExtension { using SExtension::Type; diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 339717146..59ee79efe 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -343,7 +343,7 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod // Check offset if(pOffset > byteLength) { - constexpr uint8_t val_size = 32; + const uint8_t val_size = 32; char val[val_size]; @@ -354,7 +354,7 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod // Check length if((pOffset + pEncodedData_Length) > byteLength) { - constexpr uint8_t val_size = 64; + const uint8_t val_size = 64; char val[val_size]; From 8ab50aa9a03783f84cc389b00847e773e2688bf4 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sat, 13 Aug 2016 16:27:07 +0300 Subject: [PATCH 15/32] [*] Few C++11 constructions are removed. --- code/glTFAsset.inl | 2 +- code/glTFExporter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 59ee79efe..382b37d8e 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -883,7 +883,7 @@ mr_skip_extensions: inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root) { -using IndicesType = unsigned short;///< \sa glTFExporter::ExportMeshes. +typedef unsigned short IndicesType;///< \sa glTFExporter::ExportMeshes. o3dgc::SC3DMCDecoder decoder; o3dgc::IndexedFaceSet ifs; diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 48ab099ed..737985922 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -262,7 +262,7 @@ void glTFExporter::ExportMeshes() // But yes for // using IndicesType = unsigned short; // because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification. -using IndicesType = unsigned short; +typedef unsigned short IndicesType; // Variables needed for compression. BEGIN. // Indices, not pointers - because pointer to buffer is changin while writing to it. From 3a10a3cf039d5eff0285452f6023cbfdecbaa474 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sat, 13 Aug 2016 16:27:34 +0300 Subject: [PATCH 16/32] [-] Removed unneeded include. --- code/glTFAsset.h | 1 - 1 file changed, 1 deletion(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 3adfb127b..237158de8 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -54,7 +54,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #define RAPIDJSON_HAS_STDSTRING 1 #include From de70f5c028820a6c61c0dc0f7dd7e7d474c90014 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sat, 13 Aug 2016 17:44:58 +0300 Subject: [PATCH 17/32] [+] Added link to RT library when using Open3DGC-compression. --- code/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 23456d13d..44336b008 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,4 +1,4 @@ -# Open Asset Import Library (assimp) +# Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # # Copyright (c) 2006-2016, assimp team @@ -767,6 +767,10 @@ SET( assimp_src ) ADD_DEFINITIONS( -DOPENDDLPARSER_BUILD ) +if (open3dgc_SRCS) + SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -lrt") +endif (open3dgc_SRCS) + INCLUDE_DIRECTORIES( ../contrib/openddlparser/include ) From 48f8c117e2f301c03740c1f4679d5390cde60111 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sun, 14 Aug 2016 16:27:16 +0300 Subject: [PATCH 18/32] [F] Conditional compilation for Open3DGC-extension. [F] Flag comp_allow did not reset when mesh can not be encoded. --- code/CMakeLists.txt | 25 +++++++++++++--- code/glTFAsset.h | 62 +++++++++++++++++++++++----------------- code/glTFAsset.inl | 12 ++++++-- code/glTFAssetWriter.inl | 6 ++-- code/glTFExporter.cpp | 14 +++++++-- code/glTFImporter.cpp | 5 +++- 6 files changed, 85 insertions(+), 39 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 44336b008..1b964a31e 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -707,9 +707,25 @@ SET ( open3dgc_SRCS ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp ../contrib/Open3DGC/o3dgcTools.cpp ../contrib/Open3DGC/o3dgcTriangleFans.cpp + ../contrib/Open3DGC/o3dgcTimer.h ) 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) + ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC ) + IF (NOT RT_FOUND) + SET (RT_LIBRARY "") + ENDIF (NOT RT_FOUND) +ELSE () + SET (open3dgc_SRCS "") + SET (RT_LIBRARY "") + 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" ) @@ -767,10 +783,6 @@ SET( assimp_src ) ADD_DEFINITIONS( -DOPENDDLPARSER_BUILD ) -if (open3dgc_SRCS) - SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -lrt") -endif (open3dgc_SRCS) - INCLUDE_DIRECTORIES( ../contrib/openddlparser/include ) @@ -837,6 +849,11 @@ else (UNZIP_FOUND) INCLUDE_DIRECTORIES("../") endif (UNZIP_FOUND) +# Add RT-extension library for glTF importer with Open3DGC-compression. +IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) + TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY}) +ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) + INSTALL( TARGETS assimp LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 237158de8..f09e97902 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -716,9 +716,13 @@ namespace glTF { /// \enum EType /// Type of extension. - enum class EType + enum EType { - Compression_Open3DGC ///< Compression of mesh data using Open3DGC algorythm. + #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + Compression_Open3DGC,///< Compression of mesh data using Open3DGC algorythm. + #endif + + Unknown }; EType Type;///< Type of extension. @@ -731,27 +735,29 @@ namespace glTF {} }; - /// \struct SCompression_Open3DGC - /// Compression of mesh data using Open3DGC algorythm. - struct SCompression_Open3DGC : public SExtension - { - using SExtension::Type; + #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). + 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(EType::Compression_Open3DGC) - {} - }; + /// \fn SCompression_Open3DGC + /// Constructor. + SCompression_Open3DGC() + : SExtension(Compression_Open3DGC) + {} + }; + #endif std::vector primitives; std::list Extension;///< List of extensions used in mesh. @@ -760,7 +766,7 @@ namespace glTF /// \fn ~Mesh() /// Destructor. - ~Mesh() { for(auto e : Extension) { delete e; }; } + ~Mesh() { for(std::list::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { delete *it; }; } /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) /// Get mesh data from JSON-object and place them to root asset. @@ -768,11 +774,13 @@ namespace glTF /// \param [out] pAsset_Root - reference to root assed where data will be stored. void Read(Value& pJSON_Object, Asset& pAsset_Root); - /// \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); + #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 diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 382b37d8e..89d5611ce 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -43,8 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Header files, Assimp #include -// Header files, Open3DGC. -#include +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + // Header files, Open3DGC. +# include +#endif namespace glTF { @@ -820,7 +822,8 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++) { - if(it_memb->name.GetString() == std::string("Open3DGC-compression")) +#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 @@ -871,6 +874,7 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& 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() + "\"."); } @@ -881,6 +885,7 @@ 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. @@ -1038,6 +1043,7 @@ Ref buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer); // No. Do not delete "output_data". After calling "EncodedRegion_Mark" bufferView is owner of "output_data". // "delete [] output_data;" } +#endif inline void Camera::Read(Value& obj, Asset& r) { diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index d76bb5df4..78bc759ba 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -60,7 +60,7 @@ namespace glTF { val.PushBack(r[i], al); } return val; - }; + } template inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref >& v, MemoryPoolAllocator<>& al) { @@ -72,7 +72,7 @@ namespace glTF { lst.PushBack(StringRef(v[i]->id), al); } obj.AddMember(StringRef(fieldId), lst, al); - }; + } } @@ -212,6 +212,7 @@ namespace glTF { { switch(ptr_ext->Type) { +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC case Mesh::SExtension::EType::Compression_Open3DGC: { Value json_comp_data; @@ -241,6 +242,7 @@ namespace glTF { } break; +#endif default: throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported."); }// switch(ptr_ext->Type) diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 737985922..fb601835f 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -61,8 +61,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "glTFAssetWriter.h" -// Header files, Open3DGC. -#include +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + // Header files, Open3DGC. +# include +#endif using namespace rapidjson; @@ -277,7 +279,12 @@ bool comp_allow;// Point that data of current mesh can be compressed. 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(); @@ -293,6 +300,7 @@ bool comp_allow;// Point that data of current mesh can be compressed. 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"); @@ -365,6 +373,7 @@ bool comp_allow;// Point that data of current mesh can be compressed. ///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; @@ -449,6 +458,7 @@ bool comp_allow;// Point that data of current mesh can be compressed. 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) { } diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index 5cdd8562a..04442960b 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -264,6 +264,7 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) { 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. @@ -282,8 +283,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) buf->EncodedRegion_SetCurrent(mesh.id); } else +#endif { - throw DeadlyImportError("GLTF: Can not import mesh: unknown mesh extension, only Open3DGC is supported."); + 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) From 2732e5d9b6e9860bc5a4f736f6457d2075fce4bf Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sun, 14 Aug 2016 19:49:05 +0300 Subject: [PATCH 19/32] [F] Removed Unicode BOM. --- code/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 176a1fd18..83ced2407 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,4 +1,4 @@ -# Open Asset Import Library (assimp) +# Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # # Copyright (c) 2006-2016, assimp team From d49ad6c93ee1eaf4cbce3fc49320f70516c724c0 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Fri, 9 Sep 2016 16:38:43 +0300 Subject: [PATCH 20/32] [*] Stylistic changes. [F] Added all files from Open3DGC codec to CMakeLists.txt --- code/CMakeLists.txt | 27 +++++++++++++++++++++++++-- code/glTFAsset.inl | 5 +++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 83ced2407..a9d8458a5 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,4 +1,4 @@ -# Open Asset Import Library (assimp) +# Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # # Copyright (c) 2006-2016, assimp team @@ -702,12 +702,35 @@ SET ( openddl_parser_SRCS SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS}) SET ( open3dgc_SRCS + ../contrib/Open3DGC/o3dgcAdjacencyInfo.h ../contrib/Open3DGC/o3dgcArithmeticCodec.cpp + ../contrib/Open3DGC/o3dgcArithmeticCodec.h + ../contrib/Open3DGC/o3dgcBinaryStream.h + ../contrib/Open3DGC/o3dgcCommon.h + ../contrib/Open3DGC/o3dgcDVEncodeParams.h ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp + ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.h ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp + ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.h + ../contrib/Open3DGC/o3dgcDynamicVector.h + ../contrib/Open3DGC/o3dgcFIFO.h + ../contrib/Open3DGC/o3dgcIndexedFaceSet.h + ../contrib/Open3DGC/o3dgcIndexedFaceSet.inl + ../contrib/Open3DGC/o3dgcSC3DMCDecoder.h + ../contrib/Open3DGC/o3dgcSC3DMCDecoder.inl + ../contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h + ../contrib/Open3DGC/o3dgcSC3DMCEncoder.h + ../contrib/Open3DGC/o3dgcSC3DMCEncoder.inl + ../contrib/Open3DGC/o3dgcTimer.h ../contrib/Open3DGC/o3dgcTools.cpp ../contrib/Open3DGC/o3dgcTriangleFans.cpp - ../contrib/Open3DGC/o3dgcTimer.h + ../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}) diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 89d5611ce..486f963c2 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -489,9 +489,10 @@ inline uint8_t* Accessor::GetPointer() if(bufferView->buffer->EncodedRegion_Current != nullptr) { const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset; - const size_t end = bufferView->buffer->EncodedRegion_Current->Offset + bufferView->buffer->EncodedRegion_Current->DecodedData_Length; + const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length; - if((offset >= begin) && (offset < end)) return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin]; + if((offset >= begin) && (offset < end)) + return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin]; } return basePtr + offset; From d97f00571e207dc3a117f549179f47533de43f9b Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sat, 10 Sep 2016 09:07:50 +0300 Subject: [PATCH 21/32] [*] Not needed namespace. --- code/glTFAsset.inl | 2 +- code/glTFImporter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index ec6f7fe60..b9f3fccd8 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -835,7 +835,7 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\"."); - Assimp::DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data."); + DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data."); /************** Read data from JSON-document **************/ #define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \ diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index 734a827de..288cfd883 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -672,7 +672,7 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS // TODO: it does not split the loaded vertices, should it? //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; - Assimp::MakeVerboseFormatProcess process; + MakeVerboseFormatProcess process; process.Execute(pScene); From 5fe32caa6d6b1fe4e291ed8c335c6482363b0459 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sat, 10 Sep 2016 09:14:28 +0300 Subject: [PATCH 22/32] Merge branch 'master' into gltf_o3dgc --- code/CMakeLists.txt | 1 + code/D3MFImporter.cpp | 47 ++++++++++++++++++++----------------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index a9d8458a5..42d3e48bc 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -617,6 +617,7 @@ ADD_ASSIMP_IMPORTER( 3MF D3MFOpcPackage.h D3MFOpcPackage.cpp ) +SOURCE_GROUP( 3MF FILES ${(3MF_SRCS}) SET( Step_SRCS diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index 1a9716828..39fdd1b32 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -66,35 +66,32 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER namespace Assimp { - namespace D3MF { namespace XmlTag { - - const std::string model = "model"; - const std::string metadata = "metadata"; - const std::string resources = "resources"; - const std::string object = "object"; - const std::string mesh = "mesh"; - const std::string vertices = "vertices"; - const std::string vertex = "vertex"; - const std::string triangles = "triangles"; - const std::string triangle = "triangle"; - const std::string x = "x"; - const std::string y = "y"; - const std::string z = "z"; - const std::string v1 = "v1"; - const std::string v2 = "v2"; - const std::string v3 = "v3"; - const std::string id = "id"; - const std::string name = "name"; - const std::string type = "type"; - const std::string build = "build"; - const std::string item = "item"; - const std::string objectid = "objectid"; - const std::string transform = "transform"; - + static const std::string model = "model"; + static const std::string metadata = "metadata"; + static const std::string resources = "resources"; + static const std::string object = "object"; + static const std::string mesh = "mesh"; + static const std::string vertices = "vertices"; + static const std::string vertex = "vertex"; + static const std::string triangles = "triangles"; + static const std::string triangle = "triangle"; + static const std::string x = "x"; + static const std::string y = "y"; + static const std::string z = "z"; + static const std::string v1 = "v1"; + static const std::string v2 = "v2"; + static const std::string v3 = "v3"; + static const std::string id = "id"; + static const std::string name = "name"; + static const std::string type = "type"; + static const std::string build = "build"; + static const std::string item = "item"; + static const std::string objectid = "objectid"; + static const std::string transform = "transform"; } From 7212ad9f0ec062df332655439d3a3c7dc22c2f5c Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Sat, 10 Sep 2016 09:16:47 +0300 Subject: [PATCH 23/32] [+] FindRT cmake module. --- cmake-modules/FindRT.cmake | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 cmake-modules/FindRT.cmake diff --git a/cmake-modules/FindRT.cmake b/cmake-modules/FindRT.cmake new file mode 100644 index 000000000..17d5df81d --- /dev/null +++ b/cmake-modules/FindRT.cmake @@ -0,0 +1,20 @@ +# Try to find real time libraries +# Once done, this will define +# +# RT_FOUND - system has rt library +# RT_LIBRARIES - rt libraries directory +# +# Source: https://gitlab.cern.ch/dss/eos/commit/44070e575faaa46bd998708ef03eedb381506ff0 +# + +if(RT_LIBRARIES) + set(RT_FIND_QUIETLY TRUE) +endif(RT_LIBRARIES) + +find_library(RT_LIBRARY rt) +set(RT_LIBRARIES ${RT_LIBRARY}) +# handle the QUIETLY and REQUIRED arguments and set +# RT_FOUND to TRUE if all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(rt DEFAULT_MSG RT_LIBRARY) +mark_as_advanced(RT_LIBRARY) From 40cfb45c74ab447092029b463d991ea1bda2d414 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Tue, 13 Sep 2016 13:29:12 +0300 Subject: [PATCH 24/32] [F] Not set option-variable (only define for compilation was set. [F] For adding library can not be used TARGET_LINK_LIBRARIES --- code/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 95f796648..bc10d5c48 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -737,7 +737,8 @@ SOURCE_GROUP( open3dgc FILES ${open3dgc_SRCS}) # has implementation for different platforms: WIN32, __MACH__ and other ("else" block). FIND_PACKAGE(RT QUIET) IF (RT_FOUND OR MSVC) - ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC ) + SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 ) + ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 ) IF (NOT RT_FOUND) SET (RT_LIBRARY "") ENDIF (NOT RT_FOUND) @@ -873,7 +874,7 @@ 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}) + SET_PROPERTY(TARGET assimp APPEND PROPERTY LINK_FLAGS ${RT_LIBRARY}) ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) INSTALL( TARGETS assimp From 8b3f348d6308591044d9b61ae77f5b99057c08ec Mon Sep 17 00:00:00 2001 From: johnmaf Date: Wed, 14 Sep 2016 18:03:52 -0400 Subject: [PATCH 25/32] Flip UVs in glTFExporter --- code/glTFExporter.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index e333272be..b610e00fd 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -291,6 +291,13 @@ void glTFExporter::ExportMeshes() if (n) p.attributes.normal.push_back(n); 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) { AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3; Ref tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true); From 65048d1ef7bdb841473844ab4c929280e9cc7ed7 Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Thu, 15 Sep 2016 14:45:00 +0300 Subject: [PATCH 26/32] [F] Removed Unicode BOM at file beginning. --- code/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index bc10d5c48..3655a0908 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,4 +1,4 @@ -# Open Asset Import Library (assimp) +# Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # # Copyright (c) 2006-2016, assimp team From cd038209dd9cc2d75ce59c0e01ff79a88fa60353 Mon Sep 17 00:00:00 2001 From: johnmaf Date: Wed, 14 Sep 2016 18:14:23 -0400 Subject: [PATCH 27/32] Add all glTF data to single buffer --- code/glTFExporter.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index e333272be..960dd3b11 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -267,6 +267,13 @@ void glTFExporter::ExportMaterials() void glTFExporter::ExportMeshes() { + std::string bufferId = mAsset->FindUniqueID("", "buffer"); + + Ref b = mAsset->GetBodyBuffer(); + if (!b) { + b = mAsset->buffers.Create(bufferId); + } + for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { const aiMesh* aim = mScene->mMeshes[i]; @@ -277,13 +284,6 @@ void glTFExporter::ExportMeshes() p.material = mAsset->materials.Get(aim->mMaterialIndex); - std::string bufferId = mAsset->FindUniqueID(meshId, "buffer"); - - Ref b = mAsset->GetBodyBuffer(); - if (!b) { - b = mAsset->buffers.Create(bufferId); - } - Ref v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if (v) p.attributes.position.push_back(v); From a9284e5a95f5b4216b8d231984ed7875005082bc Mon Sep 17 00:00:00 2001 From: Alexandr Arutjunov Date: Thu, 15 Sep 2016 20:39:39 +0300 Subject: [PATCH 28/32] [F] Removed unneeded definitions. [F] Add library for linker. --- code/CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 3655a0908..b1e0256ca 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -739,12 +739,8 @@ FIND_PACKAGE(RT QUIET) IF (RT_FOUND OR MSVC) SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 ) ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 ) - IF (NOT RT_FOUND) - SET (RT_LIBRARY "") - ENDIF (NOT RT_FOUND) ELSE () SET (open3dgc_SRCS "") - SET (RT_LIBRARY "") 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 () @@ -874,7 +870,7 @@ endif (UNZIP_FOUND) # Add RT-extension library for glTF importer with Open3DGC-compression. IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) - SET_PROPERTY(TARGET assimp APPEND PROPERTY LINK_FLAGS ${RT_LIBRARY}) + TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY}) ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) INSTALL( TARGETS assimp From dad4d0fa991247fa7ff16c385988b7fd7f41e076 Mon Sep 17 00:00:00 2001 From: smalcom Date: Thu, 15 Sep 2016 22:25:34 +0300 Subject: [PATCH 29/32] [F] min/max redefined when including windows.h --- contrib/Open3DGC/o3dgcTimer.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/Open3DGC/o3dgcTimer.h b/contrib/Open3DGC/o3dgcTimer.h index 303d4f790..97f575931 100644 --- a/contrib/Open3DGC/o3dgcTimer.h +++ b/contrib/Open3DGC/o3dgcTimer.h @@ -27,6 +27,8 @@ THE SOFTWARE. #include "o3dgcCommon.h" #ifdef WIN32 +/* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */ +#define NOMINMAX #include #elif __MACH__ #include From 3c827f29f652f102dc620d3c4f283db4d38cec4b Mon Sep 17 00:00:00 2001 From: johnmaf Date: Mon, 19 Sep 2016 17:44:38 -0400 Subject: [PATCH 30/32] Export glTF buffers as separate .bin files --- code/glTFAsset.h | 3 ++ code/glTFAssetWriter.h | 1 + code/glTFAssetWriter.inl | 70 +++++++++++++++++++++++++--------------- code/glTFExporter.cpp | 24 ++++++++------ 4 files changed, 63 insertions(+), 35 deletions(-) diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 6d5ac1a71..022774779 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -489,6 +489,9 @@ namespace glTF bool IsSpecial() const { return mIsSpecial; } + std::string GetURI() + { return std::string(this->id) + ".bin"; } + static const char* TranslateId(Asset& r, const char* id); }; diff --git a/code/glTFAssetWriter.h b/code/glTFAssetWriter.h index 370d2c0ab..4d2d3c919 100644 --- a/code/glTFAssetWriter.h +++ b/code/glTFAssetWriter.h @@ -79,6 +79,7 @@ public: AssetWriter(Asset& asset); void WriteFile(const char* path); + void WriteGLBFile(const char* path); }; } diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index 415db6714..6302ab3c3 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -94,9 +94,6 @@ namespace glTF { inline void Write(Value& obj, Buffer& b, AssetWriter& w) { - std::string dataURI = "data:application/octet-stream;base64,"; - Util::EncodeBase64(b.GetPointer(), b.byteLength, dataURI); - const char* type; switch (b.type) { case Buffer::Type_text: @@ -107,7 +104,7 @@ namespace glTF { obj.AddMember("byteLength", static_cast(b.byteLength), w.mAl); obj.AddMember("type", StringRef(type), w.mAl); - obj.AddMember("uri", Value(dataURI, w.mAl).Move(), w.mAl); + obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl); } inline void Write(Value& obj, BufferView& bv, AssetWriter& w) @@ -328,39 +325,61 @@ namespace glTF { inline void AssetWriter::WriteFile(const char* path) { - bool isBinary = mAsset.extensionsUsed.KHR_binary_glTF; + std::unique_ptr jsonOutFile(mAsset.OpenFile(path, "wt", true)); - std::unique_ptr outfile - (mAsset.OpenFile(path, isBinary ? "wb" : "wt", true)); + if (jsonOutFile == 0) { + throw DeadlyExportError("Could not open output file: " + std::string(path)); + } + + StringBuffer docBuffer; + + PrettyWriter writer(docBuffer); + mDoc.Accept(writer); + + if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { + throw DeadlyExportError("Failed to write scene data!"); + } + + // Write buffer data to separate .bin files + for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) { + Ref b = mAsset.buffers.Get(i); + + std::string binPath = b->GetURI(); + + std::unique_ptr binOutFile(mAsset.OpenFile(binPath, "wb", true)); + + if (binOutFile == 0) { + throw DeadlyExportError("Could not open output file: " + binPath); + } + + if (b->byteLength > 0) { + if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) { + throw DeadlyExportError("Failed to write binary file: " + binPath); + } + } + } + } + + inline void AssetWriter::WriteGLBFile(const char* path) + { + std::unique_ptr outfile(mAsset.OpenFile(path, "wb", true)); if (outfile == 0) { throw DeadlyExportError("Could not open output file: " + std::string(path)); } - if (isBinary) { - // we will write the header later, skip its size - outfile->Seek(sizeof(GLB_Header), aiOrigin_SET); - } + // we will write the header later, skip its size + outfile->Seek(sizeof(GLB_Header), aiOrigin_SET); StringBuffer docBuffer; - - bool pretty = true; - if (!isBinary && pretty) { - PrettyWriter writer(docBuffer); - mDoc.Accept(writer); - } - else { - Writer writer(docBuffer); - mDoc.Accept(writer); - } + Writer writer(docBuffer); + mDoc.Accept(writer); if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { - throw DeadlyExportError("Failed to write scene data!"); + throw DeadlyExportError("Failed to write scene data!"); } - if (isBinary) { - WriteBinaryData(outfile.get(), docBuffer.GetSize()); - } + WriteBinaryData(outfile.get(), docBuffer.GetSize()); } inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength) @@ -385,7 +404,6 @@ namespace glTF { } } - // // write the header // diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index e333272be..e2681d0f1 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -137,9 +137,13 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc ExportScene(); - glTF::AssetWriter writer(*mAsset); - writer.WriteFile(filename); + + if (isBinary) { + writer.WriteGLBFile(filename); + } else { + writer.WriteFile(filename); + } } @@ -267,6 +271,15 @@ void glTFExporter::ExportMaterials() void glTFExporter::ExportMeshes() { + std::string fname = std::string(mFilename); + std::string bufferIdPrefix = fname.substr(0, fname.find(".")); + std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str()); + + Ref b = mAsset->GetBodyBuffer(); + if (!b) { + b = mAsset->buffers.Create(bufferId); + } + for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) { const aiMesh* aim = mScene->mMeshes[i]; @@ -277,13 +290,6 @@ void glTFExporter::ExportMeshes() p.material = mAsset->materials.Get(aim->mMaterialIndex); - std::string bufferId = mAsset->FindUniqueID(meshId, "buffer"); - - Ref b = mAsset->GetBodyBuffer(); - if (!b) { - b = mAsset->buffers.Create(bufferId); - } - Ref v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if (v) p.attributes.position.push_back(v); From 3052f35824eb98f3a26ed89a9215622a41343025 Mon Sep 17 00:00:00 2001 From: johnmaf Date: Tue, 20 Sep 2016 14:15:42 -0400 Subject: [PATCH 31/32] glTF: move mesh splitting to constructor to cover GLB --- code/glTFExporter.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 45877c8a9..708570577 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -80,20 +80,9 @@ namespace Assimp { // Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) { - aiScene* sceneCopy_tmp; - SceneCombiner::CopyScene(&sceneCopy_tmp, pScene); - std::unique_ptr sceneCopy(sceneCopy_tmp); - - SplitLargeMeshesProcess_Triangle tri_splitter; - tri_splitter.SetLimit(0xffff); - tri_splitter.Execute(sceneCopy.get()); - - SplitLargeMeshesProcess_Vertex vert_splitter; - vert_splitter.SetLimit(0xffff); - vert_splitter.Execute(sceneCopy.get()); // invoke the exporter - glTFExporter exporter(pFile, pIOSystem, sceneCopy.get(), pProperties, false); + glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false); } // ------------------------------------------------------------------------------------------------ @@ -112,9 +101,22 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc const ExportProperties* pProperties, bool isBinary) : mFilename(filename) , mIOSystem(pIOSystem) - , mScene(pScene) , mProperties(pProperties) { + aiScene* sceneCopy_tmp; + SceneCombiner::CopyScene(&sceneCopy_tmp, pScene); + std::unique_ptr sceneCopy(sceneCopy_tmp); + + SplitLargeMeshesProcess_Triangle tri_splitter; + tri_splitter.SetLimit(0xffff); + tri_splitter.Execute(sceneCopy.get()); + + SplitLargeMeshesProcess_Vertex vert_splitter; + vert_splitter.SetLimit(0xffff); + vert_splitter.Execute(sceneCopy.get()); + + mScene = sceneCopy.get(); + std::unique_ptr asset(); mAsset.reset( new glTF::Asset( pIOSystem ) ); From 0277a23521b2325a28e6f1ea0d097e1f6c299f33 Mon Sep 17 00:00:00 2001 From: johnmaf Date: Wed, 21 Sep 2016 11:33:02 -0400 Subject: [PATCH 32/32] Add Triangulate post-processing step to glTF exporters --- code/Exporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/Exporter.cpp b/code/Exporter.cpp index e510b7642..33ece5297 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -139,9 +139,9 @@ Exporter::ExportFormatEntry gExporters[] = #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, - aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/), + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate /*| aiProcess_SortByPType*/), Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, - aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/), + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate /*| aiProcess_SortByPType*/), #endif #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER