new stuff

This commit is contained in:
Tarion 2026-07-03 03:41:25 +02:00
parent 8998bc3936
commit 64c8492e5c
No known key found for this signature in database
6907 changed files with 3401899 additions and 0 deletions

View file

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

View file

@ -0,0 +1,863 @@
/*
Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// **************************** -
// ARITHMETIC CODING EXAMPLES -
// **************************** -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// Fast arithmetic coding implementation -
// -> 32-bit variables, 32-bit product, periodic updates, table decoding -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// Version 1.00 - April 25, 2004 -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// WARNING -
// ========= -
// -
// The only purpose of this program is to demonstrate the basic principles -
// of arithmetic coding. It is provided as is, without any express or -
// implied warranty, without even the warranty of fitness for any particular -
// purpose, or that the implementations are correct. -
// -
// Permission to copy and redistribute this code is hereby granted, provided -
// that this warning and copyright notices are not removed or altered. -
// -
// Copyright (c) 2004 by Amir Said (said@ieee.org) & -
// William A. Pearlman (pearlw@ecse.rpi.edu) -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// A description of the arithmetic coding method used here is available in -
// -
// Lossless Compression Handbook, ed. K. Sayood -
// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
// -
// A. Said, Introduction to Arithetic Coding Theory and Practice -
// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Inclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include <stdlib.h>
#include "o3dgcArithmeticCodec.h"
namespace o3dgc
{
// - - Constants - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const unsigned AC__MinLength = 0x01000000U; // threshold for renormalization
const unsigned AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length
// Maximum values for binary models
const unsigned BM__LengthShift = 13; // length bits discarded before mult.
const unsigned BM__MaxCount = 1 << BM__LengthShift; // for adaptive models
// Maximum values for general models
const unsigned DM__LengthShift = 15; // length bits discarded before mult.
const unsigned DM__MaxCount = 1 << DM__LengthShift; // for adaptive models
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Static functions - - - - - - - - - - - - - - - - - - - - - - - - - - -
AI_WONT_RETURN static void AC_Error(const char * msg) AI_WONT_RETURN_SUFFIX;
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
new_buffer = new unsigned char[buffer_size+16]; // 16 extra bytes
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];
}
}
// 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;
}
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);
}
assert(total_count > 0);
// 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 {
assert(decoder_table);
for (k = 0; k < data_symbols; k++) {
distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
sum += symbol_count[k];
unsigned w = distribution[k] >> table_shift;
while (s < w) decoder_table[++s] = k - 1;
}
decoder_table[0] = 0;
while (s <= table_size) decoder_table[++s] = data_symbols - 1;
}
// set frequency of model updates
update_cycle = (5 * update_cycle) >> 2;
unsigned max_cycle = (data_symbols + 6) << 3;
if (update_cycle > max_cycle) update_cycle = max_cycle;
symbols_until_update = update_cycle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Data_Model::reset(void)
{
if (data_symbols == 0) return;
// restore probability estimates to uniform distribution
total_count = 0;
update_cycle = data_symbols;
for (unsigned k = 0; k < data_symbols; k++) symbol_count[k] = 1;
update(false);
symbols_until_update = update_cycle = (data_symbols + 6) >> 1;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,861 @@
/*
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"
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning( disable : 4456)
#endif // _MSC_VER
//#define DEBUG_VERBOSE
namespace o3dgc
{
#ifdef DEBUG_VERBOSE
FILE * g_fileDebugSC3DMCDec = NULL;
#endif //DEBUG_VERBOSE
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodeHeader(IndexedFaceSet<T> & ifs,
const BinaryStream & bstream)
{
unsigned long iterator0 = m_iterator;
unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY);
if (start_code != O3DGC_SC3DMC_START_CODE)
{
m_iterator = iterator0;
start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII);
if (start_code != O3DGC_SC3DMC_START_CODE)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
else
{
m_streamType = O3DGC_STREAM_TYPE_ASCII;
}
}
else
{
m_streamType = O3DGC_STREAM_TYPE_BINARY;
}
m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType);
m_params.SetEncodeMode( (O3DGCSC3DMCEncodingMode) bstream.ReadUChar(m_iterator, m_streamType));
ifs.SetCreaseAngle((Real) bstream.ReadFloat32(m_iterator, m_streamType));
unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType);
ifs.SetCCW ((mask & 1) == 1);
// (mask & 2) == 1
ifs.SetSolid (false);
// (mask & 4) == 1
ifs.SetConvex (false);
// (mask & 8) == 1
ifs.SetIsTriangularMesh(false);
//bool markerBit0 = (mask & 16 ) == 1;
//bool markerBit1 = (mask & 32 ) == 1;
//bool markerBit2 = (mask & 64 ) == 1;
//bool markerBit3 = (mask & 128) == 1;
ifs.SetNCoord (bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetNNormal (bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetNumFloatAttributes(bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetNumIntAttributes (bstream.ReadUInt32(m_iterator, m_streamType));
if (ifs.GetNCoord() > 0)
{
ifs.SetNCoordIndex(bstream.ReadUInt32(m_iterator, m_streamType));
for(int j=0 ; j<3 ; ++j)
{
ifs.SetCoordMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
ifs.SetCoordMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
}
m_params.SetCoordQuantBits( bstream.ReadUChar(m_iterator, m_streamType) );
}
if (ifs.GetNNormal() > 0)
{
ifs.SetNNormalIndex(bstream.ReadUInt32(m_iterator, m_streamType));
for(int j=0 ; j<3 ; ++j)
{
ifs.SetNormalMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
ifs.SetNormalMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
}
ifs.SetNormalPerVertex(bstream.ReadUChar(m_iterator, m_streamType) == 1);
m_params.SetNormalQuantBits(bstream.ReadUChar(m_iterator, m_streamType));
}
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
ifs.SetNFloatAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType));
if (ifs.GetNFloatAttribute(a) > 0)
{
ifs.SetNFloatAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType));
unsigned char d = bstream.ReadUChar(m_iterator, m_streamType);
ifs.SetFloatAttributeDim(a, d);
for(unsigned char j = 0 ; j < d ; ++j)
{
ifs.SetFloatAttributeMin(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
ifs.SetFloatAttributeMax(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
}
ifs.SetFloatAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1);
ifs.SetFloatAttributeType(a, (O3DGCIFSFloatAttributeType) bstream.ReadUChar(m_iterator, m_streamType));
m_params.SetFloatAttributeQuantBits(a, bstream.ReadUChar(m_iterator, m_streamType));
}
}
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
ifs.SetNIntAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType));
if (ifs.GetNIntAttribute(a) > 0)
{
ifs.SetNIntAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetIntAttributeDim(a, bstream.ReadUChar(m_iterator, m_streamType));
ifs.SetIntAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1);
ifs.SetIntAttributeType(a, (O3DGCIFSIntAttributeType) bstream.ReadUChar(m_iterator, m_streamType));
}
}
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodePayload(IndexedFaceSet<T> & ifs,
const BinaryStream & bstream)
{
O3DGCErrorCode ret = O3DGC_OK;
#ifdef DEBUG_VERBOSE
g_fileDebugSC3DMCDec = fopen("tfans_dec_main.txt", "w");
#endif //DEBUG_VERBOSE
m_triangleListDecoder.SetStreamType(m_streamType);
m_stats.m_streamSizeCoordIndex = m_iterator;
Timer timer;
timer.Tic();
m_triangleListDecoder.Decode(ifs.GetCoordIndex(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream, m_iterator);
timer.Toc();
m_stats.m_timeCoordIndex = timer.GetElapsedTime();
m_stats.m_streamSizeCoordIndex = m_iterator - m_stats.m_streamSizeCoordIndex;
// decode coord
m_stats.m_streamSizeCoord = m_iterator;
timer.Tic();
if (ifs.GetNCoord() > 0)
{
ret = DecodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(),
m_params.GetCoordQuantBits(), ifs, m_params.GetCoordPredMode(), bstream);
}
if (ret != O3DGC_OK)
{
return ret;
}
timer.Toc();
m_stats.m_timeCoord = timer.GetElapsedTime();
m_stats.m_streamSizeCoord = m_iterator - m_stats.m_streamSizeCoord;
// decode Normal
m_stats.m_streamSizeNormal = m_iterator;
timer.Tic();
if (ifs.GetNNormal() > 0)
{
DecodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(),
m_params.GetNormalQuantBits(), ifs, m_params.GetNormalPredMode(), bstream);
}
if (ret != O3DGC_OK)
{
return ret;
}
timer.Toc();
m_stats.m_timeNormal = timer.GetElapsedTime();
m_stats.m_streamSizeNormal = m_iterator - m_stats.m_streamSizeNormal;
// decode FloatAttributes
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
m_stats.m_streamSizeFloatAttribute[a] = m_iterator;
timer.Tic();
DecodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a),
ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a),
m_params.GetFloatAttributeQuantBits(a), ifs, m_params.GetFloatAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeFloatAttribute[a] = m_iterator - m_stats.m_streamSizeFloatAttribute[a];
}
if (ret != O3DGC_OK)
{
return ret;
}
// decode IntAttributes
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
m_stats.m_streamSizeIntAttribute[a] = m_iterator;
timer.Tic();
DecodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), ifs.GetIntAttributeDim(a),
ifs, m_params.GetIntAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeIntAttribute[a] = m_iterator - m_stats.m_streamSizeIntAttribute[a];
}
if (ret != O3DGC_OK)
{
return ret;
}
timer.Tic();
m_triangleListDecoder.Reorder();
timer.Toc();
m_stats.m_timeReorder = timer.GetElapsedTime();
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugSC3DMCDec);
#endif //DEBUG_VERBOSE
return ret;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodeIntArray(long * const intArray,
unsigned long numIntArray,
unsigned long dimIntArray,
unsigned long stride,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode & predMode,
const BinaryStream & bstream)
{
assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual;
SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
Arithmetic_Codec acd;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
unsigned long nPred;
const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numIntArray;
unsigned char * buffer = 0;
unsigned long start = m_iterator;
unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size
unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType);
O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7);
predMode = (O3DGCSC3DMCPredictionMode)(mask & 7);
streamSize -= (m_iterator - start);
unsigned long iteratorPred = m_iterator + streamSize;
unsigned int exp_k = 0;
unsigned int M = 0;
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.GetBuffer(m_iterator, buffer);
m_iterator += streamSize;
acd.set_buffer(streamSize, buffer);
acd.start_decoder();
exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
M = acd.ExpGolombDecode(0, bModel0, bModel1);
}
else
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size
}
Adaptive_Data_Model mModelValues(M+2);
#ifdef DEBUG_VERBOSE
printf("IntArray (%i, %i)\n", numIntArray, dimIntArray);
fprintf(g_fileDebugSC3DMCDec, "IntArray (%i, %i)\n", numIntArray, dimIntArray);
#endif //DEBUG_VERBOSE
for (long v=0; v < nvert; ++v)
{
nPred = 0;
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if (ta < 0)
{
break;
}
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( w < v )
{
SC3DMCTriplet id = {-1, -1, w};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
m_neighbors[p].m_pred[i] = intArray[w*stride+i];
}
}
}
}
}
}
if (nPred > 1)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", v);
fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v);
for (unsigned long p = 0; p < nPred; ++p)
{
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
for (unsigned long i = 0; i < dimIntArray; ++i)
{
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
}
}
#endif //DEBUG_VERBOSE
unsigned long bestPred;
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bestPred = bstream.ReadUCharASCII(iteratorPred);
}
else
{
bestPred = acd.decode(mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
for (unsigned long i = 0; i < dimIntArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
intArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
}
}
else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
intArray[v*stride+i] = predResidual + intArray[(v-1)*stride+i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadUIntASCII(m_iterator);
}
else
{
predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
intArray[v*stride+i] = predResidual;
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
m_iterator = iteratorPred;
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCDec);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCDecoder<T>::ProcessNormals(const IndexedFaceSet<T> & ifs)
{
const long nvert = (long) ifs.GetNNormal();
const unsigned long normalSize = ifs.GetNNormal() * 2;
if (m_normalsSize < normalSize)
{
delete [] m_normals;
m_normalsSize = normalSize;
m_normals = new Real [normalSize];
}
const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle();
const T * const triangles = ifs.GetCoordIndex();
Vec3<long> p1, p2, p3, n0, nt;
long na0 = 0, nb0 = 0;
Real rna0, rnb0, norm0;
char ni0 = 0, ni1 = 0;
long a, b, c;
for (long v=0; v < nvert; ++v)
{
n0.X() = 0;
n0.Y() = 0;
n0.Z() = 0;
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if (ta == -1)
{
break;
}
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
c = triangles[ta*3 + 2];
p1.X() = m_quantFloatArray[3*a];
p1.Y() = m_quantFloatArray[3*a+1];
p1.Z() = m_quantFloatArray[3*a+2];
p2.X() = m_quantFloatArray[3*b];
p2.Y() = m_quantFloatArray[3*b+1];
p2.Z() = m_quantFloatArray[3*b+2];
p3.X() = m_quantFloatArray[3*c];
p3.Y() = m_quantFloatArray[3*c+1];
p3.Z() = m_quantFloatArray[3*c+2];
nt = (p2-p1)^(p3-p1);
n0 += nt;
}
norm0 = (Real) n0.GetNorm();
if (norm0 == 0.0)
{
norm0 = 1.0;
}
SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0);
rna0 = na0 / norm0;
rnb0 = nb0 / norm0;
ni1 = ni0 + m_orientation[v];
m_orientation[v] = ni1;
if ( (ni1 >> 1) != (ni0 >> 1) )
{
rna0 = Real(0.0);
rnb0 = Real(0.0);
}
m_normals[2*v] = rna0;
m_normals[2*v+1] = rnb0;
#ifdef DEBUG_VERBOSE1
printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
fprintf(g_fileDebugSC3DMCDec, "n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
#endif //DEBUG_VERBOSE
}
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodeFloatArray(Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode & predMode,
const BinaryStream & bstream)
{
assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual;
SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
Arithmetic_Codec acd;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
unsigned long nPred;
const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numFloatArray;
const unsigned long size = numFloatArray * dimFloatArray;
unsigned char * buffer = 0;
unsigned long start = m_iterator;
unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size
unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType);
O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7);
predMode = (O3DGCSC3DMCPredictionMode)(mask & 7);
streamSize -= (m_iterator - start);
unsigned long iteratorPred = m_iterator + streamSize;
unsigned int exp_k = 0;
unsigned int M = 0;
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.GetBuffer(m_iterator, buffer);
m_iterator += streamSize;
acd.set_buffer(streamSize, buffer);
acd.start_decoder();
exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
M = acd.ExpGolombDecode(0, bModel0, bModel1);
}
else
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size
}
Adaptive_Data_Model mModelValues(M+2);
if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
m_orientation.Allocate(size);
m_orientation.Clear();
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
for(unsigned long i = 0; i < numFloatArray; ++i)
{
m_orientation.PushBack((unsigned char) bstream.ReadIntASCII(m_iterator));
}
}
else
{
Adaptive_Data_Model dModel(12);
for(unsigned long i = 0; i < numFloatArray; ++i)
{
m_orientation.PushBack((unsigned char) UIntToInt(acd.decode(dModel)));
}
}
ProcessNormals(ifs);
dimFloatArray = 2;
}
#ifdef DEBUG_VERBOSE
printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
fprintf(g_fileDebugSC3DMCDec, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
#endif //DEBUG_VERBOSE
if (m_quantFloatArraySize < size)
{
delete [] m_quantFloatArray;
m_quantFloatArraySize = size;
m_quantFloatArray = new long [size];
}
for (long v=0; v < nvert; ++v)
{
nPred = 0;
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if (ta < 0)
{
break;
}
if (predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION)
{
long a,b;
if ((long) triangles[ta*3] == v)
{
a = triangles[ta*3 + 1];
b = triangles[ta*3 + 2];
}
else if ((long)triangles[ta*3 + 1] == v)
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 2];
}
else
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
}
if ( a < v && b < v)
{
int u0 = v2T.Begin(a);
int u1 = v2T.End(a);
for (long u = u0; u < u1; u++)
{
long tb = v2T.GetNeighbor(u);
if (tb < 0)
{
break;
}
long c = -1;
bool foundB = false;
for(long k = 0; k < 3; ++k)
{
long x = triangles[tb*3 + k];
if (x == b)
{
foundB = true;
}
if (x < v && x != a && x != b)
{
c = x;
}
}
if (c != -1 && foundB)
{
SC3DMCTriplet id = {min(a, b), max(a, b), -c-1};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] +
m_quantFloatArray[b*stride+i] -
m_quantFloatArray[c*stride+i];
}
}
}
}
}
}
if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION ||
predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ||
predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION )
{
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( w < v )
{
SC3DMCTriplet id = {-1, -1, w};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i];
}
}
}
}
}
}
}
if (nPred > 1)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", v);
fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v);
for (unsigned long p = 0; p < nPred; ++p)
{
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
for (unsigned long i = 0; i < dimFloatArray; ++i)
{
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
}
}
#endif //DEBUG_VERBOSE
unsigned long bestPred;
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bestPred = bstream.ReadUCharASCII(iteratorPred);
}
else
{
bestPred = acd.decode(mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
for (unsigned long i = 0; i < dimFloatArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
m_quantFloatArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
}
}
else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
m_quantFloatArray[v*stride+i] = predResidual + m_quantFloatArray[(v-1)*stride+i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadUIntASCII(m_iterator);
}
else
{
predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
m_quantFloatArray[v*stride+i] = predResidual;
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
m_iterator = iteratorPred;
if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
const Real minNormal[2] = {(Real)(-2),(Real)(-2)};
const Real maxNormal[2] = {(Real)(2),(Real)(2)};
Real na1, nb1;
Real na0, nb0;
char ni1;
IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minNormal, maxNormal, nQBits+1);
for (long v=0; v < nvert; ++v)
{
na0 = m_normals[2*v];
nb0 = m_normals[2*v+1];
na1 = floatArray[stride*v] + na0;
nb1 = floatArray[stride*v+1] + nb0;
ni1 = m_orientation[v];
CubeToSphere(na1, nb1, ni1,
floatArray[stride*v],
floatArray[stride*v+1],
floatArray[stride*v+2]);
#ifdef DEBUG_VERBOSE1
printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n",
v,
floatArray[stride*v],
floatArray[stride*v+1],
floatArray[stride*v+2],
ni1, na1, nb1,
na0, nb0);
fprintf(g_fileDebugSC3DMCDec, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n",
v,
floatArray[stride*v],
floatArray[stride*v+1],
floatArray[stride*v+2],
ni1, na1, nb1,
na0, nb0);
#endif //DEBUG_VERBOSE
}
}
else
{
IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits);
}
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCDec);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::IQuantizeFloatArray(Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits)
{
Real idelta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
Real r;
for(unsigned long d = 0; d < dimFloatArray; d++)
{
r = maxFloatArray[d] - minFloatArray[d];
if (r > 0.0f)
{
idelta[d] = r/(float)((1 << nQBits) - 1);
}
else
{
idelta[d] = 1.0f;
}
}
for(unsigned long v = 0; v < numFloatArray; ++v)
{
for(unsigned long d = 0; d < dimFloatArray; ++d) {
floatArray[v * stride + d] = m_quantFloatArray[v * stride + d] * idelta[d] + minFloatArray[d];
}
}
return O3DGC_OK;
}
} // namespace o3dgc
#ifdef _MSC_VER
# pragma warning( pop )
#endif // _MSC_VER
#endif // O3DGC_SC3DMC_DECODER_INL

View file

@ -0,0 +1,137 @@
/*
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;
}
};
O3DGCStreamType GetStreamType() const { return m_streamTypeMode;}
O3DGCSC3DMCEncodingMode GetEncodeMode() const { return m_encodeMode;}
unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;}
unsigned long GetNumIntAttributes() const { return m_numIntAttributes;}
unsigned long GetCoordQuantBits() const { return m_coordQuantBits;}
unsigned long GetNormalQuantBits() const { return m_normalQuantBits;}
unsigned long GetFloatAttributeQuantBits(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_floatAttributeQuantBits[a];
}
O3DGCSC3DMCPredictionMode GetCoordPredMode() const { return m_coordPredMode; }
O3DGCSC3DMCPredictionMode GetNormalPredMode() const { return m_normalPredMode; }
O3DGCSC3DMCPredictionMode GetFloatAttributePredMode(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_floatAttributePredMode[a];
}
O3DGCSC3DMCPredictionMode GetIntAttributePredMode(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_intAttributePredMode[a];
}
O3DGCSC3DMCPredictionMode & GetCoordPredMode() { return m_coordPredMode; }
O3DGCSC3DMCPredictionMode & GetNormalPredMode() { return m_normalPredMode; }
O3DGCSC3DMCPredictionMode & GetFloatAttributePredMode(unsigned long a)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_floatAttributePredMode[a];
}
O3DGCSC3DMCPredictionMode & GetIntAttributePredMode(unsigned long a)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_intAttributePredMode[a];
}
void SetStreamType(O3DGCStreamType streamTypeMode) { m_streamTypeMode = streamTypeMode;}
void SetEncodeMode(O3DGCSC3DMCEncodingMode encodeMode) { m_encodeMode = encodeMode;}
void SetNumFloatAttributes(unsigned long numFloatAttributes)
{
assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_numFloatAttributes = numFloatAttributes;
}
void SetNumIntAttributes (unsigned long numIntAttributes)
{
assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_numIntAttributes = numIntAttributes;
}
void SetCoordQuantBits (unsigned int coordQuantBits ) { m_coordQuantBits = coordQuantBits ; }
void SetNormalQuantBits (unsigned int normalQuantBits ) { m_normalQuantBits = normalQuantBits ; }
void SetFloatAttributeQuantBits(unsigned long a, unsigned long q)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_floatAttributeQuantBits[a] = q;
}
void SetCoordPredMode (O3DGCSC3DMCPredictionMode coordPredMode ) { m_coordPredMode = coordPredMode ; }
void SetNormalPredMode (O3DGCSC3DMCPredictionMode normalPredMode ) { m_normalPredMode = normalPredMode ; }
void SetFloatAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_floatAttributePredMode[a] = p;
}
void SetIntAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_intAttributePredMode[a] = p;
}
private:
unsigned long m_numFloatAttributes;
unsigned long m_numIntAttributes;
unsigned long m_coordQuantBits;
unsigned long m_normalQuantBits;
unsigned long m_floatAttributeQuantBits[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
O3DGCSC3DMCPredictionMode m_coordPredMode;
O3DGCSC3DMCPredictionMode m_normalPredMode;
O3DGCSC3DMCPredictionMode m_floatAttributePredMode[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
O3DGCSC3DMCPredictionMode m_intAttributePredMode [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES];
O3DGCStreamType m_streamTypeMode;
O3DGCSC3DMCEncodingMode m_encodeMode;
};
}
#endif // O3DGC_SC3DMC_ENCODE_PARAMS_H

View file

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

View file

@ -0,0 +1,936 @@
/*
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
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4456)
#endif // _MSC_VER
namespace o3dgc
{
#ifdef DEBUG_VERBOSE
FILE * g_fileDebugSC3DMCEnc = NULL;
#endif //DEBUG_VERBOSE
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::Encode(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream)
{
// Encode header
unsigned long start = bstream.GetSize();
EncodeHeader(params, ifs, bstream);
// Encode payload
EncodePayload(params, ifs, bstream);
bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType);
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodeHeader(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream)
{
m_streamType = params.GetStreamType();
bstream.WriteUInt32(O3DGC_SC3DMC_START_CODE, m_streamType);
m_posSize = bstream.GetSize();
bstream.WriteUInt32(0, m_streamType); // to be filled later
bstream.WriteUChar(O3DGC_SC3DMC_ENCODE_MODE_TFAN, m_streamType);
bstream.WriteFloat32((float)ifs.GetCreaseAngle(), m_streamType);
unsigned char mask = 0;
bool markerBit0 = false;
bool markerBit1 = false;
bool markerBit2 = false;
bool markerBit3 = false;
mask += (ifs.GetCCW() );
mask += (ifs.GetSolid() << 1);
mask += (ifs.GetConvex() << 2);
mask += (ifs.GetIsTriangularMesh() << 3);
mask += (markerBit0 << 4);
mask += (markerBit1 << 5);
mask += (markerBit2 << 6);
mask += (markerBit3 << 7);
bstream.WriteUChar(mask, m_streamType);
bstream.WriteUInt32(ifs.GetNCoord(), m_streamType);
bstream.WriteUInt32(ifs.GetNNormal(), m_streamType);
bstream.WriteUInt32(ifs.GetNumFloatAttributes(), m_streamType);
bstream.WriteUInt32(ifs.GetNumIntAttributes(), m_streamType);
if (ifs.GetNCoord() > 0)
{
bstream.WriteUInt32(ifs.GetNCoordIndex(), m_streamType);
for(int j=0 ; j<3 ; ++j)
{
bstream.WriteFloat32((float) ifs.GetCoordMin(j), m_streamType);
bstream.WriteFloat32((float) ifs.GetCoordMax(j), m_streamType);
}
bstream.WriteUChar((unsigned char) params.GetCoordQuantBits(), m_streamType);
}
if (ifs.GetNNormal() > 0)
{
bstream.WriteUInt32(0, m_streamType);
for(int j=0 ; j<3 ; ++j)
{
bstream.WriteFloat32((float) ifs.GetNormalMin(j), m_streamType);
bstream.WriteFloat32((float) ifs.GetNormalMax(j), m_streamType);
}
bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetNormalPerVertex()
bstream.WriteUChar((unsigned char) params.GetNormalQuantBits(), m_streamType);
}
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
bstream.WriteUInt32(ifs.GetNFloatAttribute(a), m_streamType);
if (ifs.GetNFloatAttribute(a) > 0)
{
assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8);
bstream.WriteUInt32(0, m_streamType);
unsigned char d = (unsigned char) ifs.GetFloatAttributeDim(a);
bstream.WriteUChar(d, m_streamType);
for(unsigned char j = 0 ; j < d ; ++j)
{
bstream.WriteFloat32((float) ifs.GetFloatAttributeMin(a, j), m_streamType);
bstream.WriteFloat32((float) ifs.GetFloatAttributeMax(a, j), m_streamType);
}
bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetFloatAttributePerVertex(a)
bstream.WriteUChar((unsigned char) ifs.GetFloatAttributeType(a), m_streamType);
bstream.WriteUChar((unsigned char) params.GetFloatAttributeQuantBits(a), m_streamType);
}
}
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
bstream.WriteUInt32(ifs.GetNIntAttribute(a), m_streamType);
if (ifs.GetNIntAttribute(a) > 0)
{
assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8);
bstream.WriteUInt32(0, m_streamType);
bstream.WriteUChar((unsigned char) ifs.GetIntAttributeDim(a), m_streamType);
bstream.WriteUChar(true, m_streamType); // (unsigned char) ifs.GetIntAttributePerVertex(a)
bstream.WriteUChar((unsigned char) ifs.GetIntAttributeType(a), m_streamType);
}
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::QuantizeFloatArray(const Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits)
{
const unsigned long size = numFloatArray * dimFloatArray;
Real delta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
Real r;
for(unsigned long d = 0; d < dimFloatArray; d++)
{
r = maxFloatArray[d] - minFloatArray[d];
if (r > 0.0f)
{
delta[d] = (float)((1 << nQBits) - 1) / r;
}
else
{
delta[d] = 1.0f;
}
}
if (m_quantFloatArraySize < size)
{
delete [] m_quantFloatArray;
m_quantFloatArraySize = size;
m_quantFloatArray = new long [size];
}
for(unsigned long v = 0; v < numFloatArray; ++v)
{
for(unsigned long d = 0; d < dimFloatArray; ++d)
{
m_quantFloatArray[v * stride + d] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta[d] + 0.5f);
}
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodeFloatArray(const Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode predMode,
BinaryStream & bstream)
{
assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual, v, uPredResidual;
unsigned long nPred;
Arithmetic_Codec ace;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle();
const long * const vmap = m_triangleListEncoder.GetVMap();
const long * const invVMap = m_triangleListEncoder.GetInvVMap();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numFloatArray;
unsigned long start = bstream.GetSize();
unsigned char mask = predMode & 7;
const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1;
unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS;
unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS;
Adaptive_Data_Model mModelValues(M+2);
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS);
memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4;
m_predictors.Allocate(nvert);
m_predictors.Clear();
}
else
{
mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4;
const unsigned int NMAX = numFloatArray * dimFloatArray * 8 + 100;
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
ace.ExpGolombEncode(0, 0, bModel0, bModel1);
ace.ExpGolombEncode(M, 0, bModel0, bModel1);
}
bstream.WriteUInt32(0, m_streamType);
bstream.WriteUChar(mask, m_streamType);
#ifdef DEBUG_VERBOSE
printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
fprintf(g_fileDebugSC3DMCEnc, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
#endif //DEBUG_VERBOSE
if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
const Real curMinFloatArray[2] = {(Real)(-2.0),(Real)(-2.0)};
const Real curMaxFloatArray[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, curMinFloatArray, curMaxFloatArray, nQBits + 1);
}
else
{
QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits);
}
for (long vm=0; vm < nvert; ++vm)
{
nPred = 0;
v = invVMap[vm];
assert( v >= 0 && v < nvert);
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if ( predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION )
{
long a,b;
if ((long) triangles[ta*3] == v)
{
a = triangles[ta*3 + 1];
b = triangles[ta*3 + 2];
}
else if ((long) triangles[ta*3 + 1] == v)
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 2];
}
else
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
}
if ( vmap[a] < vm && vmap[b] < vm)
{
int u0 = v2T.Begin(a);
int u1 = v2T.End(a);
for (long u = u0; u < u1; u++)
{
long tb = v2T.GetNeighbor(u);
long c = -1;
bool foundB = false;
for(long k = 0; k < 3; ++k)
{
long x = triangles[tb*3 + k];
if (x == b)
{
foundB = true;
}
if (vmap[x] < vm && x != a && x != b)
{
c = x;
}
}
if (c != -1 && foundB)
{
SC3DMCTriplet id = {min(vmap[a], vmap[b]), max(vmap[a], vmap[b]), -vmap[c]-1};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] +
m_quantFloatArray[b*stride+i] -
m_quantFloatArray[c*stride+i];
}
}
}
}
}
}
if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION ||
predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ||
predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION )
{
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( vmap[w] < vm )
{
SC3DMCTriplet id = {-1, -1, vmap[w]};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i];
}
}
}
}
}
}
}
if (nPred > 1)
{
// find best predictor
unsigned long bestPred = 0xFFFFFFFF;
double bestCost = O3DGC_MAX_DOUBLE;
double cost;
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", vm);
fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm);
#endif //DEBUG_VERBOSE
for (unsigned long p = 0; p < nPred; ++p)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
#endif //DEBUG_VERBOSE
cost = -log2((m_freqPreds[p]+1.0) / nPredictors );
for (unsigned long i = 0; i < dimFloatArray; ++i)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
#endif //DEBUG_VERBOSE
predResidual = (long) IntToUInt(m_quantFloatArray[v*stride+i] - m_neighbors[p].m_pred[i]);
if (predResidual < (long) M)
{
cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols );
}
else
{
cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M));
}
}
if (cost < bestCost)
{
bestCost = cost;
bestPred = p;
}
}
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
m_predictors.PushBack((unsigned char) bestPred);
}
else
{
ace.encode(bestPred, mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
// use best predictor
for (unsigned long i = 0; i < dimFloatArray; ++i)
{
predResidual = m_quantFloatArray[v*stride+i] - m_neighbors[bestPred].m_pred[i];
uPredResidual = IntToUInt(predResidual);
++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
}
++m_freqPreds[bestPred];
nSymbols += dimFloatArray;
++nPredictors;
}
else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
long prev = invVMap[vm-1];
for (unsigned long i = 0; i < dimFloatArray; i++)
{
predResidual = m_quantFloatArray[v*stride+i] - m_quantFloatArray[prev*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
predResidual = m_quantFloatArray[v*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteUIntASCII(predResidual);
}
else
{
EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
unsigned long encodedBytes = ace.stop_encoder();
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
unsigned long start = bstream.GetSize();
bstream.WriteUInt32ASCII(0);
const unsigned long size = m_predictors.GetSize();
for(unsigned long i = 0; i < size; ++i)
{
bstream.WriteUCharASCII((unsigned char) m_predictors[i]);
}
bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
}
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCEnc);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodeIntArray(const long * const intArray,
unsigned long numIntArray,
unsigned long dimIntArray,
unsigned long stride,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode predMode,
BinaryStream & bstream)
{
assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual, v, uPredResidual;
unsigned long nPred;
Arithmetic_Codec ace;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle();
const long * const vmap = m_triangleListEncoder.GetVMap();
const long * const invVMap = m_triangleListEncoder.GetInvVMap();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numIntArray;
unsigned long start = bstream.GetSize();
unsigned char mask = predMode & 7;
const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1;
unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS;
unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS;
Adaptive_Data_Model mModelValues(M+2);
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS);
memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4;
m_predictors.Allocate(nvert);
m_predictors.Clear();
}
else
{
mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4;
const unsigned int NMAX = numIntArray * dimIntArray * 8 + 100;
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
ace.ExpGolombEncode(0, 0, bModel0, bModel1);
ace.ExpGolombEncode(M, 0, bModel0, bModel1);
}
bstream.WriteUInt32(0, m_streamType);
bstream.WriteUChar(mask, m_streamType);
#ifdef DEBUG_VERBOSE
printf("IntArray (%i, %i)\n", numIntArray, dimIntArray);
fprintf(g_fileDebugSC3DMCEnc, "IntArray (%i, %i)\n", numIntArray, dimIntArray);
#endif //DEBUG_VERBOSE
for (long vm=0; vm < nvert; ++vm)
{
nPred = 0;
v = invVMap[vm];
assert( v >= 0 && v < nvert);
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( vmap[w] < vm )
{
SC3DMCTriplet id = {-1, -1, vmap[w]};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
m_neighbors[p].m_pred[i] = intArray[w*stride+i];
}
}
}
}
}
}
if (nPred > 1)
{
// find best predictor
unsigned long bestPred = 0xFFFFFFFF;
double bestCost = O3DGC_MAX_DOUBLE;
double cost;
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", vm);
fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm);
#endif //DEBUG_VERBOSE
for (unsigned long p = 0; p < nPred; ++p)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
#endif //DEBUG_VERBOSE
cost = -log2((m_freqPreds[p]+1.0) / nPredictors );
for (unsigned long i = 0; i < dimIntArray; ++i)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
#endif //DEBUG_VERBOSE
predResidual = (long) IntToUInt(intArray[v*stride+i] - m_neighbors[p].m_pred[i]);
if (predResidual < (long) M)
{
cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols );
}
else
{
cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M));
}
}
if (cost < bestCost)
{
bestCost = cost;
bestPred = p;
}
}
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
m_predictors.PushBack((unsigned char) bestPred);
}
else
{
ace.encode(bestPred, mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
// use best predictor
for (unsigned long i = 0; i < dimIntArray; ++i)
{
predResidual = intArray[v*stride+i] - m_neighbors[bestPred].m_pred[i];
uPredResidual = IntToUInt(predResidual);
++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
}
++m_freqPreds[bestPred];
nSymbols += dimIntArray;
++nPredictors;
}
else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
long prev = invVMap[vm-1];
for (unsigned long i = 0; i < dimIntArray; i++)
{
predResidual = intArray[v*stride+i] - intArray[prev*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
predResidual = intArray[v*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteUIntASCII(predResidual);
}
else
{
EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
unsigned long encodedBytes = ace.stop_encoder();
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
unsigned long start = bstream.GetSize();
bstream.WriteUInt32ASCII(0);
const unsigned long size = m_predictors.GetSize();
for(unsigned long i = 0; i < size; ++i)
{
bstream.WriteUCharASCII((unsigned char) m_predictors[i]);
}
bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
}
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCEnc);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::ProcessNormals(const IndexedFaceSet<T> & ifs)
{
const long nvert = (long) ifs.GetNNormal();
const unsigned long normalSize = ifs.GetNNormal() * 2;
if (m_normalsSize < normalSize)
{
delete [] m_normals;
m_normalsSize = normalSize;
m_normals = new Real [normalSize];
}
const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle();
const long * const invVMap = m_triangleListEncoder.GetInvVMap();
const T * const triangles = ifs.GetCoordIndex();
const Real * const originalNormals = ifs.GetNormal();
Vec3<long> p1, p2, p3, n0, nt;
Vec3<Real> n1;
long na0 = 0, nb0 = 0;
Real rna0, rnb0, na1 = 0, nb1 = 0, norm0, norm1;
char ni0 = 0, ni1 = 0;
long a, b, c, v;
m_predictors.Clear();
for (long i=0; i < nvert; ++i)
{
v = invVMap[i];
n0.X() = 0;
n0.Y() = 0;
n0.Z() = 0;
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
c = triangles[ta*3 + 2];
p1.X() = m_quantFloatArray[3*a];
p1.Y() = m_quantFloatArray[3*a+1];
p1.Z() = m_quantFloatArray[3*a+2];
p2.X() = m_quantFloatArray[3*b];
p2.Y() = m_quantFloatArray[3*b+1];
p2.Z() = m_quantFloatArray[3*b+2];
p3.X() = m_quantFloatArray[3*c];
p3.Y() = m_quantFloatArray[3*c+1];
p3.Z() = m_quantFloatArray[3*c+2];
nt = (p2-p1)^(p3-p1);
n0 += nt;
}
norm0 = (Real) n0.GetNorm();
if (norm0 == 0.0)
{
norm0 = 1.0;
}
SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0);
rna0 = na0 / norm0;
rnb0 = nb0 / norm0;
n1.X() = originalNormals[3*v];
n1.Y() = originalNormals[3*v+1];
n1.Z() = originalNormals[3*v+2];
norm1 = (Real) n1.GetNorm();
if (norm1 != 0.0)
{
n1.X() /= norm1;
n1.Y() /= norm1;
n1.Z() /= norm1;
}
SphereToCube(n1.X(), n1.Y(), n1.Z(), na1, nb1, ni1);
m_predictors.PushBack(ni1 - ni0);
if ( (ni1 >> 1) != (ni0 >> 1) )
{
rna0 = (Real)0.0;
rnb0 = (Real)0.0;
}
m_normals[2*v] = na1 - rna0;
m_normals[2*v+1] = nb1 - rnb0;
#ifdef DEBUG_VERBOSE1
printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
fprintf(g_fileDebugSC3DMCEnc,"n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
#endif //DEBUG_VERBOSE
#ifdef DEBUG_VERBOSE1
printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0);
fprintf(g_fileDebugSC3DMCEnc, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0);
#endif //DEBUG_VERBOSE
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodePayload(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream)
{
#ifdef DEBUG_VERBOSE
g_fileDebugSC3DMCEnc = fopen("tfans_enc_main.txt", "w");
#endif //DEBUG_VERBOSE
// encode triangle list
m_triangleListEncoder.SetStreamType(params.GetStreamType());
m_stats.m_streamSizeCoordIndex = bstream.GetSize();
Timer timer;
timer.Tic();
m_triangleListEncoder.Encode(ifs.GetCoordIndex(), ifs.GetIndexBufferID(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream);
timer.Toc();
m_stats.m_timeCoordIndex = timer.GetElapsedTime();
m_stats.m_streamSizeCoordIndex = bstream.GetSize() - m_stats.m_streamSizeCoordIndex;
// encode coord
m_stats.m_streamSizeCoord = bstream.GetSize();
timer.Tic();
if (ifs.GetNCoord() > 0)
{
EncodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(),
params.GetCoordQuantBits(), ifs, params.GetCoordPredMode(), bstream);
}
timer.Toc();
m_stats.m_timeCoord = timer.GetElapsedTime();
m_stats.m_streamSizeCoord = bstream.GetSize() - m_stats.m_streamSizeCoord;
// encode Normal
m_stats.m_streamSizeNormal = bstream.GetSize();
timer.Tic();
if (ifs.GetNNormal() > 0)
{
if (params.GetNormalPredMode() == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
ProcessNormals(ifs);
EncodeFloatArray(m_normals, ifs.GetNNormal(), 2, 2, ifs.GetNormalMin(), ifs.GetNormalMax(),
params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream);
}
else
{
EncodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(),
params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream);
}
}
timer.Toc();
m_stats.m_timeNormal = timer.GetElapsedTime();
m_stats.m_streamSizeNormal = bstream.GetSize() - m_stats.m_streamSizeNormal;
// encode FloatAttribute
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize();
timer.Tic();
EncodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a),
ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a),
ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a),
params.GetFloatAttributeQuantBits(a), ifs,
params.GetFloatAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeFloatAttribute[a];
}
// encode IntAttribute
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize();
timer.Tic();
EncodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a),
ifs.GetIntAttributeDim(a), ifs, params.GetIntAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeIntAttribute[a];
}
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugSC3DMCEnc);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
} // namespace o3dgc
#ifdef _MSC_VER
# pragma warning(pop)
#endif // _MSC_VER
#endif // O3DGC_SC3DMC_ENCODER_INL

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,96 @@
# Copyright (c) 2014, Pavel Rojtberg
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# 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.
# ------------------------------------------------------------------------------
# Usage:
# 1. place AndroidNdkGdb.cmake somewhere inside ${CMAKE_MODULE_PATH}
# 2. inside your project add
#
# include(AndroidNdkGdb)
# android_ndk_gdb_enable()
# # for each target
# add_library(MyLibrary ...)
# android_ndk_gdb_debuggable(MyLibrary)
# add gdbserver and general gdb configuration to project
# also create a mininal NDK skeleton so ndk-gdb finds the paths
#
# the optional parameter defines the path to the android project.
# uses PROJECT_SOURCE_DIR by default.
macro(android_ndk_gdb_enable)
if(ANDROID)
# create custom target that depends on the real target so it gets executed afterwards
add_custom_target(NDK_GDB ALL)
if(${ARGC})
set(ANDROID_PROJECT_DIR ${ARGV0})
else()
set(ANDROID_PROJECT_DIR ${PROJECT_SOURCE_DIR})
endif()
set(NDK_GDB_SOLIB_PATH ${ANDROID_PROJECT_DIR}/obj/local/${ANDROID_NDK_ABI_NAME}/)
file(MAKE_DIRECTORY ${NDK_GDB_SOLIB_PATH})
# 1. generate essential Android Makefiles
file(MAKE_DIRECTORY ${ANDROID_PROJECT_DIR}/jni)
if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Android.mk)
file(WRITE ${ANDROID_PROJECT_DIR}/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
endif()
if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Application.mk)
file(WRITE ${ANDROID_PROJECT_DIR}/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
endif()
# 2. generate gdb.setup
get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES)
string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}")
file(WRITE ${LIBRARY_OUTPUT_PATH}/gdb.setup "set solib-search-path ${NDK_GDB_SOLIB_PATH}\n")
file(APPEND ${LIBRARY_OUTPUT_PATH}/gdb.setup "directory ${PROJECT_INCLUDES}\n")
# 3. copy gdbserver executable
file(COPY ${ANDROID_NDK}/prebuilt/android-${ANDROID_ARCH_NAME}/gdbserver/gdbserver DESTINATION ${LIBRARY_OUTPUT_PATH})
endif()
endmacro()
# register a target for remote debugging
# copies the debug version to NDK_GDB_SOLIB_PATH then strips symbols of original
macro(android_ndk_gdb_debuggable TARGET_NAME)
if(ANDROID)
get_property(TARGET_LOCATION TARGET ${TARGET_NAME} PROPERTY LOCATION)
# create custom target that depends on the real target so it gets executed afterwards
add_dependencies(NDK_GDB ${TARGET_NAME})
# 4. copy lib to obj
add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TARGET_LOCATION} ${NDK_GDB_SOLIB_PATH})
# 5. strip symbols
add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_STRIP} ${TARGET_LOCATION})
endif()
endmacro()

View file

@ -0,0 +1,58 @@
# Copyright (c) 2014, Pavel Rojtberg
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# 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.
macro(android_ndk_import_module_cpufeatures)
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
target_link_libraries(cpufeatures dl)
endif()
endmacro()
macro(android_ndk_import_module_native_app_glue)
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
add_library(native_app_glue ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
target_link_libraries(native_app_glue log)
endif()
endmacro()
macro(android_ndk_import_module_ndk_helper)
if(ANDROID)
android_ndk_import_module_cpufeatures()
android_ndk_import_module_native_app_glue()
include_directories(${ANDROID_NDK}/sources/android/ndk_helper)
file(GLOB _NDK_HELPER_SRCS ${ANDROID_NDK}/sources/android/ndk_helper/*.cpp ${ANDROID_NDK}/sources/android/ndk_helper/gl3stub.c)
add_library(ndk_helper ${_NDK_HELPER_SRCS})
target_link_libraries(ndk_helper log android EGL GLESv2 cpufeatures native_app_glue)
unset(_NDK_HELPER_SRCS)
endif()
endmacro()

View file

@ -0,0 +1,240 @@
# android-cmake
CMake is great, and so is Android. This is a collection of CMake scripts that may be useful to the Android NDK community. It is based on experience from porting OpenCV library to Android: http://opencv.org/platforms/android.html
Main goal is to share these scripts so that devs that use CMake as their build system may easily compile native code for Android.
## TL;DR
cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake \
-DANDROID_NDK=<ndk_path> \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_ABI="armeabi-v7a with NEON" \
<source_path>
cmake --build .
One-liner:
cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_NDK=<ndk_path> -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="armeabi-v7a with NEON" <source_path> && cmake --build .
_android-cmake_ will search for your NDK install in the following order:
1. Value of `ANDROID_NDK` CMake variable;
1. Value of `ANDROID_NDK` environment variable;
1. Search under paths from `ANDROID_NDK_SEARCH_PATHS` CMake variable;
1. Search platform specific locations (home folder, Windows "Program Files", etc).
So if you have installed the NDK as `~/android-ndk-r10d` then _android-cmake_ will locate it automatically.
## Getting started
To build a cmake-based C/C++ project for Android you need:
* Android NDK (>= r5) http://developer.android.com/tools/sdk/ndk/index.html
* CMake (>= v2.6.3, >= v2.8.9 recommended) http://www.cmake.org/download
The _android-cmake_ is also capable to build with NDK from AOSP or Linaro Android source tree, but you may be required to manually specify path to `libm` binary to link with.
## Difference from traditional CMake
Folowing the _ndk-build_ the _android-cmake_ supports **only two build targets**:
* `-DCMAKE_BUILD_TYPE=Release`
* `-DCMAKE_BUILD_TYPE=Debug`
So don't even try other targets that can be found in CMake documentation and don't forget to explicitly specify `Release` or `Debug` because CMake builds without a build configuration by default.
## Difference from _ndk-build_
* Latest GCC available in NDK is used as the default compiler;
* `Release` builds with `-O3` instead of `-Os`;
* `Release` builds without debug info (without `-g`) (because _ndk-build_ always creates a stripped version but cmake delays this for `install/strip` target);
* `-fsigned-char` is added to compiler flags to make `char` signed by default as it is on x86/x86_64;
* GCC's stack protector is not used neither in `Debug` nor `Release` configurations;
* No builds for multiple platforms (e.g. building for both arm and x86 require to run cmake twice with different parameters);
* No file level Neon via `.neon` suffix;
The following features of _ndk-build_ are not supported by the _android-cmake_ yet:
* `armeabi-v7a-hard` ABI
* `libc++_static`/`libc++_shared` STL runtime
## Basic options
Similarly to the NDK build system _android-cmake_ allows to select between several compiler toolchains and target platforms. Most of the options can be set either as cmake arguments: `-D<NAME>=<VALUE>` or as environment variables:
* **ANDROID_NDK** - path to the Android NDK. If not set then _android-cmake_ will search for the most recent version of supported NDK in commonly used locations;
* **ANDROID_ABI** - specifies the target Application Binary Interface (ABI). This option nearly matches to the APP_ABI variable used by ndk-build tool from Android NDK. If not specified then set to `armeabi-v7a`. Possible target names are:
* `armeabi` - ARMv5TE based CPU with software floating point operations;
* **`armeabi-v7a`** - ARMv7 based devices with hardware FPU instructions (VFPv3_D16);
* `armeabi-v7a with NEON` - same as armeabi-v7a, but sets NEON as floating-point unit;
* `armeabi-v7a with VFPV3` - same as armeabi-v7a, but sets VFPv3_D32 as floating-point unit;
* `armeabi-v6 with VFP` - tuned for ARMv6 processors having VFP;
* `x86` - IA-32 instruction set
* `mips` - MIPS32 instruction set
* `arm64-v8a` - ARMv8 AArch64 instruction set - only for NDK r10 and newer
* `x86_64` - Intel64 instruction set (r1) - only for NDK r10 and newer
* `mips64` - MIPS64 instruction set (r6) - only for NDK r10 and newer
* **ANDROID_NATIVE_API_LEVEL** - level of android API to build for. Can be set either to full name (example: `android-8`) or a numeric value (example: `17`). The default API level depends on the target ABI:
* `android-8` for ARM;
* `android-9` for x86 and MIPS;
* `android-21` for 64-bit ABIs.
Building for `android-L` is possible only when it is explicitly selected.
* **ANDROID_TOOLCHAIN_NAME** - the name of compiler toolchain to be used. This option allows to select between different GCC and Clang versions. The list of possible values depends on the NDK version and will be printed by toolchain file if an invalid value is set. By default _android-cmake_ selects the most recent version of GCC which can build for specified `ANDROID_ABI`.
Example values are:
* `aarch64-linux-android-4.9`
* `aarch64-linux-android-clang3.5`
* `arm-linux-androideabi-4.8`
* `arm-linux-androideabi-4.9`
* `arm-linux-androideabi-clang3.5`
* `mips64el-linux-android-4.9`
* `mipsel-linux-android-4.8`
* `x86-4.9`
* `x86_64-4.9`
* etc.
* **ANDROID_STL** - the name of C++ runtime to use. The default is `gnustl_static`.
* `none` - do not configure the runtime.
* `system` - use the default minimal system C++ runtime library.
* Implies `-fno-rtti -fno-exceptions`.
* `system_re` - use the default minimal system C++ runtime library.
* Implies `-frtti -fexceptions`.
* `gabi++_static` - use the GAbi++ runtime as a static library.
* Implies `-frtti -fno-exceptions`.
* Available for NDK r7 and newer.
* `gabi++_shared` - use the GAbi++ runtime as a shared library.
* Implies `-frtti -fno-exceptions`.
* Available for NDK r7 and newer.
* `stlport_static` - use the STLport runtime as a static library.
* Implies `-fno-rtti -fno-exceptions` for NDK before r7.
* Implies `-frtti -fno-exceptions` for NDK r7 and newer.
* `stlport_shared` - use the STLport runtime as a shared library.
* Implies `-fno-rtti -fno-exceptions` for NDK before r7.
* Implies `-frtti -fno-exceptions` for NDK r7 and newer.
* **`gnustl_static`** - use the GNU STL as a static library.
* Implies `-frtti -fexceptions`.
* `gnustl_shared` - use the GNU STL as a shared library.
* Implies `-frtti -fno-exceptions`.
* Available for NDK r7b and newer.
* Silently degrades to `gnustl_static` if not available.
* **NDK_CCACHE** - path to `ccache` executable. If not set then initialized from `NDK_CCACHE` environment variable.
## Advanced _android-cmake_ options
Normally _android-cmake_ users are not supposed to touch these variables but they might be useful to workaround some build issues:
* **ANDROID_FORCE_ARM_BUILD** = `OFF` - generate 32-bit ARM instructions instead of Thumb. Applicable only for arm ABIs and is forced to be `ON` for `armeabi-v6 with VFP`;
* **ANDROID_NO_UNDEFINED** = `ON` - show all undefined symbols as linker errors;
* **ANDROID_SO_UNDEFINED** = `OFF` - allow undefined symbols in shared libraries;
* actually it is turned `ON` by default for NDK older than `r7`
* **ANDROID_STL_FORCE_FEATURES** = `ON` - automatically configure rtti and exceptions support based on C++ runtime;
* **ANDROID_NDK_LAYOUT** = `RELEASE` - inner layout of Android NDK, should be detected automatically. Possible values are:
* `RELEASE` - public releases from Google;
* `LINARO` - NDK from Linaro project;
* `ANDROID` - NDK from AOSP.
* **ANDROID_FUNCTION_LEVEL_LINKING** = `ON` - enables saparate putting each function and data items into separate sections and enable garbage collection of unused input sections at link time (`-fdata-sections -ffunction-sections -Wl,--gc-sections`);
* **ANDROID_GOLD_LINKER** = `ON` - use gold linker with GCC 4.6 for NDK r8b and newer (only for ARM and x86);
* **ANDROID_NOEXECSTACK** = `ON` - enables or disables stack execution protection code (`-Wl,-z,noexecstack`);
* **ANDROID_RELRO** = `ON` - Enables RELRO - a memory corruption mitigation technique (`-Wl,-z,relro -Wl,-z,now`);
* **ANDROID_LIBM_PATH** - path to `libm.so` (set to something like `$(TOP)/out/target/product/<product_name>/obj/lib/libm.so`) to workaround unresolved `sincos`.
## Fine-tuning `CMakeLists.txt` for _android-cmake_
### Recognizing Android build
_android-cmake_ defines `ANDROID` CMake variable which can be used to add Android-specific stuff:
if (ANDROID)
message(STATUS "Hello from Android build!")
endif()
The recommended way to identify ARM/MIPS/x86 architecture is examining `CMAKE_SYSTEM_PROCESSOR` which is set to the appropriate value:
* `armv5te` - for `armeabi` ABI
* `armv6` - for `armeabi-v6 with VFP` ABI
* `armv7-a` - for `armeabi-v7a`, `armeabi-v7a with VFPV3` and `armeabi-v7a with NEON` ABIs
* `aarch64` - for `arm64-v8a` ABI
* `i686` - for `x86` ABI
* `x86_64` - for `x86_64` ABI
* `mips` - for `mips` ABI
* `mips64` - for `mips64` ABI
Other variables that are set by _android-cmake_ and can be used for the fine-grained build configuration are:
* `NEON` - set if target ABI supports Neon;
* `ANDROID_NATIVE_API_LEVEL` - native Android API level we are building for (note: Java part of Andoid application can be built for another API level)
* `ANDROID_NDK_RELEASE` - version of the Android NDK
* `ANDROID_NDK_HOST_SYSTEM_NAME` - "windows", "linux-x86" or "darwin-x86" depending on the host platform
* `ANDROID_RTTI` - set if rtti is enabled by the runtime
* `ANDROID_EXCEPTIONS` - set if exceptions are enabled by the runtime
### Finding packages
When crosscompiling CMake `find_*` commands are normally expected to find libraries and packages belonging to the same build target. So _android-cmake_ configures CMake to search in Android-specific paths only and ignore your host system locations. So
find_package(ZLIB)
will surely find libz.so within the Android NDK.
However sometimes you need to locate a host package even when cross-compiling. For example you can be searching for your documentation generator. The _android-cmake_ recommends you to use `find_host_package` and `find_host_program` macro defined in the `android.toolchain.cmake`:
find_host_package(Doxygen)
find_host_program(PDFLATEX pdflatex)
However this will break regular builds so instead of wrapping package search into platform-specific logic you can copy the following snippet into your project (put it after your top-level `project()` command):
# Search packages for host system instead of packages for target system
# in case of cross compilation these macro should be defined by toolchain file
if(NOT COMMAND find_host_package)
macro(find_host_package)
find_package(${ARGN})
endmacro()
endif()
if(NOT COMMAND find_host_program)
macro(find_host_program)
find_program(${ARGN})
endmacro()
endif()
### Compiler flags recycling
Make sure to do the following in your scripts:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}")
The flags will be prepopulated with critical flags, so don't loose them. Also be aware that _android-cmake_ also sets configuration-specific compiler and linker flags.
## Troubleshooting
### Building on Windows
First of all `cygwin` builds are **NOT supported** and will not be supported by _android-cmake_. To build natively on Windows you need a port of make but I recommend http://martine.github.io/ninja/ instead.
To build with Ninja you need:
* Ensure you are using CMake newer than 2.8.9;
* Download the latest Ninja from https://github.com/martine/ninja/releases;
* Put the `ninja.exe` into your PATH (or add path to `ninja.exe` to your PATH environment variable);
* Pass `-GNinja` to `cmake` alongside with other arguments (or choose Ninja generator in `cmake-gui`).
* Enjoy the fast native multithreaded build :)
But if you still want to stick to old make then:
* Get a Windows port of GNU Make:
* Android NDK r7 (and newer) already has `make.exe` on board;
* `mingw-make` should work as fine;
* Download some other port. For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm.
* Add path to your `make.exe` to system PATH or always use full path;
* Pass `-G"MinGW Makefiles"` and `-DCMAKE_MAKE_PROGRAM="<full/path/to/>make.exe"`
* It must be `MinGW Makefiles` and not `Unix Makefiles` even if your `make.exe` is not a MinGW's make.
* Run `make.exe` or `cmake --build .` for single-threaded build.
### Projects with assembler files
The _android-cmake_ should correctly handle projects with assembler sources (`*.s` or `*.S`). But if you still facing problems with assembler then try to upgrade your CMake to version newer than 2.8.5
## Copying
_android-cmake_ is distributed under the terms of [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,211 @@
============== r1 ============== (dead links)
* http://dl.google.com/android/ndk/android-ndk-1.5_r1-windows.zip
* http://dl.google.com/android/ndk/android-ndk-1.5_r1-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-1.5_r1-linux-x86.zip
============== r2 ==============
* http://dl.google.com/android/ndk/android-ndk-1.6_r1-windows.zip
* http://dl.google.com/android/ndk/android-ndk-1.6_r1-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-1.6_r1-linux-x86.zip
============== r3 ==============
* http://dl.google.com/android/ndk/android-ndk-r3-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r3-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r3-linux-x86.zip
============== r4 ==============
* http://dl.google.com/android/ndk/android-ndk-r4-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r4-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r4-linux-x86.zip
============== r4b ==============
* http://dl.google.com/android/ndk/android-ndk-r4b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r4b-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r4b-linux-x86.zip
============== r5 ==============
* http://dl.google.com/android/ndk/android-ndk-r5-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r5-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r5-linux-x86.tar.bz2
============== r5b ==============
* http://dl.google.com/android/ndk/android-ndk-r5b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r5b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r5b-linux-x86.tar.bz2
============== r5c ==============
* http://dl.google.com/android/ndk/android-ndk-r5c-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r5c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r5c-linux-x86.tar.bz2
============== r6 ==============
* http://dl.google.com/android/ndk/android-ndk-r6-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r6-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r6-linux-x86.tar.bz2
============== r6b ==============
* http://dl.google.com/android/ndk/android-ndk-r6b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r6b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r6b-linux-x86.tar.bz2
============== r7 ==============
* http://dl.google.com/android/ndk/android-ndk-r7-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r7-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r7-linux-x86.tar.bz2
============== r7b ==============
* http://dl.google.com/android/ndk/android-ndk-r7b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r7b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r7b-linux-x86.tar.bz2
============== r7c ==============
* http://dl.google.com/android/ndk/android-ndk-r7c-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r7c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r7c-linux-x86.tar.bz2
============== r8 ==============
* http://dl.google.com/android/ndk/android-ndk-r8-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8-linux-x86.tar.bz2
============== r8b ==============
* http://dl.google.com/android/ndk/android-ndk-r8b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2
============== r8c ==============
* http://dl.google.com/android/ndk/android-ndk-r8c-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8c-linux-x86.tar.bz2
============== r8d ==============
* http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8d-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8d-linux-x86.tar.bz2
============== r8e ==============
* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86_64.tar.bz2
============== r9 ==============
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64-legacy-toolchains.tar.bz2
============== r9b ==============
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64-legacy-toolchains.tar.bz2
============== r9c ==============
* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-cxx-stl-libs-with-debugging-info.zip
============== r9d ==============
* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-cxx-stl-libs-with-debug-info.zip
============== r10 ==============
* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r10-cxx-stl-libs-with-debug-info.zip
============== r10b ==============
* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r10b-cxx-stl-libs-with-debug-info.zip
============== r10c ==============
* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86.exe
* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86_64.exe
* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86_64.bin
* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin
============== r10d ==============
* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86.exe
* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86_64.exe
* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86_64.bin
* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin

View file

@ -0,0 +1,24 @@
Boost Software License - Version 1.0 - August 17th, 2003
http://www.boost.org/LICENSE_1_0.txt
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

4637
vendor/assimp/contrib/clipper/clipper.cpp vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,406 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
* Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
* "A generic solution to polygon clipping" *
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
* http://portal.acm.org/citation.cfm?id=129906 *
* *
* Computer graphics and geometric modeling: implementation and algorithms *
* By Max K. Agoston *
* Springer; 1 edition (January 4, 2005) *
* http://books.google.com/books?q=vatti+clipping+agoston *
* *
* See also: *
* "Polygon Offsetting by Computing Winding Numbers" *
* Paper no. DETC2005-85513 pp. 565-575 *
* ASME 2005 International Design Engineering Technical Conferences *
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
* September 24-28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
#ifndef clipper_hpp
#define clipper_hpp
#define CLIPPER_VERSION "6.4.2"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
//#define use_int32
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines
//use_deprecated: Enables temporary support for the obsolete functions
//#define use_deprecated
#include <vector>
#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
#include <queue>
namespace ClipperLib {
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
//By far the most widely used winding rules for polygon filling are
//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
//see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
typedef int cInt;
static cInt const loRange = 0x7FFF;
static cInt const hiRange = 0x7FFF;
#else
typedef signed long long cInt;
static cInt const loRange = 0x3FFFFFFF;
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
typedef signed long long long64; //used by Int128 class
typedef unsigned long long ulong64;
#endif
struct IntPoint {
cInt X;
cInt Y;
#ifdef use_xyz
cInt Z;
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
#else
IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
#endif
friend inline bool operator== (const IntPoint& a, const IntPoint& b)
{
return a.X == b.X && a.Y == b.Y;
}
friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
{
return a.X != b.X || a.Y != b.Y;
}
};
//------------------------------------------------------------------------------
typedef std::vector< IntPoint > Path;
typedef std::vector< Path > Paths;
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
std::ostream& operator <<(std::ostream &s, const IntPoint &p);
std::ostream& operator <<(std::ostream &s, const Path &p);
std::ostream& operator <<(std::ostream &s, const Paths &p);
struct DoublePoint
{
double X;
double Y;
DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
};
//------------------------------------------------------------------------------
#ifdef use_xyz
typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
class PolyNode
{
public:
PolyNode();
virtual ~PolyNode(){};
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
PolyNode* GetNext() const;
bool IsHole() const;
bool IsOpen() const;
int ChildCount() const;
private:
//PolyNode& operator =(PolyNode& other);
unsigned Index; //node index in Parent.Childs
bool m_IsOpen;
JoinType m_jointype;
EndType m_endtype;
PolyNode* GetNextSiblingUp() const;
void AddChild(PolyNode& child);
friend class Clipper; //to access Index
friend class ClipperOffset;
};
class PolyTree: public PolyNode
{
public:
~PolyTree(){ Clear(); };
PolyNode* GetFirst() const;
void Clear();
int Total() const;
private:
//PolyTree& operator =(PolyTree& other);
PolyNodes AllNodes;
friend class Clipper; //to access AllNodes
};
bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
void CleanPolygon(Path& poly, double distance = 1.415);
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
void CleanPolygons(Paths& polys, double distance = 1.415);
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
void ReversePath(Path& p);
void ReversePaths(Paths& p);
struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
//enums that are used internally ...
enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinimum;
struct OutPt;
struct OutRec;
struct Join;
typedef std::vector < OutRec* > PolyOutList;
typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
//instantiated directly. This class simply abstracts the conversion of sets of
//polygon coordinates into edge objects that are stored in a LocalMinima list.
class ClipperBase
{
public:
ClipperBase();
virtual ~ClipperBase();
virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
bool PreserveCollinear() {return m_PreserveCollinear;};
void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
void InsertScanbeam(const cInt Y);
bool PopScanbeam(cInt &Y);
bool LocalMinimaPending();
bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
OutRec* CreateOutRec();
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
typedef std::vector<LocalMinimum> MinimaList;
MinimaList::iterator m_CurrentLM;
MinimaList m_MinimaList;
bool m_UseFullRange;
EdgeList m_edges;
bool m_PreserveCollinear;
bool m_HasOpenPaths;
PolyOutList m_PolyOuts;
TEdge *m_ActiveEdges;
typedef std::priority_queue<cInt> ScanbeamList;
ScanbeamList m_Scanbeam;
};
//------------------------------------------------------------------------------
class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType fillType = pftEvenOdd);
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType subjFillType,
PolyFillType clipFillType);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType fillType = pftEvenOdd);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType subjFillType,
PolyFillType clipFillType);
bool ReverseSolution() { return m_ReverseOutput; };
void ReverseSolution(bool value) {m_ReverseOutput = value;};
bool StrictlySimple() {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
virtual bool ExecuteInternal();
private:
JoinList m_Joins;
JoinList m_GhostJoins;
IntersectList m_IntersectList;
ClipType m_ClipType;
typedef std::list<cInt> MaximaList;
MaximaList m_Maxima;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
PolyFillType m_SubjFillType;
bool m_ReverseOutput;
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
ZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
bool PopEdgeFromSEL(TEdge *&edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
void DoMaxima(TEdge *e);
void ProcessHorizontals();
void ProcessHorizontal(TEdge *horzEdge);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
OutPt* GetLastOutPt(TEdge *e);
bool ProcessIntersections(const cInt topY);
void BuildIntersectList(const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
void BuildResult2(PolyTree& polytree);
void SetHoleState(TEdge *e, OutRec *outrec);
void DisposeIntersectNodes();
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
void FixupOutPolyline(OutRec &outrec);
bool IsHole(TEdge *e);
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
void FixHoleLinkage(OutRec &outrec);
void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
void ClearJoins();
void ClearGhostJoins();
void AddGhostJoin(OutPt *op, const IntPoint offPt);
bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2);
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif
};
//------------------------------------------------------------------------------
class ClipperOffset
{
public:
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
~ClipperOffset();
void AddPath(const Path& path, JoinType joinType, EndType endType);
void AddPaths(const Paths& paths, JoinType joinType, EndType endType);
void Execute(Paths& solution, double delta);
void Execute(PolyTree& solution, double delta);
void Clear();
double MiterLimit;
double ArcTolerance;
private:
Paths m_destPolys;
Path m_srcPoly;
Path m_destPoly;
std::vector<DoublePoint> m_normals;
double m_delta, m_sinA, m_sin, m_cos;
double m_miterLim, m_StepsPerRad;
IntPoint m_lowest;
PolyNode m_polyNodes;
void FixOrientations();
void DoOffset(double delta);
void OffsetPoint(int j, int& k, JoinType jointype);
void DoSquare(int j, int k);
void DoMiter(int j, int k, double r);
void DoRound(int j, int k);
};
//------------------------------------------------------------------------------
class clipperException : public std::exception
{
public:
clipperException(const char* description): m_descr(description) {}
virtual ~clipperException() throw() {}
virtual const char* what() const throw() {return m_descr.c_str();}
private:
std::string m_descr;
};
//------------------------------------------------------------------------------
} //ClipperLib namespace
#endif //clipper_hpp

View file

@ -0,0 +1,5 @@
---
Language: Cpp
BasedOnStyle: Google
PointerAlignment: Right
...

View file

@ -0,0 +1,137 @@
with section('parse'):
# Specify structure for custom cmake functions
additional_commands = {
'draco_add_emscripten_executable': {
'kwargs': {
'NAME': '*',
'SOURCES': '*',
'OUTPUT_NAME': '*',
'DEFINES': '*',
'INCLUDES': '*',
'COMPILE_FLAGS': '*',
'LINK_FLAGS': '*',
'OBJLIB_DEPS': '*',
'LIB_DEPS': '*',
'GLUE_PATH': '*',
'PRE_LINK_JS_SOURCES': '*',
'POST_LINK_JS_SOURCES': '*',
'FEATURES': '*',
},
'pargs': 0,
},
'draco_add_executable': {
'kwargs': {
'NAME': '*',
'SOURCES': '*',
'OUTPUT_NAME': '*',
'TEST': 0,
'DEFINES': '*',
'INCLUDES': '*',
'COMPILE_FLAGS': '*',
'LINK_FLAGS': '*',
'OBJLIB_DEPS': '*',
'LIB_DEPS': '*',
},
'pargs': 0,
},
'draco_add_library': {
'kwargs': {
'NAME': '*',
'TYPE': '*',
'SOURCES': '*',
'TEST': 0,
'OUTPUT_NAME': '*',
'DEFINES': '*',
'INCLUDES': '*',
'COMPILE_FLAGS': '*',
'LINK_FLAGS': '*',
'OBJLIB_DEPS': '*',
'LIB_DEPS': '*',
'PUBLIC_INCLUDES': '*',
},
'pargs': 0,
},
'draco_generate_emscripten_glue': {
'kwargs': {
'INPUT_IDL': '*',
'OUTPUT_PATH': '*',
},
'pargs': 0,
},
'draco_get_required_emscripten_flags': {
'kwargs': {
'FLAG_LIST_VAR_COMPILER': '*',
'FLAG_LIST_VAR_LINKER': '*',
},
'pargs': 0,
},
'draco_option': {
'kwargs': {
'NAME': '*',
'HELPSTRING': '*',
'VALUE': '*',
},
'pargs': 0,
},
# Rules for built in CMake commands and those from dependencies.
'list': {
'kwargs': {
'APPEND': '*',
'FILTER': '*',
'FIND': '*',
'GET': '*',
'INSERT': '*',
'JOIN': '*',
'LENGTH': '*',
'POP_BACK': '*',
'POP_FRONT': '*',
'PREPEND': '*',
'REMOVE_DUPLICATES': '*',
'REMOVE_ITEM': '*',
'REVERSE': '*',
'SORT': '*',
'SUBLIST': '*',
'TRANSFORM': '*',
},
},
'protobuf_generate': {
'kwargs': {
'IMPORT_DIRS': '*',
'LANGUAGE': '*',
'OUT_VAR': '*',
'PROTOC_OUT_DIR': '*',
'PROTOS': '*',
},
},
}
with section('format'):
# Formatting options.
# How wide to allow formatted cmake files
line_width = 80
# How many spaces to tab for indent
tab_size = 2
# If true, separate flow control names from their parentheses with a space
separate_ctrl_name_with_space = False
# If true, separate function names from parentheses with a space
separate_fn_name_with_space = False
# If a statement is wrapped to more than one line, than dangle the closing
# parenthesis on its own line.
dangle_parens = False
# Do not sort argument lists.
enable_sort = False
# What style line endings to use in the output.
line_ending = 'unix'
# Format command names consistently as 'lower' or 'upper' case
command_case = 'canonical'
# Format keywords consistently as 'lower' or 'upper' case
keyword_case = 'upper'

7
vendor/assimp/contrib/draco/AUTHORS vendored Normal file
View file

@ -0,0 +1,7 @@
# This is the list of Draco authors for copyright purposes.
#
# This does not necessarily list everyone who has contributed code, since in
# some cases, their employer may be the copyright holder. To see the full list
# of contributors, see the revision history in source control.
Google Inc.
and other contributors

375
vendor/assimp/contrib/draco/BUILDING.md vendored Normal file
View file

@ -0,0 +1,375 @@
_**Contents**_
* [CMake Basics](#cmake-basics)
* [Mac OS X](#mac-os-x)
* [Windows](#windows)
* [CMake Build Configuration](#cmake-build-configuration)
* [Transcoder](#transcoder)
* [Debugging and Optimization](#debugging-and-optimization)
* [Googletest Integration](#googletest-integration)
* [Third Party Libraries](#third-party-libraries)
* [Javascript Encoder/Decoder](#javascript-encoderdecoder)
* [WebAssembly Decoder](#webassembly-decoder)
* [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder)
* [WebAssembly Point Cloud Only Decoder](#webassembly-point-cloud-only-decoder)
* [iOS Builds](#ios-builds)
* [Android Studio Project Integration](#android-studio-project-integration)
* [Native Android Builds](#native-android-builds)
* [vcpkg](#vcpkg)
Building
========
For all platforms, you must first generate the project/make files and then
compile the examples.
CMake Basics
------------
To generate project/make files for the default toolchain on your system, run
`cmake` from a directory where you would like to generate build files, and pass
it the path to your Draco repository.
E.g. Starting from Draco root.
~~~~~ bash
$ mkdir build_dir && cd build_dir
$ cmake ../
~~~~~
On Windows, the above command will produce Visual Studio project files for the
newest Visual Studio detected on the system. On Mac OS X and Linux systems,
the above command will produce a `makefile`.
To control what types of projects are generated, add the `-G` parameter to the
`cmake` command. This argument must be followed by the name of a generator.
Running `cmake` with the `--help` argument will list the available
generators for your system.
Mac OS X
---------
On Mac OS X, run the following command to generate Xcode projects:
~~~~~ bash
$ cmake ../ -G Xcode
~~~~~
Windows
-------
On a Windows box you would run the following command to generate Visual Studio
2019 projects:
~~~~~ bash
C:\Users\nobody> cmake ../ -G "Visual Studio 16 2019" -A Win32
~~~~~
To generate 64-bit Windows Visual Studio 2019 projects:
~~~~~ bash
C:\Users\nobody> cmake ../ -G "Visual Studio 16 2019" -A x64
~~~~~
CMake Build Configuration
-------------------------
Transcoder
----------
Before attempting to build Draco with transcoding support you must run an
additional Git command to obtain the submodules:
~~~~~ bash
# Run this command from within your Draco clone.
$ git submodule update --init
# See below if you prefer to use existing versions of Draco dependencies.
~~~~~
In order to build the `draco_transcoder` target, the transcoding support needs
to be explicitly enabled when you run `cmake`, for example:
~~~~~ bash
$ cmake ../ -DDRACO_TRANSCODER_SUPPORTED=ON
~~~~~
The above option is currently not compatible with our Javascript or WebAssembly
builds but all other use cases are supported. Note that binaries and libraries
built with the transcoder support may result in increased binary sizes of the
produced libraries and executables compared to the default CMake settings.
The following CMake variables can be used to configure Draco to use local
copies of third party dependencies instead of git submodules.
- `DRACO_EIGEN_PATH`: this path must contain an Eigen directory that includes
the Eigen sources.
- `DRACO_FILESYSTEM_PATH`: this path must contain the ghc directory where the
filesystem includes are located.
- `DRACO_TINYGLTF_PATH`: this path must contain tiny_gltf.h and its
dependencies.
When not specified the Draco build requires the presence of the submodules that
are stored within `draco/third_party`.
Debugging and Optimization
--------------------------
Unlike Visual Studio and Xcode projects, the build configuration for make
builds is controlled when you run `cmake`. The following examples demonstrate
various build configurations.
Omitting the build type produces makefiles that use release build flags
by default:
~~~~~ bash
$ cmake ../
~~~~~
A makefile using release (optimized) flags is produced like this:
~~~~~ bash
$ cmake ../ -DCMAKE_BUILD_TYPE=Release
~~~~~
A release build with debug info can be produced as well:
~~~~~ bash
$ cmake ../ -DCMAKE_BUILD_TYPE=RelWithDebInfo
~~~~~
And your standard debug build will be produced using:
~~~~~ bash
$ cmake ../ -DCMAKE_BUILD_TYPE=Debug
~~~~~
To enable the use of sanitizers when the compiler in use supports them, set the
sanitizer type when running CMake:
~~~~~ bash
$ cmake ../ -DDRACO_SANITIZE=address
~~~~~
Googletest Integration
----------------------
Draco includes testing support built using Googletest. The Googletest repository
is included as a submodule of the Draco git repository. Run the following
command to clone the Googletest repository:
~~~~~ bash
$ git submodule update --init
~~~~~
To enable Googletest unit test support the DRACO_TESTS cmake variable must be
turned on at cmake generation time:
~~~~~ bash
$ cmake ../ -DDRACO_TESTS=ON
~~~~~
To run the tests execute `draco_tests` from your build output directory:
~~~~~ bash
$ ./draco_tests
~~~~~
Draco can be configured to use a local Googletest installation. The
`DRACO_GOOGLETEST_PATH` variable overrides the behavior described above and
configures Draco to use the Googletest at the specified path.
Third Party Libraries
---------------------
When Draco is built with transcoding and/or testing support enabled the project
has dependencies on third party libraries:
- [Eigen](https://eigen.tuxfamily.org/)
- Provides various math utilites.
- [Googletest](https://github.com/google/googletest)
- Provides testing support.
- [Gulrak/filesystem](https://github.com/gulrak/filesystem)
- Provides C++17 std::filesystem emulation for pre-C++17 environments.
- [TinyGLTF](https://github.com/syoyo/tinygltf)
- Provides GLTF I/O support.
These dependencies are managed as Git submodules. To obtain the dependencies
run the following command in your Draco repository:
~~~~~ bash
$ git submodule update --init
~~~~~
WebAssembly Decoder
-------------------
The WebAssembly decoder can be built using the existing cmake build file by
passing the path the Emscripten's cmake toolchain file at cmake generation time
in the CMAKE_TOOLCHAIN_FILE variable and enabling the WASM build option.
In addition, the EMSCRIPTEN environment variable must be set to the local path
of the parent directory of the Emscripten tools directory.
~~~~~ bash
# Make the path to emscripten available to cmake.
$ export EMSCRIPTEN=/path/to/emscripten/tools/parent
# Emscripten.cmake can be found within your Emscripten installation directory,
# it should be the subdir: cmake/Modules/Platform/Emscripten.cmake
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=/path/to/Emscripten.cmake -DDRACO_WASM=ON
# Build the WebAssembly decoder.
$ make
# Run the Javascript wrapper through Closure.
$ java -jar closure.jar --compilation_level SIMPLE --js draco_decoder.js --js_output_file draco_wasm_wrapper.js
~~~~~
WebAssembly Mesh Only Decoder
-----------------------------
~~~~~ bash
# cmake command line for mesh only WebAssembly decoder.
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=/path/to/Emscripten.cmake -DDRACO_WASM=ON -DDRACO_POINT_CLOUD_COMPRESSION=OFF
~~~~~
WebAssembly Point Cloud Only Decoder
-----------------------------
~~~~~ bash
# cmake command line for point cloud only WebAssembly decoder.
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=/path/to/Emscripten.cmake -DDRACO_WASM=ON -DDRACO_MESH_COMPRESSION=OFF
~~~~~
Javascript Encoder/Decoder
------------------
The javascript encoder and decoder can be built using the existing cmake build
file by passing the path the Emscripten's cmake toolchain file at cmake
generation time in the CMAKE_TOOLCHAIN_FILE variable.
In addition, the EMSCRIPTEN environment variable must be set to the local path
of the parent directory of the Emscripten tools directory.
*Note* The WebAssembly decoder should be favored over the JavaScript decoder.
~~~~~ bash
# Make the path to emscripten available to cmake.
$ export EMSCRIPTEN=/path/to/emscripten/tools/parent
# Emscripten.cmake can be found within your Emscripten installation directory,
# it should be the subdir: cmake/Modules/Platform/Emscripten.cmake
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=/path/to/Emscripten.cmake
# Build the Javascript encoder and decoder.
$ make
~~~~~
iOS Builds
---------------------
These are the basic commands needed to build Draco for iOS targets.
~~~~~ bash
#arm64
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/arm64-ios.cmake
$ make
#x86_64
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/x86_64-ios.cmake
$ make
#armv7
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/armv7-ios.cmake
$ make
#i386
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/i386-ios.cmake
$ make
~~~~~~
After building for each target the libraries can be merged into a single
universal/fat library using lipo, and then used in iOS applications.
Native Android Builds
---------------------
It's sometimes useful to build Draco command line tools and run them directly on
Android devices via adb.
~~~~~ bash
# This example is for armeabi-v7a.
$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/android.cmake \
-DDRACO_ANDROID_NDK_PATH=path/to/ndk -DANDROID_ABI=armeabi-v7a
$ make
# See the android.cmake toolchain file for additional ANDROID_ABI options and
# other configurable Android variables.
~~~~~
After building the tools they can be moved to an android device via the use of
`adb push`, and then run within an `adb shell` instance.
Android Studio Project Integration
----------------------------------
Tested on Android Studio 3.5.3.
Draco - Static Library
----------------------
To include Draco in an existing or new Android Studio project, reference it
from the `cmake` file of an existing native project that has a minimum SDK
version of 18 or higher. The project must support C++11.
To add Draco to your project:
1. Create a new "Native C++" project.
2. Add the following somewhere within the `CMakeLists.txt` for your project
before the `add_library()` for your project's native-lib:
~~~~~ cmake
# Note "/path/to/draco" must be changed to the path where you have cloned
# the Draco sources.
add_subdirectory(/path/to/draco
${CMAKE_BINARY_DIR}/draco_build)
include_directories("${CMAKE_BINARY_DIR}" /path/to/draco)
~~~~~
3. Add the library target "draco" to the `target_link_libraries()` call for
your project's native-lib. The `target_link_libraries()` call for an
empty activity native project looks like this after the addition of
Draco:
~~~~~ cmake
target_link_libraries( # Specifies the target library.
native-lib
# Tells cmake this build depends on libdraco.
draco
# Links the target library to the log library
# included in the NDK.
${log-lib} )
vcpkg
---------------------
You can download and install Draco using the
[vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install draco
The Draco port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please
[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the
vcpkg repository.

106
vendor/assimp/contrib/draco/CMAKE.md vendored Normal file
View file

@ -0,0 +1,106 @@
# CMake Build System Overview
[TOC]
This document provides a general layout of the Draco CMake build system.
## Core Build System Files
These files are listed in order of interest to maintainers of the build system.
- `CMakeLists.txt` is the main driver of the build system. It's responsible
for defining targets and source lists, surfacing build system options, and
tying the components of the build system together.
- `cmake/draco_build_definitions.cmake` defines the macro
`draco_set_build_definitions()`, which is called from `CMakeLists.txt` to
configure include paths, compiler and linker flags, library settings,
platform speficic configuration, and other build system settings that
depend on optional build configurations.
- `cmake/draco_targets.cmake` defines the macros `draco_add_library()` and
`draco_add_executable()` which are used to create all targets in the CMake
build. These macros attempt to behave in a manner that loosely mirrors the
blaze `cc_library()` and `cc_binary()` commands. Note that
`draco_add_executable()` is also used for tests.
- `cmake/draco_emscripten.cmake` handles Emscripten SDK integration. It
defines several Emscripten specific macros that are required to build the
Emscripten specific targets defined in `CMakeLists.txt`.
- `cmake/draco_flags.cmake` defines macros related to compiler and linker
flags. Testing macros, macros for isolating flags to specific source files,
and the main flag configuration function for the library are defined here.
- `cmake/draco_options.cmake` defines macros that control optional features
of draco, and help track draco library and build system options.
- `cmake/draco_install.cmake` defines the draco install target.
- `cmake/draco_cpu_detection.cmake` determines the optimization types to
enable based on target system processor as reported by CMake.
- `cmake/draco_intrinsics.cmake` manages flags for source files that use
intrinsics. It handles detection of whether flags are necessary, and the
application of the flags to the sources that need them when they are
required.
## Helper and Utility Files
- `.cmake-format.py` Defines coding style for cmake-format.
- `cmake/draco_helpers.cmake` defines utility macros.
- `cmake/draco_sanitizer.cmake` defines the `draco_configure_sanitizer()`
macro, which implements support for `DRACO_SANITIZE`. It handles the
compiler and linker flags necessary for using sanitizers like asan and msan.
- `cmake/draco_variables.cmake` defines macros for tracking and control of
draco build system variables.
## Toolchain Files
These files help facilitate cross compiling of draco for various targets.
- `cmake/toolchains/aarch64-linux-gnu.cmake` provides cross compilation
support for arm64 targets.
- `cmake/toolchains/android.cmake` provides cross compilation support for
Android targets.
- `cmake/toolchains/arm-linux-gnueabihf.cmake` provides cross compilation
support for armv7 targets.
- `cmake/toolchains/arm64-ios.cmake`, `cmake/toolchains/armv7-ios.cmake`,
and `cmake/toolchains/armv7s-ios.cmake` provide support for iOS.
- `cmake/toolchains/arm64-linux-gcc.cmake` and
`cmake/toolchains/armv7-linux-gcc.cmake` are deprecated, but remain for
compatibility. `cmake/toolchains/android.cmake` should be used instead.
- `cmake/toolchains/arm64-android-ndk-libcpp.cmake`,
`cmake/toolchains/armv7-android-ndk-libcpp.cmake`,
`cmake/toolchains/x86-android-ndk-libcpp.cmake`, and
`cmake/toolchains/x86_64-android-ndk-libcpp.cmake` are deprecated, but
remain for compatibility. `cmake/toolchains/android.cmake` should be used
instead.
- `cmake/toolchains/i386-ios.cmake` and `cmake/toolchains/x86_64-ios.cmake`
provide support for the iOS simulator.
- `cmake/toolchains/android-ndk-common.cmake` and
`cmake/toolchains/arm-ios-common.cmake` are support files used by other
toolchain files.
## Template Files
These files are inputs to the CMake build and are used to generate inputs to the
build system output by CMake.
- `cmake/draco-config.cmake.template` is used to produce
draco-config.cmake. draco-config.cmake can be used by CMake to find draco
when another CMake project depends on draco.
- `cmake/draco.pc.template` is used to produce draco's pkg-config file.
Some build systems use pkg-config to configure include and library paths
when they depend upon third party libraries like draco.

1156
vendor/assimp/contrib/draco/CMakeLists.txt vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
Want to contribute? Great! First, read this page (including the small print at the end).
### Before you contribute
Before we can use your code, you must sign the
[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual)
(CLA), which you can do online. The CLA is necessary mainly because you own the
copyright to your changes, even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things—for instance that you'll tell us if you
know that your code infringes on other people's patents. You don't have to sign
the CLA until after you've submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase.
Before you start working on a larger contribution, you should get in touch with
us first through the issue tracker with your idea so that we can help out and
possibly guide you. Coordinating up front makes it much easier to avoid
frustration later on.
### Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose.
Please make sure that your code conforms with our
[coding style guidelines](https://google.github.io/styleguide/cppguide.html).
### The small print
Contributions made by corporations are covered by a different agreement than
the one above, the
[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate).

252
vendor/assimp/contrib/draco/LICENSE vendored Normal file
View file

@ -0,0 +1,252 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------------------
Files: docs/assets/js/ASCIIMathML.js
Copyright (c) 2014 Peter Jipsen and other ASCIIMathML.js contributors
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.
--------------------------------------------------------------------------------
Files: docs/assets/css/pygments/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>

616
vendor/assimp/contrib/draco/README.md vendored Normal file
View file

@ -0,0 +1,616 @@
<p align="center">
<img width="350px" src="docs/artwork/draco3d-vert.svg" />
</p>
[![draco-ci](https://github.com/google/draco/workflows/draco-ci/badge.svg?branch=master)](https://github.com/google/draco/actions/workflows/ci.yml)
News
=======
Attention GStatic users: the Draco team strongly recommends using the versioned
URLs for accessing Draco GStatic content. If you are using the URLs that include
the `v1/decoders` substring within the URL, edge caching and GStatic propagation
delays can result in transient errors that can be difficult to diagnose when
new Draco releases are launched. To avoid the issue pin your sites to a
versioned release.
### Version 1.5.7 release:
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
to be recommended. To use v1.5.7, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.5.7/*
* Added support for normalized attributes to Emscripten encoder API.
* Bug fixes.
* Security fixes.
### Version 1.5.6 release:
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
to be recommended. To use v1.5.6, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.5.6/*
* The CMake flag DRACO_DEBUG_MSVC_WARNINGS has been replaced with
DRACO_DEBUG_COMPILER_WARNINGS, and the behavior has changed. It is now a
boolean flag defined in draco_options.cmake.
* Bug fixes.
* Security fixes.
### Version 1.5.5 release:
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
to be recommended. To use v1.5.5, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.5.5/*
* Bug fix: https://github.com/google/draco/issues/935
### Version 1.5.4 release:
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
to be recommended. To use v1.5.4, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.5.4/*
* Added partial support for glTF extensions EXT_mesh_features and
EXT_structural_metadata.
* Bug fixes.
* Security fixes.
### Version 1.5.3 release:
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
to be recommended. To use v1.5.3, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.5.3/*
* Bug fixes.
### Version 1.5.2 release
* This is the same as v1.5.1 with the following two bug fixes:
* Fixes DRACO_TRANSCODER_SUPPORTED enabled builds.
* ABI version updated.
### Version 1.5.1 release
* Adds assertion enabled Emscripten builds to the release, and a subset of the
assertion enabled builds to GStatic. See the file listing below.
* Custom paths to third party dependencies are now supported. See BUILDING.md
for more information.
* The CMake configuration file draco-config.cmake is now tested and known to
work for using Draco in Linux, MacOS, and Windows CMake projects. See the
`install_test` subdirectory of `src/draco/tools` for more information.
* Bug fixes.
### Version 1.5.0 release
* Adds the draco_transcoder tool. See the section below on the glTF transcoding
tool, and BUILDING.md for build and dependency information.
* Some changes to configuration variables have been made for this release:
- The DRACO_GLTF flag has been renamed to DRACO_GLTF_BITSTREAM to help
increase understanding of its purpose, which is to limit Draco features to
those included in the Draco glTF specification.
- Variables exported in CMake via draco-config.cmake and find-draco.cmake
(formerly FindDraco.cmake) have been renamed. It's unlikely that this
impacts any existing projects as the aforementioned files were not formed
correctly. See [PR775](https://github.com/google/draco/pull/775) for full
details of the changes.
* A CMake version file has been added.
* The CMake install target now uses absolute paths direct from CMake instead
of building them using CMAKE_INSTALL_PREFIX. This was done to make Draco
easier to use for downstream packagers and should have little to no impact on
users picking up Draco from source.
* Certain MSVC warnings have had their levels changed via compiler flag to
reduce the amount of noise output by the MSVC compilers. Set MSVC warning
level to 4, or define DRACO_DEBUG_MSVC_WARNINGS at CMake configuration time
to restore previous behavior.
* Bug fixes.
### Version 1.4.3 release
* Using the versioned www.gstatic.com WASM and Javascript decoders continues
to be recommended. To use v1.4.3, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.4.3/*
* Bug fixes
### Version 1.4.1 release
* Using the versioned www.gstatic.com WASM and Javascript decoders is now
recommended. To use v1.4.1, use this URL:
* https://www.gstatic.com/draco/versioned/decoders/1.4.1/*
* Replace the * with the files to load. E.g.
* https://www.gstatic.com/draco/versioned/decoders/1.4.1/draco_decoder.js
* This works with the v1.3.6 and v1.4.0 releases, and will work with future
Draco releases.
* Bug fixes
### Version 1.4.0 release
* WASM and JavaScript decoders are hosted from a static URL.
* It is recommended to always pull your Draco WASM and JavaScript decoders from this URL:
* https://www.gstatic.com/draco/v1/decoders/*
* Replace * with the files to load. E.g.
* https://www.gstatic.com/draco/v1/decoders/draco_decoder_gltf.wasm
* Users will benefit from having the Draco decoder in cache as more sites start using the static URL
* Changed npm modules to use WASM, which increased performance by ~200%.
* Updated Emscripten to 2.0.
* This causes the Draco codec modules to return a promise instead of the module directly.
* Please see the example code on how to handle the promise.
* Changed NORMAL quantization default to 8.
* Added new array API to decoder and deprecated DecoderBuffer.
* See PR https://github.com/google/draco/issues/513 for more information.
* Changed WASM/JavaScript behavior of catching exceptions.
* See issue https://github.com/google/draco/issues/629 for more information.
* Code cleanup.
* Emscripten builds now disable NODEJS_CATCH_EXIT and NODEJS_CATCH_REJECTION.
* Authors of a CLI tool might want to add their own error handlers.
* Added Maya plugin builds.
* Unity plugin builds updated.
* Builds are now stored as archives.
* Added iOS build.
* Unity users may want to look into https://github.com/atteneder/DracoUnity.
* Bug fixes.
### Version 1.3.6 release
* WASM and JavaScript decoders are now hosted from a static URL
* It is recommended to always pull your Draco WASM and JavaScript decoders from this URL:
* https://www.gstatic.com/draco/v1/decoders/*
* Replace * with the files to load. E.g.
* https://www.gstatic.com/draco/v1/decoders/draco_decoder_gltf.wasm
* Users will benefit from having the Draco decoder in cache as more sites start using the static URL
* Changed web examples to pull Draco decoders from static URL
* Added new API to Draco WASM decoder, which increased performance by ~15%
* Decreased Draco WASM decoder size by ~20%
* Added support for generic and multiple attributes to Draco Unity plug-ins
* Added new API to Draco Unity, which increased decoder performance by ~15%
* Changed quantization defaults:
* POSITION: 11
* NORMAL: 7
* TEX_COORD: 10
* COLOR: 8
* GENERIC: 8
* Code cleanup
* Bug fixes
### Version 1.3.5 release
* Added option to build Draco for Universal Scene Description
* Code cleanup
* Bug fixes
### Version 1.3.4 release
* Released Draco Animation code
* Fixes for Unity
* Various file location and name changes
### Version 1.3.3 release
* Added ExpertEncoder to the Javascript API
* Allows developers to set quantization options per attribute id
* Bug fixes
### Version 1.3.2 release
* Bug fixes
### Version 1.3.1 release
* Fix issue with multiple attributes when skipping an attribute transform
### Version 1.3.0 release
* Improved kD-tree based point cloud encoding
* Now applicable to point clouds with any number of attributes
* Support for all integer attribute types and quantized floating point types
* Improved mesh compression up to 10% (on average ~2%)
* For meshes, the 1.3.0 bitstream is fully compatible with 1.2.x decoders
* Improved Javascript API
* Added support for all signed and unsigned integer types
* Added support for point clouds to our Javascript encoder API
* Added support for integer properties to the PLY decoder
* Bug fixes
### Previous releases
https://github.com/google/draco/releases
Description
===========
Draco is a library for compressing and decompressing 3D geometric [meshes] and
[point clouds]. It is intended to improve the storage and transmission of 3D
graphics.
Draco was designed and built for compression efficiency and speed. The code
supports compressing points, connectivity information, texture coordinates,
color information, normals, and any other generic attributes associated with
geometry. With Draco, applications using 3D graphics can be significantly
smaller without compromising visual fidelity. For users, this means apps can
now be downloaded faster, 3D graphics in the browser can load quicker, and VR
and AR scenes can now be transmitted with a fraction of the bandwidth and
rendered quickly.
Draco is released as C++ source code that can be used to compress 3D graphics
as well as C++ and Javascript decoders for the encoded data.
_**Contents**_
* [Building](#building)
* [Usage](#usage)
* [Unity](#unity)
* [WASM and JavaScript Decoders](#WASM-and-JavaScript-Decoders)
* [Command Line Applications](#command-line-applications)
* [Encoding Tool](#encoding-tool)
* [Encoding Point Clouds](#encoding-point-clouds)
* [Decoding Tool](#decoding-tool)
* [glTF Transcoding Tool](#gltf-transcoding-tool)
* [C++ Decoder API](#c-decoder-api)
* [Javascript Encoder API](#javascript-encoder-api)
* [Javascript Decoder API](#javascript-decoder-api)
* [Javascript Decoder Performance](#javascript-decoder-performance)
* [Metadata API](#metadata-api)
* [NPM Package](#npm-package)
* [three.js Renderer Example](#threejs-renderer-example)
* [GStatic Javascript Builds](#gstatic-javascript-builds)
* [Support](#support)
* [License](#license)
* [References](#references)
Building
========
See [BUILDING](BUILDING.md) for building instructions.
Usage
======
Unity
-----
For the best information about using Unity with Draco please visit https://github.com/atteneder/DracoUnity
For a simple example of using Unity with Draco see [README](unity/README.md) in the unity folder.
WASM and JavaScript Decoders
----------------------------
It is recommended to always pull your Draco WASM and JavaScript decoders from:
~~~~~ bash
https://www.gstatic.com/draco/v1/decoders/
~~~~~
Users will benefit from having the Draco decoder in cache as more sites start using the static URL.
Command Line Applications
------------------------
The default target created from the build files will be the `draco_encoder`
and `draco_decoder` command line applications. Additionally, `draco_transcoder`
is generated when CMake is run with the DRACO_TRANSCODER_SUPPORTED variable set
to ON (see [BUILDING](BUILDING.md#transcoder) for more details). For all
applications, if you run them without any arguments or `-h`, the applications
will output usage and options.
Encoding Tool
-------------
`draco_encoder` will read OBJ, STL or PLY files as input, and output
Draco-encoded files. We have included Stanford's [Bunny] mesh for testing. The
basic command line looks like this:
~~~~~ bash
./draco_encoder -i testdata/bun_zipper.ply -o out.drc
~~~~~
A value of `0` for the quantization parameter will not perform any quantization
on the specified attribute. Any value other than `0` will quantize the input
values for the specified attribute to that number of bits. For example:
~~~~~ bash
./draco_encoder -i testdata/bun_zipper.ply -o out.drc -qp 14
~~~~~
will quantize the positions to 14 bits (default is 11 for the position
coordinates).
In general, the more you quantize your attributes the better compression rate
you will get. It is up to your project to decide how much deviation it will
tolerate. In general, most projects can set quantization values of about `11`
without any noticeable difference in quality.
The compression level (`-cl`) parameter turns on/off different compression
features.
~~~~~ bash
./draco_encoder -i testdata/bun_zipper.ply -o out.drc -cl 8
~~~~~
In general, the highest setting, `10`, will have the most compression but
worst decompression speed. `0` will have the least compression, but best
decompression speed. The default setting is `7`.
Encoding Point Clouds
---------------------
You can encode point cloud data with `draco_encoder` by specifying the
`-point_cloud` parameter. If you specify the `-point_cloud` parameter with a
mesh input file, `draco_encoder` will ignore the connectivity data and encode
the positions from the mesh file.
~~~~~ bash
./draco_encoder -point_cloud -i testdata/bun_zipper.ply -o out.drc
~~~~~
This command line will encode the mesh input as a point cloud, even though the
input might not produce compression that is representative of other point
clouds. Specifically, one can expect much better compression rates for larger
and denser point clouds.
Decoding Tool
-------------
`draco_decoder` will read Draco files as input, and output OBJ, STL or PLY
files. The basic command line looks like this:
~~~~~ bash
./draco_decoder -i in.drc -o out.obj
~~~~~
glTF Transcoding Tool
---------------------
`draco_transcoder` can be used to add Draco compression to glTF assets. The
basic command line looks like this:
~~~~~ bash
./draco_transcoder -i in.glb -o out.glb
~~~~~
This command line will add geometry compression to all meshes in the `in.glb`
file. Quantization values for different glTF attributes can be specified
similarly to the `draco_encoder` tool. For example `-qp` can be used to define
quantization of the position attribute:
~~~~~ bash
./draco_transcoder -i in.glb -o out.glb -qp 12
~~~~~
C++ Decoder API
---------------
If you'd like to add decoding to your applications you will need to include
the `draco_dec` library. In order to use the Draco decoder you need to
initialize a `DecoderBuffer` with the compressed data. Then call
`DecodeMeshFromBuffer()` to return a decoded mesh object or call
`DecodePointCloudFromBuffer()` to return a decoded `PointCloud` object. For
example:
~~~~~ cpp
draco::DecoderBuffer buffer;
buffer.Init(data.data(), data.size());
const draco::EncodedGeometryType geom_type =
draco::GetEncodedGeometryType(&buffer);
if (geom_type == draco::TRIANGULAR_MESH) {
unique_ptr<draco::Mesh> mesh = draco::DecodeMeshFromBuffer(&buffer);
} else if (geom_type == draco::POINT_CLOUD) {
unique_ptr<draco::PointCloud> pc = draco::DecodePointCloudFromBuffer(&buffer);
}
~~~~~
Please see [src/draco/mesh/mesh.h](src/draco/mesh/mesh.h) for the full `Mesh` class interface and
[src/draco/point_cloud/point_cloud.h](src/draco/point_cloud/point_cloud.h) for the full `PointCloud` class interface.
Javascript Encoder API
----------------------
The Javascript encoder is located in `javascript/draco_encoder.js`. The encoder
API can be used to compress mesh and point cloud. In order to use the encoder,
you need to first create an instance of `DracoEncoderModule`. Then use this
instance to create `MeshBuilder` and `Encoder` objects. `MeshBuilder` is used
to construct a mesh from geometry data that could be later compressed by
`Encoder`. First create a mesh object using `new encoderModule.Mesh()` . Then,
use `AddFacesToMesh()` to add indices to the mesh and use
`AddFloatAttributeToMesh()` to add attribute data to the mesh, e.g. position,
normal, color and texture coordinates. After a mesh is constructed, you could
then use `EncodeMeshToDracoBuffer()` to compress the mesh. For example:
~~~~~ js
const mesh = {
indices : new Uint32Array(indices),
vertices : new Float32Array(vertices),
normals : new Float32Array(normals)
};
const encoderModule = DracoEncoderModule();
const encoder = new encoderModule.Encoder();
const meshBuilder = new encoderModule.MeshBuilder();
const dracoMesh = new encoderModule.Mesh();
const numFaces = mesh.indices.length / 3;
const numPoints = mesh.vertices.length;
meshBuilder.AddFacesToMesh(dracoMesh, numFaces, mesh.indices);
meshBuilder.AddFloatAttributeToMesh(dracoMesh, encoderModule.POSITION,
numPoints, 3, mesh.vertices);
if (mesh.hasOwnProperty('normals')) {
meshBuilder.AddFloatAttributeToMesh(
dracoMesh, encoderModule.NORMAL, numPoints, 3, mesh.normals);
}
if (mesh.hasOwnProperty('colors')) {
meshBuilder.AddFloatAttributeToMesh(
dracoMesh, encoderModule.COLOR, numPoints, 3, mesh.colors);
}
if (mesh.hasOwnProperty('texcoords')) {
meshBuilder.AddFloatAttributeToMesh(
dracoMesh, encoderModule.TEX_COORD, numPoints, 3, mesh.texcoords);
}
if (method === "edgebreaker") {
encoder.SetEncodingMethod(encoderModule.MESH_EDGEBREAKER_ENCODING);
} else if (method === "sequential") {
encoder.SetEncodingMethod(encoderModule.MESH_SEQUENTIAL_ENCODING);
}
const encodedData = new encoderModule.DracoInt8Array();
// Use default encoding setting.
const encodedLen = encoder.EncodeMeshToDracoBuffer(dracoMesh,
encodedData);
encoderModule.destroy(dracoMesh);
encoderModule.destroy(encoder);
encoderModule.destroy(meshBuilder);
~~~~~
Please see [src/draco/javascript/emscripten/draco_web_encoder.idl](src/draco/javascript/emscripten/draco_web_encoder.idl) for the full API.
Javascript Decoder API
----------------------
The Javascript decoder is located in [javascript/draco_decoder.js](javascript/draco_decoder.js). The
Javascript decoder can decode mesh and point cloud. In order to use the
decoder, you must first create an instance of `DracoDecoderModule`. The
instance is then used to create `DecoderBuffer` and `Decoder` objects. Set
the encoded data in the `DecoderBuffer`. Then call `GetEncodedGeometryType()`
to identify the type of geometry, e.g. mesh or point cloud. Then call either
`DecodeBufferToMesh()` or `DecodeBufferToPointCloud()`, which will return
a Mesh object or a point cloud. For example:
~~~~~ js
// Create the Draco decoder.
const decoderModule = DracoDecoderModule();
const buffer = new decoderModule.DecoderBuffer();
buffer.Init(byteArray, byteArray.length);
// Create a buffer to hold the encoded data.
const decoder = new decoderModule.Decoder();
const geometryType = decoder.GetEncodedGeometryType(buffer);
// Decode the encoded geometry.
let outputGeometry;
let status;
if (geometryType == decoderModule.TRIANGULAR_MESH) {
outputGeometry = new decoderModule.Mesh();
status = decoder.DecodeBufferToMesh(buffer, outputGeometry);
} else {
outputGeometry = new decoderModule.PointCloud();
status = decoder.DecodeBufferToPointCloud(buffer, outputGeometry);
}
// You must explicitly delete objects created from the DracoDecoderModule
// or Decoder.
decoderModule.destroy(outputGeometry);
decoderModule.destroy(decoder);
decoderModule.destroy(buffer);
~~~~~
Please see [src/draco/javascript/emscripten/draco_web_decoder.idl](src/draco/javascript/emscripten/draco_web_decoder.idl) for the full API.
Javascript Decoder Performance
------------------------------
The Javascript decoder is built with dynamic memory. This will let the decoder
work with all of the compressed data. But this option is not the fastest.
Pre-allocating the memory sees about a 2x decoder speed improvement. If you
know all of your project's memory requirements, you can turn on static memory
by changing `CMakeLists.txt` accordingly.
Metadata API
------------
Starting from v1.0, Draco provides metadata functionality for encoding data
other than geometry. It could be used to encode any custom data along with the
geometry. For example, we can enable metadata functionality to encode the name
of attributes, name of sub-objects and customized information.
For one mesh and point cloud, it can have one top-level geometry metadata class.
The top-level metadata then can have hierarchical metadata. Other than that,
the top-level metadata can have metadata for each attribute which is called
attribute metadata. The attribute metadata should be initialized with the
correspondent attribute id within the mesh. The metadata API is provided both
in C++ and Javascript.
For example, to add metadata in C++:
~~~~~ cpp
draco::PointCloud pc;
// Add metadata for the geometry.
std::unique_ptr<draco::GeometryMetadata> metadata =
std::unique_ptr<draco::GeometryMetadata>(new draco::GeometryMetadata());
metadata->AddEntryString("description", "This is an example.");
pc.AddMetadata(std::move(metadata));
// Add metadata for attributes.
draco::GeometryAttribute pos_att;
pos_att.Init(draco::GeometryAttribute::POSITION, nullptr, 3,
draco::DT_FLOAT32, false, 12, 0);
const uint32_t pos_att_id = pc.AddAttribute(pos_att, false, 0);
std::unique_ptr<draco::AttributeMetadata> pos_metadata =
std::unique_ptr<draco::AttributeMetadata>(
new draco::AttributeMetadata(pos_att_id));
pos_metadata->AddEntryString("name", "position");
// Directly add attribute metadata to geometry.
// You can do this without explicitly add |GeometryMetadata| to mesh.
pc.AddAttributeMetadata(pos_att_id, std::move(pos_metadata));
~~~~~
To read metadata from a geometry in C++:
~~~~~ cpp
// Get metadata for the geometry.
const draco::GeometryMetadata *pc_metadata = pc.GetMetadata();
// Request metadata for a specific attribute.
const draco::AttributeMetadata *requested_pos_metadata =
pc.GetAttributeMetadataByStringEntry("name", "position");
~~~~~
Please see [src/draco/metadata](src/draco/metadata) and [src/draco/point_cloud](src/draco/point_cloud) for the full API.
NPM Package
-----------
Draco NPM NodeJS package is located in [javascript/npm/draco3d](javascript/npm/draco3d). Please see the
doc in the folder for detailed usage.
three.js Renderer Example
-------------------------
Here's an [example] of a geometric compressed with Draco loaded via a
Javascript decoder using the `three.js` renderer.
Please see the [javascript/example/README.md](javascript/example/README.md) file for more information.
GStatic Javascript Builds
=========================
Prebuilt versions of the Emscripten-built Draco javascript decoders are hosted
on www.gstatic.com in version labeled directories:
https://www.gstatic.com/draco/versioned/decoders/VERSION/*
As of the v1.4.3 release the files available are:
- [draco_decoder.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder.js)
- [draco_decoder.wasm](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder.wasm)
- [draco_decoder_gltf.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder_gltf.js)
- [draco_decoder_gltf.wasm](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_decoder_gltf.wasm)
- [draco_wasm_wrapper.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_wasm_wrapper.js)
- [draco_wasm_wrapper_gltf.js](https://www.gstatic.com/draco/versioned/decoders/1.4.3/draco_wasm_wrapper_gltf.js)
Beginning with the v1.5.1 release assertion enabled builds of the following
files are available:
- [draco_decoder.js](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_decoder.js)
- [draco_decoder.wasm](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_decoder.wasm)
- [draco_wasm_wrapper.js](https://www.gstatic.com/draco/versioned/decoders/1.5.1/with_asserts/draco_wasm_wrapper.js)
Support
=======
For questions/comments please email <draco-3d-discuss@googlegroups.com>
If you have found an error in this library, please file an issue at
<https://github.com/google/draco/issues>
Patches are encouraged, and may be submitted by forking this project and
submitting a pull request through GitHub. See [CONTRIBUTING] for more detail.
License
=======
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
<http://www.apache.org/licenses/LICENSE-2.0>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
References
==========
[example]:https://storage.googleapis.com/demos.webmproject.org/draco/draco_loader_throw.html
[meshes]: https://en.wikipedia.org/wiki/Polygon_mesh
[point clouds]: https://en.wikipedia.org/wiki/Point_cloud
[Bunny]: https://graphics.stanford.edu/data/3Dscanrep/
[CONTRIBUTING]: https://raw.githubusercontent.com/google/draco/master/CONTRIBUTING.md
Bunny model from Stanford's graphic department <https://graphics.stanford.edu/data/3Dscanrep/>

View file

@ -0,0 +1,3 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/draco-targets.cmake")

View file

@ -0,0 +1,6 @@
Name: @PROJECT_NAME@
Description: Draco geometry de(com)pression library.
Version: @DRACO_VERSION@
Cflags: -I@includes_path@
Libs: -L@libs_path@ -ldraco
Libs.private: @CMAKE_THREAD_LIBS_INIT@

View file

@ -0,0 +1,157 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_
set(DRACO_CMAKE_DRACO_BUILD_DEFINITIONS_CMAKE_ 1)
# Utility for controlling the main draco library dependency. This changes in
# shared builds, and when an optional target requires a shared library build.
macro(set_draco_target)
if(MSVC)
set(draco_dependency draco)
set(draco_plugin_dependency ${draco_dependency})
else()
if(BUILD_SHARED_LIBS)
set(draco_dependency draco_shared)
else()
set(draco_dependency draco_static)
endif()
set(draco_plugin_dependency draco_static)
endif()
endmacro()
# Configures flags and sets build system globals.
macro(draco_set_build_definitions)
string(TOLOWER "${CMAKE_BUILD_TYPE}" build_type_lowercase)
if(build_type_lowercase MATCHES "rel" AND DRACO_FAST)
if(MSVC)
list(APPEND draco_msvc_cxx_flags "/Ox")
else()
list(APPEND draco_base_cxx_flags "-O3")
endif()
endif()
draco_load_version_info()
# Library version info. See the libtool docs for updating the values:
# https://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
#
# c=<current>, r=<revision>, a=<age>
#
# libtool generates a .so file as .so.[c-a].a.r, while -version-info c:r:a is
# passed to libtool.
#
# We set DRACO_SOVERSION = [c-a].a.r
set(LT_CURRENT 9)
set(LT_REVISION 0)
set(LT_AGE 0)
math(EXPR DRACO_SOVERSION_MAJOR "${LT_CURRENT} - ${LT_AGE}")
set(DRACO_SOVERSION "${DRACO_SOVERSION_MAJOR}.${LT_AGE}.${LT_REVISION}")
unset(LT_CURRENT)
unset(LT_REVISION)
unset(LT_AGE)
list(APPEND draco_include_paths "${draco_root}" "${draco_root}/src"
"${draco_build}")
if(DRACO_TRANSCODER_SUPPORTED)
draco_setup_eigen()
draco_setup_filesystem()
draco_setup_tinygltf()
endif()
list(APPEND draco_defines "DRACO_CMAKE=1"
"DRACO_FLAGS_SRCDIR=\"${draco_root}\""
"DRACO_FLAGS_TMPDIR=\"/tmp\"")
if(MSVC OR WIN32)
list(APPEND draco_defines "_CRT_SECURE_NO_DEPRECATE=1" "NOMINMAX=1")
if(BUILD_SHARED_LIBS)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
endif()
endif()
if(NOT MSVC)
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
# Ensure 64-bit platforms can support large files.
list(APPEND draco_defines "_LARGEFILE_SOURCE" "_FILE_OFFSET_BITS=64")
endif()
if(NOT DRACO_DEBUG_COMPILER_WARNINGS)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
list(APPEND draco_clang_cxx_flags
"-Wno-implicit-const-int-float-conversion")
else()
list(APPEND draco_base_cxx_flags "-Wno-deprecated-declarations")
endif()
endif()
endif()
if(ANDROID)
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a")
set(CMAKE_ANDROID_ARM_MODE ON)
endif()
endif()
set_draco_target()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6")
# Quiet warnings in copy-list-initialization where {} elision has always
# been allowed.
list(APPEND draco_clang_cxx_flags "-Wno-missing-braces")
endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "7")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7")
# Quiet gcc 6 vs 7 abi warnings:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728
list(APPEND draco_base_cxx_flags "-Wno-psabi")
list(APPEND ABSL_GCC_FLAGS "-Wno-psabi")
endif()
endif()
endif()
# Source file names ending in these suffixes will have the appropriate
# compiler flags added to their compile commands to enable intrinsics.
set(draco_neon_source_file_suffix "neon.cc")
set(draco_sse4_source_file_suffix "sse4.cc")
if((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
VERSION_LESS 5)
OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"
AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4))
message(
WARNING "GNU/GCC < v5 or Clang/LLVM < v4, ENABLING COMPATIBILITY MODE.")
draco_enable_feature(FEATURE "DRACO_OLD_GCC")
endif()
if(EMSCRIPTEN)
draco_check_emscripten_environment()
draco_get_required_emscripten_flags(
FLAG_LIST_VAR_COMPILER draco_base_cxx_flags
FLAG_LIST_VAR_LINKER draco_base_exe_linker_flags)
endif()
draco_configure_sanitizer()
endmacro()

View file

@ -0,0 +1,42 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_
set(DRACO_CMAKE_DRACO_CPU_DETECTION_CMAKE_ 1)
# Detect optimizations available for the current target CPU.
macro(draco_optimization_detect)
if(DRACO_ENABLE_OPTIMIZATIONS)
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" cpu_lowercase)
if(cpu_lowercase MATCHES "^arm|^aarch64")
set(draco_have_neon ON)
elseif(cpu_lowercase MATCHES "^x86|amd64")
set(draco_have_sse4 ON)
endif()
endif()
if(draco_have_neon AND DRACO_ENABLE_NEON)
list(APPEND draco_defines "DRACO_ENABLE_NEON=1")
else()
list(APPEND draco_defines "DRACO_ENABLE_NEON=0")
endif()
if(draco_have_sse4 AND DRACO_ENABLE_SSE4_1)
list(APPEND draco_defines "DRACO_ENABLE_SSE4_1=1")
else()
list(APPEND draco_defines "DRACO_ENABLE_SSE4_1=0")
endif()
endmacro()

View file

@ -0,0 +1,136 @@
# Copyright 2022 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_DEPENDENCIES_CMAKE)
return()
endif()
set(DRACO_CMAKE_DRACO_DEPENDENCIES_CMAKE 1)
include("${draco_root}/cmake/draco_variables.cmake")
# Each variable holds a user specified custom path to a local copy of the
# sources that belong to each project that Draco depends on. When paths are
# empty the build will be generated pointing to the Draco git submodules.
# Otherwise the paths specified by the user will be used in the build
# configuration.
# Path to the Eigen. The path must contain the Eigen directory.
set(DRACO_EIGEN_PATH)
draco_track_configuration_variable(DRACO_EIGEN_PATH)
# Path to the gulrak/filesystem installation. The path specified must contain
# the ghc subdirectory that houses the filesystem includes.
set(DRACO_FILESYSTEM_PATH)
draco_track_configuration_variable(DRACO_FILESYSTEM_PATH)
# Path to the googletest installation. The path must be to the root of the
# Googletest project directory.
set(DRACO_GOOGLETEST_PATH)
draco_track_configuration_variable(DRACO_GOOGLETEST_PATH)
# Path to the syoyo/tinygltf installation. The path must be to the root of the
# project directory.
set(DRACO_TINYGLTF_PATH)
draco_track_configuration_variable(DRACO_TINYGLTF_PATH)
# Utility macro for killing the build due to a missing submodule directory.
macro(draco_die_missing_submodule dir)
message(FATAL_ERROR "${dir} missing, run git submodule update --init")
endmacro()
# Determines the Eigen location and updates the build configuration accordingly.
macro(draco_setup_eigen)
if(DRACO_EIGEN_PATH)
set(eigen_path "${DRACO_EIGEN_PATH}")
if(NOT IS_DIRECTORY "${eigen_path}")
message(FATAL_ERROR "DRACO_EIGEN_PATH does not exist.")
endif()
else()
set(eigen_path "${draco_root}/third_party/eigen")
if(NOT IS_DIRECTORY "${eigen_path}")
draco_die_missing_submodule("${eigen_path}")
endif()
endif()
set(eigen_include_path "${eigen_path}/Eigen")
if(NOT EXISTS "${eigen_path}/Eigen")
message(FATAL_ERROR "The eigen path does not contain an Eigen directory.")
endif()
list(APPEND draco_include_paths "${eigen_path}")
endmacro()
# Determines the gulrak/filesystem location and updates the build configuration
# accordingly.
macro(draco_setup_filesystem)
if(DRACO_FILESYSTEM_PATH)
set(fs_path "${DRACO_FILESYSTEM_PATH}")
if(NOT IS_DIRECTORY "${fs_path}")
message(FATAL_ERROR "DRACO_FILESYSTEM_PATH does not exist.")
endif()
else()
set(fs_path "${draco_root}/third_party/filesystem/include")
if(NOT IS_DIRECTORY "${fs_path}")
draco_die_missing_submodule("${fs_path}")
endif()
endif()
list(APPEND draco_include_paths "${fs_path}")
endmacro()
# Determines the Googletest location and sets up include and source list vars
# for the draco_tests build.
macro(draco_setup_googletest)
if(DRACO_GOOGLETEST_PATH)
set(gtest_path "${DRACO_GOOGLETEST_PATH}")
if(NOT IS_DIRECTORY "${gtest_path}")
message(FATAL_ERROR "DRACO_GOOGLETEST_PATH does not exist.")
endif()
else()
set(gtest_path "${draco_root}/third_party/googletest")
endif()
list(APPEND draco_test_include_paths ${draco_include_paths}
"${gtest_path}/include" "${gtest_path}/googlemock"
"${gtest_path}/googletest/include" "${gtest_path}/googletest")
list(APPEND draco_gtest_all "${gtest_path}/googletest/src/gtest-all.cc")
list(APPEND draco_gtest_main "${gtest_path}/googletest/src/gtest_main.cc")
endmacro()
# Determines the location of TinyGLTF and updates the build configuration
# accordingly.
macro(draco_setup_tinygltf)
if(DRACO_TINYGLTF_PATH)
set(tinygltf_path "${DRACO_TINYGLTF_PATH}")
if(NOT IS_DIRECTORY "${tinygltf_path}")
message(FATAL_ERROR "DRACO_TINYGLTF_PATH does not exist.")
endif()
else()
set(tinygltf_path "${draco_root}/third_party/tinygltf")
if(NOT IS_DIRECTORY "${tinygltf_path}")
draco_die_missing_submodule("${tinygltf_path}")
endif()
endif()
list(APPEND draco_include_paths "${tinygltf_path}")
endmacro()

View file

@ -0,0 +1,232 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_EMSCRIPTEN_CMAKE_
# Checks environment for Emscripten prerequisites.
macro(draco_check_emscripten_environment)
if(NOT PYTHONINTERP_FOUND)
message(
FATAL_ERROR
"Python required for Emscripten builds, but cmake cannot find it.")
endif()
if(NOT EXISTS "$ENV{EMSCRIPTEN}")
message(
FATAL_ERROR
"The EMSCRIPTEN environment variable must be set. See README.md.")
endif()
endmacro()
# Obtains the required Emscripten flags for Draco targets.
macro(draco_get_required_emscripten_flags)
set(em_FLAG_LIST_VAR_COMPILER)
set(em_FLAG_LIST_VAR_LINKER)
set(em_flags)
set(em_single_arg_opts FLAG_LIST_VAR_COMPILER FLAG_LIST_VAR_LINKER)
set(em_multi_arg_opts)
cmake_parse_arguments(em "${em_flags}" "${em_single_arg_opts}"
"${em_multi_arg_opts}" ${ARGN})
if(NOT em_FLAG_LIST_VAR_COMPILER)
message(
FATAL
"draco_get_required_emscripten_flags: FLAG_LIST_VAR_COMPILER required")
endif()
if(NOT em_FLAG_LIST_VAR_LINKER)
message(
FATAL
"draco_get_required_emscripten_flags: FLAG_LIST_VAR_LINKER required")
endif()
if(DRACO_JS_GLUE)
unset(required_flags)
# TODO(tomfinegan): Revisit splitting of compile/link flags for Emscripten,
# and drop -Wno-unused-command-line-argument. Emscripten complains about
# what are supposedly link-only flags sent with compile commands, but then
# proceeds to produce broken code if the warnings are heeded.
list(APPEND ${em_FLAG_LIST_VAR_COMPILER}
"-Wno-unused-command-line-argument")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-Wno-almost-asm")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--memory-init-file" "0")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-fno-omit-frame-pointer")
# According to Emscripten the following flags are linker only, but sending
# these flags (en masse) to only the linker results in a broken Emscripten
# build with an empty DracoDecoderModule.
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sALLOW_MEMORY_GROWTH=1")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sMODULARIZE=1")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sFILESYSTEM=0")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER}
"-sEXPORTED_FUNCTIONS=[\"_free\",\"_malloc\"]")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sPRECISE_F32=1")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sNODEJS_CATCH_EXIT=0")
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sNODEJS_CATCH_REJECTION=0")
if(DRACO_FAST)
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "--llvm-lto" "1")
endif()
# The WASM flag is reported as linker only.
if(DRACO_WASM)
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=1")
else()
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sWASM=0")
endif()
# The LEGACY_VM_SUPPORT flag is reported as linker only.
if(DRACO_IE_COMPATIBLE)
list(APPEND ${em_FLAG_LIST_VAR_COMPILER} "-sLEGACY_VM_SUPPORT=1")
endif()
endif()
endmacro()
# Macro for generating C++ glue code from IDL for Emscripten targets. Executes
# python to generate the C++ binding, and establishes dendency: $OUTPUT_PATH.cpp
# on $INPUT_IDL.
macro(draco_generate_emscripten_glue)
set(glue_flags)
set(glue_single_arg_opts INPUT_IDL OUTPUT_PATH)
set(glue_multi_arg_opts)
cmake_parse_arguments(glue "${glue_flags}" "${glue_single_arg_opts}"
"${glue_multi_arg_opts}" ${ARGN})
if(DRACO_VERBOSE GREATER 1)
message(
"--------- draco_generate_emscripten_glue -----------\n"
"glue_INPUT_IDL=${glue_INPUT_IDL}\n"
"glue_OUTPUT_PATH=${glue_OUTPUT_PATH}\n"
"----------------------------------------------------\n")
endif()
if(NOT glue_INPUT_IDL OR NOT glue_OUTPUT_PATH)
message(
FATAL_ERROR
"draco_generate_emscripten_glue: INPUT_IDL and OUTPUT_PATH required.")
endif()
# Generate the glue source.
execute_process(
COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
${glue_INPUT_IDL} ${glue_OUTPUT_PATH})
if(NOT EXISTS "${glue_OUTPUT_PATH}.cpp")
message(FATAL_ERROR "JS glue generation failed for ${glue_INPUT_IDL}.")
endif()
# Create a dependency so that it regenerated on edits.
add_custom_command(
OUTPUT "${glue_OUTPUT_PATH}.cpp"
COMMAND ${PYTHON_EXECUTABLE} $ENV{EMSCRIPTEN}/tools/webidl_binder.py
${glue_INPUT_IDL} ${glue_OUTPUT_PATH}
DEPENDS ${draco_js_dec_idl}
COMMENT "Generating ${glue_OUTPUT_PATH}.cpp."
WORKING_DIRECTORY ${draco_build}
VERBATIM)
endmacro()
# Wrapper for draco_add_executable() that handles the extra work necessary for
# emscripten targets when generating JS glue:
#
# ~~~
# - Set source level dependency on the C++ binding.
# - Pre/Post link emscripten magic.
#
# Required args:
# - GLUE_PATH: Base path for glue file. Used to generate .cpp and .js files.
# - PRE_LINK_JS_SOURCES: em_link_pre_js() source files.
# - POST_LINK_JS_SOURCES: em_link_post_js() source files.
# Optional args:
# - FEATURES:
# ~~~
macro(draco_add_emscripten_executable)
unset(emexe_NAME)
unset(emexe_FEATURES)
unset(emexe_SOURCES)
unset(emexe_DEFINES)
unset(emexe_INCLUDES)
unset(emexe_LINK_FLAGS)
set(optional_args)
set(single_value_args NAME GLUE_PATH)
set(multi_value_args
SOURCES
DEFINES
FEATURES
INCLUDES
LINK_FLAGS
PRE_LINK_JS_SOURCES
POST_LINK_JS_SOURCES)
cmake_parse_arguments(emexe "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT
(emexe_GLUE_PATH
AND emexe_POST_LINK_JS_SOURCES
AND emexe_PRE_LINK_JS_SOURCES))
message(FATAL
"draco_add_emscripten_executable: GLUE_PATH PRE_LINK_JS_SOURCES "
"POST_LINK_JS_SOURCES args required.")
endif()
if(DRACO_VERBOSE GREATER 1)
message(
"--------- draco_add_emscripten_executable ---------\n"
"emexe_NAME=${emexe_NAME}\n"
"emexe_SOURCES=${emexe_SOURCES}\n"
"emexe_DEFINES=${emexe_DEFINES}\n"
"emexe_INCLUDES=${emexe_INCLUDES}\n"
"emexe_LINK_FLAGS=${emexe_LINK_FLAGS}\n"
"emexe_GLUE_PATH=${emexe_GLUE_PATH}\n"
"emexe_FEATURES=${emexe_FEATURES}\n"
"emexe_PRE_LINK_JS_SOURCES=${emexe_PRE_LINK_JS_SOURCES}\n"
"emexe_POST_LINK_JS_SOURCES=${emexe_POST_LINK_JS_SOURCES}\n"
"----------------------------------------------------\n")
endif()
# The Emscripten linker needs the C++ flags in addition to whatever has been
# passed in with the target.
list(APPEND emexe_LINK_FLAGS ${DRACO_CXX_FLAGS})
if(DRACO_GLTF_BITSTREAM)
# Add "_gltf" suffix to target output name.
draco_add_executable(
NAME ${emexe_NAME}
OUTPUT_NAME ${emexe_NAME}_gltf
SOURCES ${emexe_SOURCES}
DEFINES ${emexe_DEFINES}
INCLUDES ${emexe_INCLUDES}
LINK_FLAGS ${emexe_LINK_FLAGS})
else()
draco_add_executable(
NAME ${emexe_NAME}
SOURCES ${emexe_SOURCES}
DEFINES ${emexe_DEFINES}
INCLUDES ${emexe_INCLUDES}
LINK_FLAGS ${emexe_LINK_FLAGS})
endif()
foreach(feature ${emexe_FEATURES})
draco_enable_feature(FEATURE ${feature} TARGETS ${emexe_NAME})
endforeach()
set_property(
SOURCE ${emexe_SOURCES}
APPEND
PROPERTY OBJECT_DEPENDS "${emexe_GLUE_PATH}.cpp")
em_link_pre_js(${emexe_NAME} ${emexe_PRE_LINK_JS_SOURCES})
em_link_post_js(${emexe_NAME} "${emexe_GLUE_PATH}.js"
${emexe_POST_LINK_JS_SOURCES})
endmacro()

View file

@ -0,0 +1,292 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_FLAGS_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_FLAGS_CMAKE_
set(DRACO_CMAKE_DRACO_FLAGS_CMAKE_ 1)
include(CheckCXXCompilerFlag)
include(CheckCXXSourceCompiles)
# Adds compiler flags specified by FLAGS to the sources specified by SOURCES:
#
# draco_set_compiler_flags_for_sources(SOURCES <sources> FLAGS <flags>)
macro(draco_set_compiler_flags_for_sources)
unset(compiler_SOURCES)
unset(compiler_FLAGS)
unset(optional_args)
unset(single_value_args)
set(multi_value_args SOURCES FLAGS)
cmake_parse_arguments(compiler "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT (compiler_SOURCES AND compiler_FLAGS))
draco_die("draco_set_compiler_flags_for_sources: SOURCES and "
"FLAGS required.")
endif()
set_source_files_properties(${compiler_SOURCES} PROPERTIES COMPILE_FLAGS
${compiler_FLAGS})
if(DRACO_VERBOSE GREATER 1)
foreach(source ${compiler_SOURCES})
foreach(flag ${compiler_FLAGS})
message("draco_set_compiler_flags_for_sources: source:${source} "
"flag:${flag}")
endforeach()
endforeach()
endif()
endmacro()
# Tests compiler flags stored in list(s) specified by FLAG_LIST_VAR_NAMES, adds
# flags to $DRACO_CXX_FLAGS when tests pass. Terminates configuration if
# FLAG_REQUIRED is specified and any flag check fails.
#
# ~~~
# draco_test_cxx_flag(<FLAG_LIST_VAR_NAMES <flag list variable(s)>>
# [FLAG_REQUIRED])
# ~~~
macro(draco_test_cxx_flag)
unset(cxx_test_FLAG_LIST_VAR_NAMES)
unset(cxx_test_FLAG_REQUIRED)
unset(single_value_args)
set(optional_args FLAG_REQUIRED)
set(multi_value_args FLAG_LIST_VAR_NAMES)
cmake_parse_arguments(cxx_test "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT cxx_test_FLAG_LIST_VAR_NAMES)
draco_die("draco_test_cxx_flag: FLAG_LIST_VAR_NAMES required")
endif()
unset(cxx_flags)
foreach(list_var ${cxx_test_FLAG_LIST_VAR_NAMES})
if(DRACO_VERBOSE)
message("draco_test_cxx_flag: adding ${list_var} to cxx_flags")
endif()
list(APPEND cxx_flags ${${list_var}})
endforeach()
if(DRACO_VERBOSE)
message("CXX test: all flags: ${cxx_flags}")
endif()
unset(all_cxx_flags)
list(APPEND all_cxx_flags ${DRACO_CXX_FLAGS} ${cxx_flags})
# Turn off output from check_cxx_source_compiles. Print status directly
# instead since the logging messages from check_cxx_source_compiles can be
# quite confusing.
set(CMAKE_REQUIRED_QUIET TRUE)
# Run the actual compile test.
unset(draco_all_cxx_flags_pass CACHE)
message("--- Running combined CXX flags test, flags: ${all_cxx_flags}")
# check_cxx_compiler_flag() requires that the flags are a string. When flags
# are passed as a list it will remove the list separators, and attempt to run
# a compile command using list entries concatenated together as a single
# argument. Avoid the problem by forcing the argument to be a string.
draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags_string)
check_cxx_compiler_flag("${all_cxx_flags_string}" draco_all_cxx_flags_pass)
if(cxx_test_FLAG_REQUIRED AND NOT draco_all_cxx_flags_pass)
draco_die("Flag test failed for required flag(s): "
"${all_cxx_flags} and FLAG_REQUIRED specified.")
endif()
if(draco_all_cxx_flags_pass)
# Test passed: update the global flag list used by the draco target creation
# wrappers.
set(DRACO_CXX_FLAGS ${cxx_flags})
list(REMOVE_DUPLICATES DRACO_CXX_FLAGS)
if(DRACO_VERBOSE)
message("DRACO_CXX_FLAGS=${DRACO_CXX_FLAGS}")
endif()
message("--- Passed combined CXX flags test")
else()
message("--- Failed combined CXX flags test, testing flags individually.")
if(cxx_flags)
message("--- Testing flags from $cxx_flags: " "${cxx_flags}")
foreach(cxx_flag ${cxx_flags})
# Since 3.17.0 check_cxx_compiler_flag() sets a normal variable at
# parent scope while check_cxx_source_compiles() continues to set an
# internal cache variable, so we unset both to avoid the failure /
# success state persisting between checks. This has been fixed in newer
# CMake releases, but 3.17 is pretty common: we will need this to avoid
# weird build breakages while the fix propagates.
unset(cxx_flag_test_passed)
unset(cxx_flag_test_passed CACHE)
message("--- Testing flag: ${cxx_flag}")
check_cxx_compiler_flag("${cxx_flag}" cxx_flag_test_passed)
if(cxx_flag_test_passed)
message("--- Passed test for ${cxx_flag}")
else()
list(REMOVE_ITEM cxx_flags ${cxx_flag})
message("--- Failed test for ${cxx_flag}, flag removed.")
endif()
endforeach()
set(DRACO_CXX_FLAGS ${cxx_flags})
endif()
endif()
if(DRACO_CXX_FLAGS)
list(REMOVE_DUPLICATES DRACO_CXX_FLAGS)
endif()
endmacro()
# Tests executable linker flags stored in list specified by FLAG_LIST_VAR_NAME,
# adds flags to $DRACO_EXE_LINKER_FLAGS when test passes. Terminates
# configuration when flag check fails. draco_set_cxx_flags() must be called
# before calling this macro because it assumes $DRACO_CXX_FLAGS contains only
# valid CXX flags.
#
# draco_test_exe_linker_flag(<FLAG_LIST_VAR_NAME <flag list variable)>)
macro(draco_test_exe_linker_flag)
unset(link_FLAG_LIST_VAR_NAME)
unset(optional_args)
unset(multi_value_args)
set(single_value_args FLAG_LIST_VAR_NAME)
cmake_parse_arguments(link "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT link_FLAG_LIST_VAR_NAME)
draco_die("draco_test_link_flag: FLAG_LIST_VAR_NAME required")
endif()
draco_set_and_stringify(DEST linker_flags SOURCE_VARS
${link_FLAG_LIST_VAR_NAME})
if(DRACO_VERBOSE)
message("EXE LINKER test: all flags: ${linker_flags}")
endif()
# Tests of $DRACO_CXX_FLAGS have already passed. Include them with the linker
# test.
draco_set_and_stringify(DEST CMAKE_REQUIRED_FLAGS SOURCE_VARS DRACO_CXX_FLAGS)
# Cache the global exe linker flags.
if(CMAKE_EXE_LINKER_FLAGS)
set(cached_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS})
draco_set_and_stringify(DEST CMAKE_EXE_LINKER_FLAGS SOURCE ${linker_flags})
endif()
draco_set_and_stringify(DEST CMAKE_EXE_LINKER_FLAGS SOURCE ${linker_flags}
${CMAKE_EXE_LINKER_FLAGS})
# Turn off output from check_cxx_source_compiles. Print status directly
# instead since the logging messages from check_cxx_source_compiles can be
# quite confusing.
set(CMAKE_REQUIRED_QUIET TRUE)
message("--- Running EXE LINKER test for flags: ${linker_flags}")
unset(linker_flag_test_passed CACHE)
set(draco_cxx_main "\nint main() { return 0; }")
check_cxx_source_compiles("${draco_cxx_main}" linker_flag_test_passed)
if(NOT linker_flag_test_passed)
draco_die("EXE LINKER test failed.")
endif()
message("--- Passed EXE LINKER flag test.")
# Restore cached global exe linker flags.
if(cached_CMAKE_EXE_LINKER_FLAGS)
set(CMAKE_EXE_LINKER_FLAGS ${cached_CMAKE_EXE_LINKER_FLAGS})
else()
unset(CMAKE_EXE_LINKER_FLAGS)
endif()
list(APPEND DRACO_EXE_LINKER_FLAGS ${${link_FLAG_LIST_VAR_NAME}})
list(REMOVE_DUPLICATES DRACO_EXE_LINKER_FLAGS)
endmacro()
# Runs the draco compiler tests. This macro builds up the list of list var(s)
# that is passed to draco_test_cxx_flag().
#
# Note: draco_set_build_definitions() must be called before this macro.
macro(draco_set_cxx_flags)
unset(cxx_flag_lists)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
list(APPEND cxx_flag_lists draco_base_cxx_flags)
endif()
# Append clang flags after the base set to allow -Wno* overrides to take
# effect. Some of the base flags may enable a large set of warnings, e.g.,
# -Wall.
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
list(APPEND cxx_flag_lists draco_clang_cxx_flags)
endif()
if(MSVC)
list(APPEND cxx_flag_lists draco_msvc_cxx_flags)
endif()
draco_set_and_stringify(DEST cxx_flags SOURCE_VARS ${cxx_flag_lists})
if(DRACO_VERBOSE)
message("draco_set_cxx_flags: internal CXX flags: ${cxx_flags}")
endif()
if(DRACO_CXX_FLAGS)
list(APPEND cxx_flag_lists DRACO_CXX_FLAGS)
if(DRACO_VERBOSE)
message("draco_set_cxx_flags: user CXX flags: ${DRACO_CXX_FLAGS}")
endif()
endif()
draco_set_and_stringify(DEST cxx_flags SOURCE_VARS ${cxx_flag_lists})
if(cxx_flags)
draco_test_cxx_flag(FLAG_LIST_VAR_NAMES ${cxx_flag_lists})
endif()
endmacro()
# Collects Draco built-in and user-specified linker flags and tests them. Halts
# configuration and reports the error when any flags cause the build to fail.
#
# Note: draco_test_exe_linker_flag() does the real work of setting the flags and
# running the test compile commands.
macro(draco_set_exe_linker_flags)
unset(linker_flag_lists)
if(DRACO_VERBOSE)
message("draco_set_exe_linker_flags: "
"draco_base_exe_linker_flags=${draco_base_exe_linker_flags}")
endif()
if(draco_base_exe_linker_flags)
list(APPEND linker_flag_lists draco_base_exe_linker_flags)
endif()
if(linker_flag_lists)
unset(test_linker_flags)
if(DRACO_VERBOSE)
message("draco_set_exe_linker_flags: "
"linker_flag_lists=${linker_flag_lists}")
endif()
draco_set_and_stringify(DEST test_linker_flags SOURCE_VARS
${linker_flag_lists})
draco_test_exe_linker_flag(FLAG_LIST_VAR_NAME test_linker_flags)
endif()
endmacro()

View file

@ -0,0 +1,124 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_HELPERS_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_HELPERS_CMAKE_
set(DRACO_CMAKE_DRACO_HELPERS_CMAKE_ 1)
# Kills build generation using message(FATAL_ERROR) and outputs all data passed
# to the console via use of $ARGN.
macro(draco_die)
message(FATAL_ERROR ${ARGN})
endmacro()
# Converts semi-colon delimited list variable(s) to string. Output is written to
# variable supplied via the DEST parameter. Input is from an expanded variable
# referenced by SOURCE and/or variable(s) referenced by SOURCE_VARS.
macro(draco_set_and_stringify)
set(optional_args)
set(single_value_args DEST SOURCE_VAR)
set(multi_value_args SOURCE SOURCE_VARS)
cmake_parse_arguments(sas "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT sas_DEST OR NOT (sas_SOURCE OR sas_SOURCE_VARS))
draco_die("draco_set_and_stringify: DEST and at least one of SOURCE "
"SOURCE_VARS required.")
endif()
unset(${sas_DEST})
if(sas_SOURCE)
# $sas_SOURCE is one or more expanded variables, just copy the values to
# $sas_DEST.
set(${sas_DEST} "${sas_SOURCE}")
endif()
if(sas_SOURCE_VARS)
# $sas_SOURCE_VARS is one or more variable names. Each iteration expands a
# variable and appends it to $sas_DEST.
foreach(source_var ${sas_SOURCE_VARS})
set(${sas_DEST} "${${sas_DEST}} ${${source_var}}")
endforeach()
# Because $sas_DEST can be empty when entering this scope leading whitespace
# can be introduced to $sas_DEST on the first iteration of the above loop.
# Remove it:
string(STRIP "${${sas_DEST}}" ${sas_DEST})
endif()
# Lists in CMake are simply semicolon delimited strings, so stringification is
# just a find and replace of the semicolon.
string(REPLACE ";" " " ${sas_DEST} "${${sas_DEST}}")
if(DRACO_VERBOSE GREATER 1)
message("draco_set_and_stringify: ${sas_DEST}=${${sas_DEST}}")
endif()
endmacro()
# Creates a dummy source file in $DRACO_GENERATED_SOURCES_DIRECTORY and adds it
# to the specified target. Optionally adds its path to a list variable.
#
# draco_create_dummy_source_file(<TARGET <target> BASENAME <basename of file>>
# [LISTVAR <list variable>])
macro(draco_create_dummy_source_file)
set(optional_args)
set(single_value_args TARGET BASENAME LISTVAR)
set(multi_value_args)
cmake_parse_arguments(cdsf "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT cdsf_TARGET OR NOT cdsf_BASENAME)
draco_die("draco_create_dummy_source_file: TARGET and BASENAME required.")
endif()
if(NOT DRACO_GENERATED_SOURCES_DIRECTORY)
set(DRACO_GENERATED_SOURCES_DIRECTORY "${draco_build}/gen_src")
endif()
set(dummy_source_dir "${DRACO_GENERATED_SOURCES_DIRECTORY}")
set(dummy_source_file
"${dummy_source_dir}/draco_${cdsf_TARGET}_${cdsf_BASENAME}.cc")
set(dummy_source_code
"// Generated file. DO NOT EDIT!\n"
"// C++ source file created for target ${cdsf_TARGET}.\n"
"void draco_${cdsf_TARGET}_${cdsf_BASENAME}_dummy_function(void)\;\n"
"void draco_${cdsf_TARGET}_${cdsf_BASENAME}_dummy_function(void) {}\n")
file(WRITE "${dummy_source_file}" ${dummy_source_code})
target_sources(${cdsf_TARGET} PRIVATE ${dummy_source_file})
if(cdsf_LISTVAR)
list(APPEND ${cdsf_LISTVAR} "${dummy_source_file}")
endif()
endmacro()
# Loads the version string from $draco_source/draco/version.h and sets
# $DRACO_VERSION.
macro(draco_load_version_info)
file(STRINGS "${draco_src_root}/core/draco_version.h" version_file_strings)
foreach(str ${version_file_strings})
if(str MATCHES "char kDracoVersion")
string(FIND "${str}" "\"" open_quote_pos)
string(FIND "${str}" ";" semicolon_pos)
math(EXPR open_quote_pos "${open_quote_pos} + 1")
math(EXPR close_quote_pos "${semicolon_pos} - 1")
math(EXPR version_string_length "${close_quote_pos} - ${open_quote_pos}")
string(SUBSTRING "${str}" ${open_quote_pos} ${version_string_length}
DRACO_VERSION)
break()
endif()
endforeach()
endmacro()

View file

@ -0,0 +1,123 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_INSTALL_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_INSTALL_CMAKE_
set(DRACO_CMAKE_DRACO_INSTALL_CMAKE_ 1)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
# Sets up the draco install targets. Must be called after the static library
# target is created.
macro(draco_setup_install_target)
if(DRACO_INSTALL)
set(bin_path "${CMAKE_INSTALL_BINDIR}")
set(data_path "${CMAKE_INSTALL_DATAROOTDIR}")
set(includes_path "${CMAKE_INSTALL_INCLUDEDIR}")
set(libs_path "${CMAKE_INSTALL_LIBDIR}")
foreach(file ${draco_sources})
if(file MATCHES "h$")
list(APPEND draco_api_includes ${file})
endif()
endforeach()
list(REMOVE_DUPLICATES draco_api_includes)
# Strip $draco_src_root from the file paths: we need to install relative to
# $include_directory.
list(TRANSFORM draco_api_includes REPLACE "${draco_src_root}/" "")
foreach(draco_api_include ${draco_api_includes})
get_filename_component(file_directory ${draco_api_include} DIRECTORY)
set(target_directory "${includes_path}/draco/${file_directory}")
install(FILES ${draco_src_root}/${draco_api_include}
DESTINATION "${target_directory}")
endforeach()
install(FILES "${draco_build}/draco/draco_features.h"
DESTINATION "${includes_path}/draco/")
install(TARGETS draco_decoder DESTINATION "${bin_path}")
install(TARGETS draco_encoder DESTINATION "${bin_path}")
if(DRACO_TRANSCODER_SUPPORTED)
install(TARGETS draco_transcoder DESTINATION "${bin_path}")
endif()
if(MSVC)
install(
TARGETS draco
EXPORT dracoExport
RUNTIME DESTINATION "${bin_path}"
ARCHIVE DESTINATION "${libs_path}"
LIBRARY DESTINATION "${libs_path}")
else()
install(
TARGETS draco_static
EXPORT dracoExport
DESTINATION "${libs_path}")
if(BUILD_SHARED_LIBS)
install(
TARGETS draco_shared
EXPORT dracoExport
RUNTIME DESTINATION "${bin_path}"
ARCHIVE DESTINATION "${libs_path}"
LIBRARY DESTINATION "${libs_path}")
endif()
endif()
if(DRACO_UNITY_PLUGIN)
install(TARGETS dracodec_unity DESTINATION "${libs_path}")
endif()
if(DRACO_MAYA_PLUGIN)
install(TARGETS draco_maya_wrapper DESTINATION "${libs_path}")
endif()
# pkg-config: draco.pc
configure_file("${draco_root}/cmake/draco.pc.template"
"${draco_build}/draco.pc" @ONLY NEWLINE_STYLE UNIX)
install(FILES "${draco_build}/draco.pc" DESTINATION "${libs_path}/pkgconfig")
# CMake config: draco-config.cmake
configure_package_config_file(
"${draco_root}/cmake/draco-config.cmake.template"
"${draco_build}/draco-config.cmake"
INSTALL_DESTINATION "${data_path}/cmake/draco")
write_basic_package_version_file(
"${draco_build}/draco-config-version.cmake"
VERSION ${DRACO_VERSION}
COMPATIBILITY AnyNewerVersion)
export(
EXPORT dracoExport
NAMESPACE draco::
FILE "${draco_build}/draco-targets.cmake")
install(
EXPORT dracoExport
NAMESPACE draco::
FILE draco-targets.cmake
DESTINATION "${data_path}/cmake/draco")
install(FILES "${draco_build}/draco-config.cmake"
"${draco_build}/draco-config-version.cmake"
DESTINATION "${data_path}/cmake/draco")
endif(DRACO_INSTALL)
endmacro()

View file

@ -0,0 +1,106 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_
set(DRACO_CMAKE_DRACO_INTRINSICS_CMAKE_ 1)
# Returns the compiler flag for the SIMD intrinsics suffix specified by the
# SUFFIX argument via the variable specified by the VARIABLE argument:
# draco_get_intrinsics_flag_for_suffix(SUFFIX <suffix> VARIABLE <var name>)
macro(draco_get_intrinsics_flag_for_suffix)
unset(intrinsics_SUFFIX)
unset(intrinsics_VARIABLE)
unset(optional_args)
unset(multi_value_args)
set(single_value_args SUFFIX VARIABLE)
cmake_parse_arguments(intrinsics "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT (intrinsics_SUFFIX AND intrinsics_VARIABLE))
message(FATAL_ERROR "draco_get_intrinsics_flag_for_suffix: SUFFIX and "
"VARIABLE required.")
endif()
if(intrinsics_SUFFIX MATCHES "neon")
if(NOT MSVC)
set(${intrinsics_VARIABLE} "${DRACO_NEON_INTRINSICS_FLAG}")
endif()
elseif(intrinsics_SUFFIX MATCHES "sse4")
if(NOT MSVC)
set(${intrinsics_VARIABLE} "-msse4.1")
endif()
else()
message(FATAL_ERROR "draco_get_intrinsics_flag_for_suffix: Unknown "
"instrinics suffix: ${intrinsics_SUFFIX}")
endif()
if(DRACO_VERBOSE GREATER 1)
message("draco_get_intrinsics_flag_for_suffix: "
"suffix:${intrinsics_SUFFIX} flag:${${intrinsics_VARIABLE}}")
endif()
endmacro()
# Processes source files specified by SOURCES and adds intrinsics flags as
# necessary: draco_process_intrinsics_sources(SOURCES <sources>)
#
# Detects requirement for intrinsics flags using source file name suffix.
# Currently supports only SSE4.1.
macro(draco_process_intrinsics_sources)
unset(arg_TARGET)
unset(arg_SOURCES)
unset(optional_args)
set(single_value_args TARGET)
set(multi_value_args SOURCES)
cmake_parse_arguments(arg "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT (arg_TARGET AND arg_SOURCES))
message(FATAL_ERROR "draco_process_intrinsics_sources: TARGET and "
"SOURCES required.")
endif()
if(DRACO_ENABLE_SSE4_1 AND draco_have_sse4)
unset(sse4_sources)
list(APPEND sse4_sources ${arg_SOURCES})
list(FILTER sse4_sources INCLUDE REGEX "${draco_sse4_source_file_suffix}$")
if(sse4_sources)
unset(sse4_flags)
draco_get_intrinsics_flag_for_suffix(
SUFFIX ${draco_sse4_source_file_suffix} VARIABLE sse4_flags)
if(sse4_flags)
draco_set_compiler_flags_for_sources(SOURCES ${sse4_sources} FLAGS
${sse4_flags})
endif()
endif()
endif()
if(DRACO_ENABLE_NEON AND draco_have_neon)
unset(neon_sources)
list(APPEND neon_sources ${arg_SOURCES})
list(FILTER neon_sources INCLUDE REGEX "${draco_neon_source_file_suffix}$")
if(neon_sources AND DRACO_NEON_INTRINSICS_FLAG)
unset(neon_flags)
draco_get_intrinsics_flag_for_suffix(
SUFFIX ${draco_neon_source_file_suffix} VARIABLE neon_flags)
if(neon_flags)
draco_set_compiler_flags_for_sources(SOURCES ${neon_sources} FLAGS
${neon_flags})
endif()
endif()
endif()
endmacro()

View file

@ -0,0 +1,358 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_OPTIONS_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_OPTIONS_CMAKE_
set(DRACO_CMAKE_DRACO_OPTIONS_CMAKE_)
set(draco_features_file_name "${draco_build}/draco/draco_features.h")
set(draco_features_list)
# Simple wrapper for CMake's builtin option command that tracks draco's build
# options in the list variable $draco_options.
macro(draco_option)
unset(option_NAME)
unset(option_HELPSTRING)
unset(option_VALUE)
unset(optional_args)
unset(multi_value_args)
set(single_value_args NAME HELPSTRING VALUE)
cmake_parse_arguments(option "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(NOT
(option_NAME
AND option_HELPSTRING
AND DEFINED option_VALUE))
message(FATAL_ERROR "draco_option: NAME HELPSTRING and VALUE required.")
endif()
option(${option_NAME} ${option_HELPSTRING} ${option_VALUE})
if(DRACO_VERBOSE GREATER 2)
message(
"--------- draco_option ---------\n"
"option_NAME=${option_NAME}\n"
"option_HELPSTRING=${option_HELPSTRING}\n"
"option_VALUE=${option_VALUE}\n"
"------------------------------------------\n")
endif()
list(APPEND draco_options ${option_NAME})
list(REMOVE_DUPLICATES draco_options)
endmacro()
# Dumps the $draco_options list via CMake message command.
macro(draco_dump_options)
foreach(option_name ${draco_options})
message("${option_name}: ${${option_name}}")
endforeach()
endmacro()
# Set default options.
macro(draco_set_default_options)
draco_option(
NAME DRACO_FAST
HELPSTRING "Try to build faster libs."
VALUE OFF)
draco_option(
NAME DRACO_JS_GLUE
HELPSTRING "Enable JS Glue and JS targets when using Emscripten."
VALUE ON)
draco_option(
NAME DRACO_IE_COMPATIBLE
HELPSTRING "Enable support for older IE builds when using Emscripten."
VALUE OFF)
draco_option(
NAME DRACO_MESH_COMPRESSION
HELPSTRING "Enable mesh compression."
VALUE ON)
draco_option(
NAME DRACO_POINT_CLOUD_COMPRESSION
HELPSTRING "Enable point cloud compression."
VALUE ON)
draco_option(
NAME DRACO_PREDICTIVE_EDGEBREAKER
HELPSTRING "Enable predictive edgebreaker."
VALUE ON)
draco_option(
NAME DRACO_STANDARD_EDGEBREAKER
HELPSTRING "Enable stand edgebreaker."
VALUE ON)
draco_option(
NAME DRACO_BACKWARDS_COMPATIBILITY
HELPSTRING "Enable backwards compatibility."
VALUE ON)
draco_option(
NAME DRACO_DECODER_ATTRIBUTE_DEDUPLICATION
HELPSTRING "Enable attribute deduping."
VALUE OFF)
draco_option(
NAME DRACO_TESTS
HELPSTRING "Enables tests."
VALUE OFF)
draco_option(
NAME DRACO_WASM
HELPSTRING "Enables WASM support."
VALUE OFF)
draco_option(
NAME DRACO_UNITY_PLUGIN
HELPSTRING "Build plugin library for Unity."
VALUE OFF)
draco_option(
NAME DRACO_ANIMATION_ENCODING
HELPSTRING "Enable animation."
VALUE OFF)
draco_option(
NAME DRACO_GLTF_BITSTREAM
HELPSTRING "Draco GLTF extension bitstream specified features only."
VALUE OFF)
draco_option(
NAME DRACO_MAYA_PLUGIN
HELPSTRING "Build plugin library for Maya."
VALUE OFF)
draco_option(
NAME DRACO_TRANSCODER_SUPPORTED
HELPSTRING "Enable the Draco transcoder."
VALUE OFF)
draco_option(
NAME DRACO_DEBUG_COMPILER_WARNINGS
HELPSTRING "Turn on more warnings."
VALUE OFF)
draco_option(
NAME DRACO_INSTALL
HELPSTRING "Enable installation."
VALUE ON)
draco_check_deprecated_options()
endmacro()
# Warns when a deprecated option is used and sets the option that replaced it.
macro(draco_handle_deprecated_option)
unset(option_OLDNAME)
unset(option_NEWNAME)
unset(optional_args)
unset(multi_value_args)
set(single_value_args OLDNAME NEWNAME)
cmake_parse_arguments(option "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if("${${option_OLDNAME}}")
message(WARNING "${option_OLDNAME} is deprecated. Use ${option_NEWNAME}.")
set(${option_NEWNAME} ${${option_OLDNAME}})
endif()
endmacro()
# Checks for use of deprecated options.
macro(draco_check_deprecated_options)
draco_handle_deprecated_option(OLDNAME ENABLE_EXTRA_SPEED NEWNAME DRACO_FAST)
draco_handle_deprecated_option(OLDNAME ENABLE_JS_GLUE NEWNAME DRACO_JS_GLUE)
draco_handle_deprecated_option(OLDNAME ENABLE_MESH_COMPRESSION NEWNAME
DRACO_MESH_COMPRESSION)
draco_handle_deprecated_option(OLDNAME ENABLE_POINT_CLOUD_COMPRESSION NEWNAME
DRACO_POINT_CLOUD_COMPRESSION)
draco_handle_deprecated_option(OLDNAME ENABLE_PREDICTIVE_EDGEBREAKER NEWNAME
DRACO_PREDICTIVE_EDGEBREAKER)
draco_handle_deprecated_option(OLDNAME ENABLE_STANDARD_EDGEBREAKER NEWNAME
DRACO_STANDARD_EDGEBREAKER)
draco_handle_deprecated_option(OLDNAME ENABLE_BACKWARDS_COMPATIBILITY NEWNAME
DRACO_BACKWARDS_COMPATIBILITY)
draco_handle_deprecated_option(OLDNAME ENABLE_DECODER_ATTRIBUTE_DEDUPLICATION
NEWNAME DRACO_DECODER_ATTRIBUTE_DEDUPLICATION)
draco_handle_deprecated_option(OLDNAME ENABLE_TESTS NEWNAME DRACO_TESTS)
draco_handle_deprecated_option(OLDNAME ENABLE_WASM NEWNAME DRACO_WASM)
draco_handle_deprecated_option(OLDNAME BUILD_UNITY_PLUGIN NEWNAME
DRACO_UNITY_PLUGIN)
draco_handle_deprecated_option(OLDNAME BUILD_ANIMATION_ENCODING NEWNAME
DRACO_ANIMATION_ENCODING)
draco_handle_deprecated_option(OLDNAME BUILD_FOR_GLTF NEWNAME DRACO_GLTF)
draco_handle_deprecated_option(OLDNAME BUILD_MAYA_PLUGIN NEWNAME
DRACO_MAYA_PLUGIN)
draco_handle_deprecated_option(OLDNAME BUILD_USD_PLUGIN NEWNAME
BUILD_SHARED_LIBS)
draco_handle_deprecated_option(OLDNAME DRACO_GLTF NEWNAME
DRACO_GLTF_BITSTREAM)
endmacro()
# Macro for setting Draco features based on user configuration. Features enabled
# by this macro are Draco global.
macro(draco_set_optional_features)
if(DRACO_GLTF_BITSTREAM)
# Enable only the features included in the Draco GLTF bitstream spec.
draco_enable_feature(FEATURE "DRACO_MESH_COMPRESSION_SUPPORTED")
draco_enable_feature(FEATURE "DRACO_NORMAL_ENCODING_SUPPORTED")
draco_enable_feature(FEATURE "DRACO_STANDARD_EDGEBREAKER_SUPPORTED")
else()
if(DRACO_POINT_CLOUD_COMPRESSION)
draco_enable_feature(FEATURE "DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED")
endif()
if(DRACO_MESH_COMPRESSION)
draco_enable_feature(FEATURE "DRACO_MESH_COMPRESSION_SUPPORTED")
draco_enable_feature(FEATURE "DRACO_NORMAL_ENCODING_SUPPORTED")
if(DRACO_STANDARD_EDGEBREAKER)
draco_enable_feature(FEATURE "DRACO_STANDARD_EDGEBREAKER_SUPPORTED")
endif()
if(DRACO_PREDICTIVE_EDGEBREAKER)
draco_enable_feature(FEATURE "DRACO_PREDICTIVE_EDGEBREAKER_SUPPORTED")
endif()
endif()
if(DRACO_BACKWARDS_COMPATIBILITY)
draco_enable_feature(FEATURE "DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED")
endif()
if(NOT EMSCRIPTEN)
# For now, enable deduplication for both encoder and decoder.
# TODO(ostava): Support for disabling attribute deduplication for the C++
# decoder is planned in future releases.
draco_enable_feature(FEATURE
DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED)
draco_enable_feature(FEATURE
DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED)
endif()
endif()
if(DRACO_UNITY_PLUGIN)
draco_enable_feature(FEATURE "DRACO_UNITY_PLUGIN")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if(DRACO_MAYA_PLUGIN)
draco_enable_feature(FEATURE "DRACO_MAYA_PLUGIN")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if(DRACO_TRANSCODER_SUPPORTED)
draco_enable_feature(FEATURE "DRACO_TRANSCODER_SUPPORTED")
endif()
endmacro()
# Macro that handles tracking of Draco preprocessor symbols for the purpose of
# producing draco_features.h.
#
# ~~~
# draco_enable_feature(FEATURE <feature_name> [TARGETS <target_name>])
# ~~~
#
# FEATURE is required. It should be a Draco preprocessor symbol. TARGETS is
# optional. It can be one or more draco targets.
#
# When the TARGETS argument is not present the preproc symbol is added to
# draco_features.h. When it is draco_features.h is unchanged, and
# target_compile_options() is called for each target specified.
macro(draco_enable_feature)
set(def_flags)
set(def_single_arg_opts FEATURE)
set(def_multi_arg_opts TARGETS)
cmake_parse_arguments(DEF "${def_flags}" "${def_single_arg_opts}"
"${def_multi_arg_opts}" ${ARGN})
if("${DEF_FEATURE}" STREQUAL "")
message(FATAL_ERROR "Empty FEATURE passed to draco_enable_feature().")
endif()
# Do nothing/return early if $DEF_FEATURE is already in the list.
list(FIND draco_features_list ${DEF_FEATURE} df_index)
if(NOT df_index EQUAL -1)
return()
endif()
list(LENGTH DEF_TARGETS df_targets_list_length)
if(${df_targets_list_length} EQUAL 0)
list(APPEND draco_features_list ${DEF_FEATURE})
else()
foreach(target ${DEF_TARGETS})
target_compile_definitions(${target} PRIVATE ${DEF_FEATURE})
endforeach()
endif()
endmacro()
# Function for generating draco_features.h.
function(draco_generate_features_h)
file(WRITE "${draco_features_file_name}.new"
"// GENERATED FILE -- DO NOT EDIT\n\n" "#ifndef DRACO_FEATURES_H_\n"
"#define DRACO_FEATURES_H_\n\n")
foreach(feature ${draco_features_list})
file(APPEND "${draco_features_file_name}.new" "#define ${feature}\n")
endforeach()
if(MSVC)
if(NOT DRACO_DEBUG_COMPILER_WARNINGS)
file(APPEND "${draco_features_file_name}.new"
"// Enable DRACO_DEBUG_COMPILER_WARNINGS at CMake generation \n"
"// time to remove these pragmas.\n")
# warning C4018: '<operator>': signed/unsigned mismatch.
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4018)\n")
# warning C4146: unary minus operator applied to unsigned type, result
# still unsigned
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4146)\n")
# warning C4244: 'return': conversion from '<type>' to '<type>', possible
# loss of data.
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4244)\n")
# warning C4267: 'initializing' conversion from '<type>' to '<type>',
# possible loss of data.
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4267)\n")
# warning C4305: 'context' : truncation from 'type1' to 'type2'.
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4305)\n")
# warning C4661: 'identifier' : no suitable definition provided for
# explicit template instantiation request.
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4661)\n")
# warning C4800: Implicit conversion from 'type' to bool. Possible
# information loss.
# Also, in older MSVC releases:
# warning C4800: 'type' : forcing value to bool 'true' or 'false'
# (performance warning).
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4800)\n")
# warning C4804: '<operator>': unsafe use of type '<type>' in operation.
file(APPEND "${draco_features_file_name}.new"
"#pragma warning(disable:4804)\n")
endif()
endif()
file(APPEND "${draco_features_file_name}.new"
"\n#endif // DRACO_FEATURES_H_\n")
# Will replace ${draco_features_file_name} only if the file content has
# changed. This prevents forced Draco rebuilds after CMake runs.
configure_file("${draco_features_file_name}.new"
"${draco_features_file_name}")
file(REMOVE "${draco_features_file_name}.new")
endfunction()
# Sets default options for the build and processes user controlled options to
# compute enabled features.
macro(draco_setup_options)
draco_set_default_options()
draco_set_optional_features()
endmacro()

View file

@ -0,0 +1,48 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_SANITIZER_CMAKE_
set(DRACO_CMAKE_DRACO_SANITIZER_CMAKE_ 1)
# Handles the details of enabling sanitizers.
macro(draco_configure_sanitizer)
if(DRACO_SANITIZE
AND NOT EMSCRIPTEN
AND NOT MSVC)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(DRACO_SANITIZE MATCHES "cfi")
list(APPEND SAN_CXX_FLAGS "-flto" "-fno-sanitize-trap=cfi")
list(APPEND SAN_LINKER_FLAGS "-flto" "-fno-sanitize-trap=cfi"
"-fuse-ld=gold")
endif()
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4 AND DRACO_SANITIZE MATCHES
"integer|undefined")
list(APPEND SAN_LINKER_FLAGS "--rtlib=compiler-rt" "-lgcc_s")
endif()
endif()
list(APPEND SAN_CXX_FLAGS "-fsanitize=${DRACO_SANITIZE}")
list(APPEND SAN_LINKER_FLAGS "-fsanitize=${DRACO_SANITIZE}")
# Make sanitizer callstacks accurate.
list(APPEND SAN_CXX_FLAGS "-fno-omit-frame-pointer")
list(APPEND SAN_CXX_FLAGS "-fno-optimize-sibling-calls")
draco_test_cxx_flag(FLAG_LIST_VAR_NAMES SAN_CXX_FLAGS FLAG_REQUIRED)
draco_test_exe_linker_flag(FLAG_LIST_VAR_NAME SAN_LINKER_FLAGS)
endif()
endmacro()

View file

@ -0,0 +1,400 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_TARGETS_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_TARGETS_CMAKE_
set(DRACO_CMAKE_DRACO_TARGETS_CMAKE_ 1)
# Resets list variables used to track draco targets.
macro(draco_reset_target_lists)
unset(draco_targets)
unset(draco_exe_targets)
unset(draco_lib_targets)
unset(draco_objlib_targets)
unset(draco_module_targets)
unset(draco_sources)
unset(draco_test_targets)
endmacro()
# Creates an executable target. The target name is passed as a parameter to the
# NAME argument, and the sources passed as a parameter to the SOURCES argument:
# draco_add_executable(NAME <name> SOURCES <sources> [optional args])
#
# Optional args:
# cmake-format: off
# - OUTPUT_NAME: Override output file basename. Target basename defaults to
# NAME.
# - TEST: Flag. Presence means treat executable as a test.
# - DEFINES: List of preprocessor macro definitions.
# - INCLUDES: list of include directories for the target.
# - COMPILE_FLAGS: list of compiler flags for the target.
# - LINK_FLAGS: List of linker flags for the target.
# - OBJLIB_DEPS: List of CMake object library target dependencies.
# - LIB_DEPS: List of CMake library dependencies.
# cmake-format: on
#
# Sources passed to this macro are added to $draco_test_sources when TEST is
# specified. Otherwise sources are added to $draco_sources.
#
# Targets passed to this macro are always added to the $draco_targets list. When
# TEST is specified targets are also added to the $draco_test_targets list.
# Otherwise targets are added to $draco_exe_targets.
macro(draco_add_executable)
unset(exe_TEST)
unset(exe_TEST_DEFINES_MAIN)
unset(exe_NAME)
unset(exe_OUTPUT_NAME)
unset(exe_SOURCES)
unset(exe_DEFINES)
unset(exe_INCLUDES)
unset(exe_COMPILE_FLAGS)
unset(exe_LINK_FLAGS)
unset(exe_OBJLIB_DEPS)
unset(exe_LIB_DEPS)
set(optional_args TEST)
set(single_value_args NAME OUTPUT_NAME)
set(multi_value_args
SOURCES
DEFINES
INCLUDES
COMPILE_FLAGS
LINK_FLAGS
OBJLIB_DEPS
LIB_DEPS)
cmake_parse_arguments(exe "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(DRACO_VERBOSE GREATER 1)
message(
"--------- draco_add_executable ---------\n"
"exe_TEST=${exe_TEST}\n"
"exe_TEST_DEFINES_MAIN=${exe_TEST_DEFINES_MAIN}\n"
"exe_NAME=${exe_NAME}\n"
"exe_OUTPUT_NAME=${exe_OUTPUT_NAME}\n"
"exe_SOURCES=${exe_SOURCES}\n"
"exe_DEFINES=${exe_DEFINES}\n"
"exe_INCLUDES=${exe_INCLUDES}\n"
"exe_COMPILE_FLAGS=${exe_COMPILE_FLAGS}\n"
"exe_LINK_FLAGS=${exe_LINK_FLAGS}\n"
"exe_OBJLIB_DEPS=${exe_OBJLIB_DEPS}\n"
"exe_LIB_DEPS=${exe_LIB_DEPS}\n"
"------------------------------------------\n")
endif()
if(NOT (exe_NAME AND exe_SOURCES))
message(FATAL_ERROR "draco_add_executable: NAME and SOURCES required.")
endif()
list(APPEND draco_targets ${exe_NAME})
if(exe_TEST)
list(APPEND draco_test_targets ${exe_NAME})
list(APPEND draco_test_sources ${exe_SOURCES})
else()
list(APPEND draco_exe_targets ${exe_NAME})
list(APPEND draco_sources ${exe_SOURCES})
endif()
add_executable(${exe_NAME} ${exe_SOURCES})
target_compile_features(${exe_NAME} PUBLIC cxx_std_11)
if(NOT EMSCRIPTEN)
set_target_properties(${exe_NAME} PROPERTIES VERSION ${DRACO_VERSION})
endif()
if(exe_OUTPUT_NAME)
set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME})
endif()
draco_process_intrinsics_sources(TARGET ${exe_NAME} SOURCES ${exe_SOURCES})
if(exe_DEFINES)
target_compile_definitions(${exe_NAME} PRIVATE ${exe_DEFINES})
endif()
if(exe_INCLUDES)
target_include_directories(${exe_NAME} PRIVATE ${exe_INCLUDES})
endif()
if(exe_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
target_compile_options(${exe_NAME} PRIVATE ${exe_COMPILE_FLAGS}
${DRACO_CXX_FLAGS})
endif()
if(exe_LINK_FLAGS OR DRACO_EXE_LINKER_FLAGS)
if(${CMAKE_VERSION} VERSION_LESS "3.13")
list(APPEND exe_LINK_FLAGS "${DRACO_EXE_LINKER_FLAGS}")
# LINK_FLAGS is managed as a string.
draco_set_and_stringify(SOURCE "${exe_LINK_FLAGS}" DEST exe_LINK_FLAGS)
set_target_properties(${exe_NAME} PROPERTIES LINK_FLAGS
"${exe_LINK_FLAGS}")
else()
target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS}
${DRACO_EXE_LINKER_FLAGS})
endif()
endif()
if(exe_OBJLIB_DEPS)
foreach(objlib_dep ${exe_OBJLIB_DEPS})
target_sources(${exe_NAME} PRIVATE $<TARGET_OBJECTS:${objlib_dep}>)
endforeach()
endif()
if(CMAKE_THREAD_LIBS_INIT)
list(APPEND exe_LIB_DEPS ${CMAKE_THREAD_LIBS_INIT})
endif()
if(BUILD_SHARED_LIBS AND (MSVC OR WIN32))
target_compile_definitions(${exe_NAME} PRIVATE "DRACO_BUILDING_DLL=0")
endif()
if(exe_LIB_DEPS)
if(CMAKE_CXX_COMPILER_ID MATCHES "^Clang|^GNU")
# Third party dependencies can introduce dependencies on system and test
# libraries. Since the target created here is an executable, and CMake
# does not provide a method of controlling order of link dependencies,
# wrap all of the dependencies of this target in start/end group flags to
# ensure that dependencies of third party targets can be resolved when
# those dependencies happen to be resolved by dependencies of the current
# target.
# TODO(tomfinegan): For portability use LINK_GROUP with RESCAN instead of
# directly (ab)using compiler/linker specific flags once CMake v3.24 is in
# wider use. See:
# https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:LINK_GROUP
list(INSERT exe_LIB_DEPS 0 -Wl,--start-group)
list(APPEND exe_LIB_DEPS -Wl,--end-group)
endif()
target_link_libraries(${exe_NAME} PRIVATE ${exe_LIB_DEPS})
endif()
endmacro()
# Creates a library target of the specified type. The target name is passed as a
# parameter to the NAME argument, the type as a parameter to the TYPE argument,
# and the sources passed as a parameter to the SOURCES argument:
# draco_add_library(NAME <name> TYPE <type> SOURCES <sources> [optional args])
#
# Optional args:
# cmake-format: off
# - OUTPUT_NAME: Override output file basename. Target basename defaults to
# NAME. OUTPUT_NAME is ignored when BUILD_SHARED_LIBS is enabled and CMake
# is generating a build for which MSVC is true. This is to avoid output
# basename collisions with DLL import libraries.
# - TEST: Flag. Presence means treat library as a test.
# - DEFINES: List of preprocessor macro definitions.
# - INCLUDES: list of include directories for the target.
# - COMPILE_FLAGS: list of compiler flags for the target.
# - LINK_FLAGS: List of linker flags for the target.
# - OBJLIB_DEPS: List of CMake object library target dependencies.
# - LIB_DEPS: List of CMake library dependencies.
# - PUBLIC_INCLUDES: List of include paths to export to dependents.
# cmake-format: on
#
# Sources passed to the macro are added to the lists tracking draco sources:
# cmake-format: off
# - When TEST is specified sources are added to $draco_test_sources.
# - Otherwise sources are added to $draco_sources.
# cmake-format: on
#
# Targets passed to this macro are added to the lists tracking draco targets:
# cmake-format: off
# - Targets are always added to $draco_targets.
# - When the TEST flag is specified, targets are added to
# $draco_test_targets.
# - When TEST is not specified:
# - Libraries of type SHARED are added to $draco_dylib_targets.
# - Libraries of type OBJECT are added to $draco_objlib_targets.
# - Libraries of type STATIC are added to $draco_lib_targets.
# cmake-format: on
macro(draco_add_library)
unset(lib_TEST)
unset(lib_NAME)
unset(lib_OUTPUT_NAME)
unset(lib_TYPE)
unset(lib_SOURCES)
unset(lib_DEFINES)
unset(lib_INCLUDES)
unset(lib_COMPILE_FLAGS)
unset(lib_LINK_FLAGS)
unset(lib_OBJLIB_DEPS)
unset(lib_LIB_DEPS)
unset(lib_PUBLIC_INCLUDES)
unset(lib_TARGET_PROPERTIES)
set(optional_args TEST)
set(single_value_args NAME OUTPUT_NAME TYPE)
set(multi_value_args
SOURCES
DEFINES
INCLUDES
COMPILE_FLAGS
LINK_FLAGS
OBJLIB_DEPS
LIB_DEPS
PUBLIC_INCLUDES
TARGET_PROPERTIES)
cmake_parse_arguments(lib "${optional_args}" "${single_value_args}"
"${multi_value_args}" ${ARGN})
if(DRACO_VERBOSE GREATER 1)
message(
"--------- draco_add_library ---------\n"
"lib_TEST=${lib_TEST}\n"
"lib_NAME=${lib_NAME}\n"
"lib_OUTPUT_NAME=${lib_OUTPUT_NAME}\n"
"lib_TYPE=${lib_TYPE}\n"
"lib_SOURCES=${lib_SOURCES}\n"
"lib_DEFINES=${lib_DEFINES}\n"
"lib_INCLUDES=${lib_INCLUDES}\n"
"lib_COMPILE_FLAGS=${lib_COMPILE_FLAGS}\n"
"lib_LINK_FLAGS=${lib_LINK_FLAGS}\n"
"lib_OBJLIB_DEPS=${lib_OBJLIB_DEPS}\n"
"lib_LIB_DEPS=${lib_LIB_DEPS}\n"
"lib_PUBLIC_INCLUDES=${lib_PUBLIC_INCLUDES}\n"
"---------------------------------------\n")
endif()
if(NOT (lib_NAME AND lib_TYPE))
message(FATAL_ERROR "draco_add_library: NAME and TYPE required.")
endif()
list(APPEND draco_targets ${lib_NAME})
if(lib_TEST)
list(APPEND draco_test_targets ${lib_NAME})
list(APPEND draco_test_sources ${lib_SOURCES})
else()
list(APPEND draco_sources ${lib_SOURCES})
if(lib_TYPE STREQUAL MODULE)
list(APPEND draco_module_targets ${lib_NAME})
elseif(lib_TYPE STREQUAL OBJECT)
list(APPEND draco_objlib_targets ${lib_NAME})
elseif(lib_TYPE STREQUAL SHARED)
list(APPEND draco_dylib_targets ${lib_NAME})
elseif(lib_TYPE STREQUAL STATIC)
list(APPEND draco_lib_targets ${lib_NAME})
else()
message(WARNING "draco_add_library: Unhandled type: ${lib_TYPE}")
endif()
endif()
add_library(${lib_NAME} ${lib_TYPE} ${lib_SOURCES})
target_compile_features(${lib_NAME} PUBLIC cxx_std_11)
target_include_directories(${lib_NAME} PUBLIC $<INSTALL_INTERFACE:include>)
if(BUILD_SHARED_LIBS)
# Enable PIC for all targets in shared configurations.
set_target_properties(${lib_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
if(lib_SOURCES)
draco_process_intrinsics_sources(TARGET ${lib_NAME} SOURCES ${lib_SOURCES})
endif()
if(lib_OUTPUT_NAME)
if(NOT (BUILD_SHARED_LIBS AND MSVC))
set_target_properties(${lib_NAME} PROPERTIES OUTPUT_NAME
${lib_OUTPUT_NAME})
endif()
endif()
if(lib_DEFINES)
target_compile_definitions(${lib_NAME} PRIVATE ${lib_DEFINES})
endif()
if(lib_INCLUDES)
target_include_directories(${lib_NAME} PRIVATE ${lib_INCLUDES})
endif()
if(lib_PUBLIC_INCLUDES)
target_include_directories(${lib_NAME} PUBLIC ${lib_PUBLIC_INCLUDES})
endif()
if(lib_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
target_compile_options(${lib_NAME} PRIVATE ${lib_COMPILE_FLAGS}
${DRACO_CXX_FLAGS})
endif()
if(lib_LINK_FLAGS)
set_target_properties(${lib_NAME} PROPERTIES LINK_FLAGS ${lib_LINK_FLAGS})
endif()
if(lib_OBJLIB_DEPS)
foreach(objlib_dep ${lib_OBJLIB_DEPS})
target_sources(${lib_NAME} PRIVATE $<TARGET_OBJECTS:${objlib_dep}>)
endforeach()
endif()
if(lib_LIB_DEPS)
if(lib_TYPE STREQUAL STATIC)
set(link_type PUBLIC)
else()
set(link_type PRIVATE)
if(lib_TYPE STREQUAL SHARED AND CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
# The draco shared object uses the static draco as input to turn it into
# a shared object. Include everything from the static library in the
# shared object.
if(APPLE)
list(INSERT lib_LIB_DEPS 0 -Wl,-force_load)
else()
list(INSERT lib_LIB_DEPS 0 -Wl,--whole-archive)
list(APPEND lib_LIB_DEPS -Wl,--no-whole-archive)
endif()
endif()
endif()
target_link_libraries(${lib_NAME} ${link_type} ${lib_LIB_DEPS})
endif()
if(NOT MSVC AND lib_NAME MATCHES "^lib")
# Non-MSVC generators prepend lib to static lib target file names. Libdraco
# already includes lib in its name. Avoid naming output files liblib*.
set_target_properties(${lib_NAME} PROPERTIES PREFIX "")
endif()
if(NOT EMSCRIPTEN)
# VERSION and SOVERSION as necessary
if((lib_TYPE STREQUAL BUNDLE OR lib_TYPE STREQUAL SHARED) AND NOT MSVC)
set_target_properties(
${lib_NAME} PROPERTIES VERSION ${DRACO_SOVERSION}
SOVERSION ${DRACO_SOVERSION_MAJOR})
endif()
endif()
if(BUILD_SHARED_LIBS AND (MSVC OR WIN32))
if(lib_TYPE STREQUAL SHARED)
target_compile_definitions(${lib_NAME} PRIVATE "DRACO_BUILDING_DLL=1")
else()
target_compile_definitions(${lib_NAME} PRIVATE "DRACO_BUILDING_DLL=0")
endif()
endif()
# Determine if $lib_NAME is a header only target.
unset(sources_list)
if(lib_SOURCES)
set(sources_list ${lib_SOURCES})
list(FILTER sources_list INCLUDE REGEX cc$)
endif()
if(NOT sources_list)
if(NOT XCODE)
# This is a header only target. Tell CMake the link language.
set_target_properties(${lib_NAME} PROPERTIES LINKER_LANGUAGE CXX)
else()
# The Xcode generator ignores LINKER_LANGUAGE. Add a dummy cc file.
draco_create_dummy_source_file(TARGET ${lib_NAME} BASENAME ${lib_NAME})
endif()
endif()
endmacro()

View file

@ -0,0 +1,28 @@
// Copyright 2021 The Draco Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DRACO_TESTING_DRACO_TEST_CONFIG_H_
#define DRACO_TESTING_DRACO_TEST_CONFIG_H_
// If this file is named draco_test_config.h.cmake:
// This file is used as input at cmake generation time.
// If this file is named draco_test_config.h:
// GENERATED FILE, DO NOT EDIT. SEE ABOVE.
#define DRACO_TEST_DATA_DIR "${DRACO_TEST_DATA_DIR}"
#define DRACO_TEST_TEMP_DIR "${DRACO_TEST_TEMP_DIR}"
#define DRACO_TEST_ROOT_DIR "${DRACO_TEST_ROOT_DIR}"
#endif // DRACO_TESTING_DRACO_TEST_CONFIG_H_

View file

@ -0,0 +1,173 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_TESTS_CMAKE)
return()
endif()
set(DRACO_CMAKE_DRACO_TESTS_CMAKE 1)
# The factory tests are in a separate target to avoid breaking tests that rely
# on file I/O via the factories. The fake reader and writer implementations
# interfere with normal file I/O function.
set(draco_factory_test_sources
"${draco_src_root}/io/file_reader_factory_test.cc"
"${draco_src_root}/io/file_writer_factory_test.cc")
list(
APPEND draco_test_common_sources
"${draco_src_root}/core/draco_test_base.h"
"${draco_src_root}/core/draco_test_utils.cc"
"${draco_src_root}/core/draco_test_utils.h"
"${draco_src_root}/core/status.cc")
list(
APPEND
draco_test_sources
"${draco_src_root}/animation/keyframe_animation_encoding_test.cc"
"${draco_src_root}/animation/keyframe_animation_test.cc"
"${draco_src_root}/attributes/point_attribute_test.cc"
"${draco_src_root}/compression/attributes/point_d_vector_test.cc"
"${draco_src_root}/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_transform_test.cc"
"${draco_src_root}/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_transform_test.cc"
"${draco_src_root}/compression/attributes/sequential_integer_attribute_encoding_test.cc"
"${draco_src_root}/compression/bit_coders/rans_coding_test.cc"
"${draco_src_root}/compression/decode_test.cc"
"${draco_src_root}/compression/encode_test.cc"
"${draco_src_root}/compression/entropy/shannon_entropy_test.cc"
"${draco_src_root}/compression/entropy/symbol_coding_test.cc"
"${draco_src_root}/compression/mesh/mesh_edgebreaker_encoding_test.cc"
"${draco_src_root}/compression/mesh/mesh_encoder_test.cc"
"${draco_src_root}/compression/point_cloud/point_cloud_kd_tree_encoding_test.cc"
"${draco_src_root}/compression/point_cloud/point_cloud_sequential_encoding_test.cc"
"${draco_src_root}/core/buffer_bit_coding_test.cc"
"${draco_src_root}/core/math_utils_test.cc"
"${draco_src_root}/core/quantization_utils_test.cc"
"${draco_src_root}/core/status_test.cc"
"${draco_src_root}/core/vector_d_test.cc"
"${draco_src_root}/io/file_reader_test_common.h"
"${draco_src_root}/io/file_utils_test.cc"
"${draco_src_root}/io/file_writer_utils_test.cc"
"${draco_src_root}/io/stdio_file_reader_test.cc"
"${draco_src_root}/io/stdio_file_writer_test.cc"
"${draco_src_root}/io/obj_decoder_test.cc"
"${draco_src_root}/io/obj_encoder_test.cc"
"${draco_src_root}/io/ply_decoder_test.cc"
"${draco_src_root}/io/ply_reader_test.cc"
"${draco_src_root}/io/stl_decoder_test.cc"
"${draco_src_root}/io/stl_encoder_test.cc"
"${draco_src_root}/io/point_cloud_io_test.cc"
"${draco_src_root}/mesh/corner_table_test.cc"
"${draco_src_root}/mesh/mesh_are_equivalent_test.cc"
"${draco_src_root}/mesh/mesh_cleanup_test.cc"
"${draco_src_root}/mesh/triangle_soup_mesh_builder_test.cc"
"${draco_src_root}/metadata/metadata_encoder_test.cc"
"${draco_src_root}/metadata/metadata_test.cc"
"${draco_src_root}/point_cloud/point_cloud_builder_test.cc"
"${draco_src_root}/point_cloud/point_cloud_test.cc")
if(DRACO_TRANSCODER_SUPPORTED)
list(
APPEND draco_test_sources
"${draco_src_root}/animation/animation_test.cc"
"${draco_src_root}/io/gltf_decoder_test.cc"
"${draco_src_root}/io/gltf_encoder_test.cc"
"${draco_src_root}/io/gltf_utils_test.cc"
"${draco_src_root}/io/gltf_test_helper.cc"
"${draco_src_root}/io/gltf_test_helper.h"
"${draco_src_root}/io/scene_io_test.cc"
"${draco_src_root}/io/texture_io_test.cc"
"${draco_src_root}/material/material_library_test.cc"
"${draco_src_root}/material/material_test.cc"
"${draco_src_root}/metadata/property_attribute_test.cc"
"${draco_src_root}/metadata/property_table_test.cc"
"${draco_src_root}/metadata/structural_metadata_test.cc"
"${draco_src_root}/metadata/structural_metadata_schema_test.cc"
"${draco_src_root}/scene/instance_array_test.cc"
"${draco_src_root}/scene/light_test.cc"
"${draco_src_root}/scene/mesh_group_test.cc"
"${draco_src_root}/scene/scene_test.cc"
"${draco_src_root}/scene/scene_are_equivalent_test.cc"
"${draco_src_root}/scene/scene_utils_test.cc"
"${draco_src_root}/scene/trs_matrix_test.cc"
"${draco_src_root}/texture/texture_library_test.cc"
"${draco_src_root}/texture/texture_map_test.cc"
"${draco_src_root}/texture/texture_transform_test.cc")
endif()
macro(draco_setup_test_targets)
if(DRACO_TESTS)
draco_setup_googletest()
if(NOT (EXISTS ${draco_gtest_all} AND EXISTS ${draco_gtest_main}))
message(FATAL_ERROR "googletest missing, run git submodule update --init")
endif()
list(APPEND draco_test_defines GTEST_HAS_PTHREAD=0)
draco_add_library(
TEST
NAME draco_test_common
TYPE STATIC
SOURCES ${draco_test_common_sources}
DEFINES ${draco_defines} ${draco_test_defines}
INCLUDES ${draco_test_include_paths})
draco_add_library(
TEST
NAME draco_gtest
TYPE STATIC
SOURCES ${draco_gtest_all}
DEFINES ${draco_defines} ${draco_test_defines}
INCLUDES ${draco_test_include_paths})
draco_add_library(
TEST
NAME draco_gtest_main
TYPE STATIC
SOURCES ${draco_gtest_main}
DEFINES ${draco_defines} ${draco_test_defines}
INCLUDES ${draco_test_include_paths})
set(DRACO_TEST_DATA_DIR "${draco_root}/testdata")
set(DRACO_TEST_TEMP_DIR "${draco_build}/draco_test_temp")
set(DRACO_TEST_ROOT_DIR "${draco_root}")
file(MAKE_DIRECTORY "${DRACO_TEST_TEMP_DIR}")
# Sets DRACO_TEST_DATA_DIR and DRACO_TEST_TEMP_DIR.
configure_file("${draco_root}/cmake/draco_test_config.h.cmake"
"${draco_build}/testing/draco_test_config.h")
# Create the test targets.
draco_add_executable(
TEST
NAME draco_tests
SOURCES ${draco_test_sources}
DEFINES ${draco_defines} ${draco_test_defines}
INCLUDES ${draco_test_include_paths}
LIB_DEPS ${draco_dependency} draco_gtest draco_gtest_main
draco_test_common)
draco_add_executable(
TEST
NAME draco_factory_tests
SOURCES ${draco_factory_test_sources}
DEFINES ${draco_defines} ${draco_test_defines}
INCLUDES ${draco_test_include_paths}
LIB_DEPS ${draco_dependency} draco_gtest draco_gtest_main
draco_test_common)
endif()
endmacro()

View file

@ -0,0 +1,79 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_DRACO_VARIABLES_CMAKE_)
return()
endif() # DRACO_CMAKE_DRACO_VARIABLES_CMAKE_
set(DRACO_CMAKE_DRACO_VARIABLES_CMAKE_ 1)
# Halts generation when $variable_name does not refer to a directory that
# exists.
macro(draco_variable_must_be_directory variable_name)
if("${variable_name}" STREQUAL "")
message(
FATAL_ERROR
"Empty variable_name passed to draco_variable_must_be_directory.")
endif()
if("${${variable_name}}" STREQUAL "")
message(
FATAL_ERROR "Empty variable ${variable_name} is required to build draco.")
endif()
if(NOT IS_DIRECTORY "${${variable_name}}")
message(
FATAL_ERROR
"${variable_name}, which is ${${variable_name}}, does not refer to a\n"
"directory.")
endif()
endmacro()
# Adds $var_name to the tracked variables list.
macro(draco_track_configuration_variable var_name)
if(DRACO_VERBOSE GREATER 2)
message("---- draco_track_configuration_variable ----\n"
"var_name=${var_name}\n"
"----------------------------------------------\n")
endif()
list(APPEND draco_configuration_variables ${var_name})
list(REMOVE_DUPLICATES draco_configuration_variables)
endmacro()
# Logs current C++ and executable linker flags via the CMake message command.
macro(draco_dump_cmake_flag_variables)
unset(flag_variables)
list(APPEND flag_variables "CMAKE_CXX_FLAGS_INIT" "CMAKE_CXX_FLAGS"
"CMAKE_EXE_LINKER_FLAGS_INIT" "CMAKE_EXE_LINKER_FLAGS")
if(CMAKE_BUILD_TYPE)
list(
APPEND flag_variables
"CMAKE_BUILD_TYPE"
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
"CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}"
"CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}_INIT"
"CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE}")
endif()
foreach(flag_variable ${flag_variables})
message("${flag_variable}:${${flag_variable}}")
endforeach()
endmacro()
# Dumps the variables tracked in $draco_configuration_variables via the CMake
# message command.
macro(draco_dump_tracked_configuration_variables)
foreach(config_variable ${draco_configuration_variables})
message("${config_variable}:${${config_variable}}")
endforeach()
endmacro()

View file

@ -0,0 +1,28 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_)
return()
endif() # DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_
set(DRACO_CMAKE_TOOLCHAINS_AARCH64_LINUX_GNU_CMAKE_ 1)
set(CMAKE_SYSTEM_NAME "Linux")
if("${CROSS}" STREQUAL "")
set(CROSS aarch64-linux-gnu-)
endif()
set(CMAKE_CXX_COMPILER ${CROSS}g++)
set(CMAKE_CXX_FLAGS_INIT "-march=armv8-a")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")

View file

@ -0,0 +1,37 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ANDROID_NDK_COMMON_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ANDROID_NDK_COMMON_CMAKE_ 1)
# Toolchain files do not have access to cached variables:
# https://gitlab.kitware.com/cmake/cmake/issues/16170. Set an intermediate
# environment variable when loaded the first time.
if(DRACO_ANDROID_NDK_PATH)
set(ENV{DRACO_ANDROID_NDK_PATH} "${DRACO_ANDROID_NDK_PATH}")
else()
set(DRACO_ANDROID_NDK_PATH "$ENV{DRACO_ANDROID_NDK_PATH}")
endif()
set(CMAKE_SYSTEM_NAME Android)
if(NOT CMAKE_ANDROID_STL_TYPE)
set(CMAKE_ANDROID_STL_TYPE c++_static)
endif()
if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION)
set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)
endif()

View file

@ -0,0 +1,53 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ANDROID_CMAKE_)
return()
endif() # DRACO_CMAKE_TOOLCHAINS_ANDROID_CMAKE_
# Additional ANDROID_* settings are available, see:
# https://developer.android.com/ndk/guides/cmake#variables
if(NOT ANDROID_PLATFORM)
set(ANDROID_PLATFORM android-21)
endif()
# Choose target architecture with:
#
# -DANDROID_ABI={armeabi-v7a,armeabi-v7a with NEON,arm64-v8a,x86,x86_64}
if(NOT ANDROID_ABI)
set(ANDROID_ABI arm64-v8a)
endif()
# Force arm mode for 32-bit arm targets (instead of the default thumb) to
# improve performance.
if(ANDROID_ABI MATCHES "^armeabi" AND NOT ANDROID_ARM_MODE)
set(ANDROID_ARM_MODE arm)
endif()
# Toolchain files do not have access to cached variables:
# https://gitlab.kitware.com/cmake/cmake/issues/16170. Set an intermediate
# environment variable when loaded the first time.
if(DRACO_ANDROID_NDK_PATH)
set(ENV{DRACO_ANDROID_NDK_PATH} "${DRACO_ANDROID_NDK_PATH}")
else()
set(DRACO_ANDROID_NDK_PATH "$ENV{DRACO_ANDROID_NDK_PATH}")
endif()
if(NOT DRACO_ANDROID_NDK_PATH)
message(FATAL_ERROR "DRACO_ANDROID_NDK_PATH not set.")
return()
endif()
include("${DRACO_ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake")

View file

@ -0,0 +1,29 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARM_IOS_COMMON_CMAKE_)
return()
endif()
set(DRACO_CMAKE_ARM_IOS_COMMON_CMAKE_ 1)
set(CMAKE_SYSTEM_NAME "Darwin")
if(CMAKE_OSX_SDK)
set(CMAKE_OSX_SYSROOT ${CMAKE_OSX_SDK})
else()
set(CMAKE_OSX_SYSROOT iphoneos)
endif()
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_ARG1 "-arch ${CMAKE_SYSTEM_PROCESSOR}")
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_ARG1 "-arch ${CMAKE_SYSTEM_PROCESSOR}")

View file

@ -0,0 +1,29 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARM_LINUX_GNUEABIHF_CMAKE_)
return()
endif() # DRACO_CMAKE_TOOLCHAINS_ARM_LINUX_GNUEABIHF_CMAKE_
set(DRACO_CMAKE_TOOLCHAINS_ARM_LINUX_GNUEABIHF_CMAKE_ 1)
set(CMAKE_SYSTEM_NAME "Linux")
if("${CROSS}" STREQUAL "")
set(CROSS arm-linux-gnueabihf-)
endif()
set(CMAKE_CXX_COMPILER ${CROSS}g++)
set(CMAKE_CXX_FLAGS_INIT "-march=armv7-a -marm")
set(CMAKE_SYSTEM_PROCESSOR "armv7")
set(DRACO_NEON_INTRINSICS_FLAG "-mfpu=neon")

View file

@ -0,0 +1,30 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARM64_ANDROID_NDK_LIBCPP_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ARM64_ANDROID_NDK_LIBCPP_CMAKE_ 1)
include("${CMAKE_CURRENT_LIST_DIR}/android-ndk-common.cmake")
if(NOT ANDROID_PLATFORM)
set(ANROID_PLATFORM android-21)
endif()
if(NOT ANDROID_ABI)
set(ANDROID_ABI arm64-v8a)
endif()
include("${DRACO_ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake")

View file

@ -0,0 +1,27 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARM64_IOS_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ARM64_IOS_CMAKE_ 1)
if(XCODE)
message(FATAL_ERROR "This toolchain does not support Xcode.")
endif()
set(CMAKE_SYSTEM_PROCESSOR "arm64")
set(CMAKE_OSX_ARCHITECTURES "arm64")
include("${CMAKE_CURRENT_LIST_DIR}/arm-ios-common.cmake")

View file

@ -0,0 +1,32 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARM64_LINUX_GCC_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ARM64_LINUX_GCC_CMAKE_ 1)
set(CMAKE_SYSTEM_NAME "Linux")
if("${CROSS}" STREQUAL "")
# Default the cross compiler prefix to something known to work.
set(CROSS aarch64-linux-gnu-)
endif()
set(CMAKE_C_COMPILER ${CROSS}gcc)
set(CMAKE_CXX_COMPILER ${CROSS}g++)
set(AS_EXECUTABLE ${CROSS}as)
set(CMAKE_C_COMPILER_ARG1 "-march=armv8-a")
set(CMAKE_CXX_COMPILER_ARG1 "-march=armv8-a")
set(CMAKE_SYSTEM_PROCESSOR "arm64")

View file

@ -0,0 +1,30 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_ANDROID_NDK_LIBCPP_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ARMV7_ANDROID_NDK_LIBCPP_CMAKE_ 1)
include("${CMAKE_CURRENT_LIST_DIR}/android-ndk-common.cmake")
if(NOT ANDROID_PLATFORM)
set(ANDROID_PLATFORM android-18)
endif()
if(NOT ANDROID_ABI)
set(ANDROID_ABI armeabi-v7a)
endif()
include("${DRACO_ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake")

View file

@ -0,0 +1,27 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_IOS_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ARMV7_IOS_CMAKE_ 1)
if(XCODE)
message(FATAL_ERROR "This toolchain does not support Xcode.")
endif()
set(CMAKE_SYSTEM_PROCESSOR "armv7")
set(CMAKE_OSX_ARCHITECTURES "armv7")
include("${CMAKE_CURRENT_LIST_DIR}/arm-ios-common.cmake")

View file

@ -0,0 +1,38 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARMV7_LINUX_GCC_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ARMV7_LINUX_GCC_CMAKE_ 1)
set(CMAKE_SYSTEM_NAME "Linux")
if("${CROSS}" STREQUAL "")
# Default the cross compiler prefix to something known to work.
set(CROSS arm-linux-gnueabihf-)
endif()
if(NOT ${CROSS} MATCHES hf-$)
set(DRACO_EXTRA_TOOLCHAIN_FLAGS "-mfloat-abi=softfp")
endif()
set(CMAKE_C_COMPILER ${CROSS}gcc)
set(CMAKE_CXX_COMPILER ${CROSS}g++)
set(AS_EXECUTABLE ${CROSS}as)
set(CMAKE_C_COMPILER_ARG1
"-march=armv7-a -mfpu=neon ${DRACO_EXTRA_TOOLCHAIN_FLAGS}")
set(CMAKE_CXX_COMPILER_ARG1
"-march=armv7-a -mfpu=neon ${DRACO_EXTRA_TOOLCHAIN_FLAGS}")
set(CMAKE_SYSTEM_PROCESSOR "armv7")

View file

@ -0,0 +1,27 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_ARMV7S_IOS_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_ARMV7S_IOS_CMAKE_ 1)
if(XCODE)
message(FATAL_ERROR "This toolchain does not support Xcode.")
endif()
set(CMAKE_SYSTEM_PROCESSOR "armv7s")
set(CMAKE_OSX_ARCHITECTURES "armv7s")
include("${CMAKE_CURRENT_LIST_DIR}/arm-ios-common.cmake")

View file

@ -0,0 +1,28 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_i386_IOS_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_i386_IOS_CMAKE_ 1)
if(XCODE)
message(FATAL_ERROR "This toolchain does not support Xcode.")
endif()
set(CMAKE_SYSTEM_PROCESSOR "i386")
set(CMAKE_OSX_ARCHITECTURES "i386")
set(CMAKE_OSX_SDK "iphonesimulator")
include("${CMAKE_CURRENT_LIST_DIR}/arm-ios-common.cmake")

View file

@ -0,0 +1,30 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_X86_ANDROID_NDK_LIBCPP_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_X86_ANDROID_NDK_LIBCPP_CMAKE_ 1)
include("${CMAKE_CURRENT_LIST_DIR}/android-ndk-common.cmake")
if(NOT ANDROID_PLATFORM)
set(ANDROID_PLATFORM android-18)
endif()
if(NOT ANDROID_ABI)
set(ANDROID_ABI x86)
endif()
include("${DRACO_ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake")

View file

@ -0,0 +1,30 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_X86_64_ANDROID_NDK_LIBCPP_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_X86_64_ANDROID_NDK_LIBCPP_CMAKE_ 1)
include("${CMAKE_CURRENT_LIST_DIR}/android-ndk-common.cmake")
if(NOT ANDROID_PLATFORM)
set(ANDROID_PLATFORM android-21)
endif()
if(NOT ANDROID_ABI)
set(ANDROID_ABI x86_64)
endif()
include("${DRACO_ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake")

View file

@ -0,0 +1,28 @@
# Copyright 2021 The Draco Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if(DRACO_CMAKE_TOOLCHAINS_X86_64_IOS_CMAKE_)
return()
endif()
set(DRACO_CMAKE_TOOLCHAINS_X86_64_IOS_CMAKE_ 1)
if(XCODE)
message(FATAL_ERROR "This toolchain does not support Xcode.")
endif()
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
set(CMAKE_OSX_ARCHITECTURES "x86_64")
set(CMAKE_OSX_SDK "iphonesimulator")
include("${CMAKE_CURRENT_LIST_DIR}/arm-ios-common.cmake")

View file

@ -0,0 +1,47 @@
// Copyright 2019 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/animation.h"
#ifdef DRACO_TRANSCODER_SUPPORTED
namespace draco {
void Animation::Copy(const Animation &src) {
name_ = src.name_;
channels_.clear();
for (int i = 0; i < src.NumChannels(); ++i) {
std::unique_ptr<AnimationChannel> new_channel(new AnimationChannel());
new_channel->Copy(*src.GetChannel(i));
channels_.push_back(std::move(new_channel));
}
samplers_.clear();
for (int i = 0; i < src.NumSamplers(); ++i) {
std::unique_ptr<AnimationSampler> new_sampler(new AnimationSampler());
new_sampler->Copy(*src.GetSampler(i));
samplers_.push_back(std::move(new_sampler));
}
node_animation_data_.clear();
for (int i = 0; i < src.NumNodeAnimationData(); ++i) {
std::unique_ptr<NodeAnimationData> new_data(new NodeAnimationData());
new_data->Copy(*src.GetNodeAnimationData(i));
node_animation_data_.push_back(std::move(new_data));
}
}
} // namespace draco
#endif // DRACO_TRANSCODER_SUPPORTED

View file

@ -0,0 +1,149 @@
// Copyright 2019 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ANIMATION_ANIMATION_H_
#define DRACO_ANIMATION_ANIMATION_H_
#include "draco/draco_features.h"
#ifdef DRACO_TRANSCODER_SUPPORTED
#include <memory>
#include <vector>
#include "draco/animation/node_animation_data.h"
#include "draco/core/status.h"
namespace draco {
// Struct to hold information about an animation's sampler.
struct AnimationSampler {
enum class SamplerInterpolation { LINEAR, STEP, CUBICSPLINE };
static std::string InterpolationToString(SamplerInterpolation value) {
switch (value) {
case SamplerInterpolation::STEP:
return "STEP";
case SamplerInterpolation::CUBICSPLINE:
return "CUBICSPLINE";
default:
return "LINEAR";
}
}
AnimationSampler()
: input_index(-1),
interpolation_type(SamplerInterpolation::LINEAR),
output_index(-1) {}
void Copy(const AnimationSampler &src) {
input_index = src.input_index;
interpolation_type = src.interpolation_type;
output_index = src.output_index;
}
int input_index;
SamplerInterpolation interpolation_type;
int output_index;
};
// Struct to hold information about an animation's channel.
struct AnimationChannel {
enum class ChannelTransformation { TRANSLATION, ROTATION, SCALE, WEIGHTS };
static std::string TransformationToString(ChannelTransformation value) {
switch (value) {
case ChannelTransformation::ROTATION:
return "rotation";
case ChannelTransformation::SCALE:
return "scale";
case ChannelTransformation::WEIGHTS:
return "weights";
default:
return "translation";
}
}
AnimationChannel()
: target_index(-1),
transformation_type(ChannelTransformation::TRANSLATION),
sampler_index(-1) {}
void Copy(const AnimationChannel &src) {
target_index = src.target_index;
transformation_type = src.transformation_type;
sampler_index = src.sampler_index;
}
int target_index;
ChannelTransformation transformation_type;
int sampler_index;
};
// This class is used to hold data and information of glTF animations.
class Animation {
public:
Animation() {}
void Copy(const Animation &src);
const std::string &GetName() const { return name_; }
void SetName(const std::string &name) { name_ = name; }
// Returns the number of channels in an animation.
int NumChannels() const { return channels_.size(); }
// Returns the number of samplers in an animation.
int NumSamplers() const { return samplers_.size(); }
// Returns the number of accessors in an animation.
int NumNodeAnimationData() const { return node_animation_data_.size(); }
// Returns a channel in the animation.
AnimationChannel *GetChannel(int index) { return channels_[index].get(); }
const AnimationChannel *GetChannel(int index) const {
return channels_[index].get();
}
// Returns a sampler in the animation.
AnimationSampler *GetSampler(int index) { return samplers_[index].get(); }
const AnimationSampler *GetSampler(int index) const {
return samplers_[index].get();
}
// Returns an accessor in the animation.
NodeAnimationData *GetNodeAnimationData(int index) {
return node_animation_data_[index].get();
}
const NodeAnimationData *GetNodeAnimationData(int index) const {
return node_animation_data_[index].get();
}
void AddNodeAnimationData(
std::unique_ptr<NodeAnimationData> node_animation_data) {
node_animation_data_.push_back(std::move(node_animation_data));
}
void AddSampler(std::unique_ptr<AnimationSampler> sampler) {
samplers_.push_back(std::move(sampler));
}
void AddChannel(std::unique_ptr<AnimationChannel> channel) {
channels_.push_back(std::move(channel));
}
private:
std::string name_;
std::vector<std::unique_ptr<AnimationSampler>> samplers_;
std::vector<std::unique_ptr<AnimationChannel>> channels_;
std::vector<std::unique_ptr<NodeAnimationData>> node_animation_data_;
};
} // namespace draco
#endif // DRACO_TRANSCODER_SUPPORTED
#endif // DRACO_ANIMATION_ANIMATION_H_

View file

@ -0,0 +1,71 @@
// Copyright 2021 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/animation.h"
#include "draco/core/draco_test_base.h"
#include "draco/draco_features.h"
namespace {
#ifdef DRACO_TRANSCODER_SUPPORTED
TEST(AnimationTest, TestCopy) {
// Test copying of animation data.
draco::Animation src_anim;
ASSERT_TRUE(src_anim.GetName().empty());
src_anim.SetName("Walking");
ASSERT_EQ(src_anim.GetName(), "Walking");
std::unique_ptr<draco::AnimationSampler> src_sampler_0(
new draco::AnimationSampler());
src_sampler_0->interpolation_type =
draco::AnimationSampler::SamplerInterpolation::CUBICSPLINE;
std::unique_ptr<draco::AnimationSampler> src_sampler_1(
new draco::AnimationSampler());
src_sampler_1->Copy(*src_sampler_0);
ASSERT_EQ(src_sampler_0->interpolation_type,
src_sampler_1->interpolation_type);
src_sampler_1->interpolation_type =
draco::AnimationSampler::SamplerInterpolation::STEP;
src_anim.AddSampler(std::move(src_sampler_0));
src_anim.AddSampler(std::move(src_sampler_1));
ASSERT_EQ(src_anim.NumSamplers(), 2);
std::unique_ptr<draco::AnimationChannel> src_channel(
new draco::AnimationChannel());
src_channel->transformation_type =
draco::AnimationChannel::ChannelTransformation::WEIGHTS;
src_anim.AddChannel(std::move(src_channel));
ASSERT_EQ(src_anim.NumChannels(), 1);
draco::Animation dst_anim;
dst_anim.Copy(src_anim);
ASSERT_EQ(dst_anim.GetName(), src_anim.GetName());
ASSERT_EQ(dst_anim.NumSamplers(), 2);
ASSERT_EQ(dst_anim.NumChannels(), 1);
ASSERT_EQ(dst_anim.GetSampler(0)->interpolation_type,
src_anim.GetSampler(0)->interpolation_type);
ASSERT_EQ(dst_anim.GetSampler(1)->interpolation_type,
src_anim.GetSampler(1)->interpolation_type);
ASSERT_EQ(dst_anim.GetChannel(0)->transformation_type,
src_anim.GetChannel(0)->transformation_type);
}
#endif // DRACO_TRANSCODER_SUPPORTED
} // namespace

View file

@ -0,0 +1,54 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/keyframe_animation.h"
namespace draco {
KeyframeAnimation::KeyframeAnimation() {}
bool KeyframeAnimation::SetTimestamps(
const std::vector<TimestampType> &timestamp) {
// Already added attributes.
const int32_t num_frames = timestamp.size();
if (num_attributes() > 0) {
// Timestamp attribute could be added only once.
if (timestamps()->size()) {
return false;
} else {
// Check if the number of frames is consistent with
// the existing keyframes.
if (num_frames != num_points()) {
return false;
}
}
} else {
// This is the first attribute.
set_num_frames(num_frames);
}
// Add attribute for time stamp data.
std::unique_ptr<PointAttribute> timestamp_att =
std::unique_ptr<PointAttribute>(new PointAttribute());
timestamp_att->Init(GeometryAttribute::GENERIC, 1, DT_FLOAT32, false,
num_frames);
for (PointIndex i(0); i < num_frames; ++i) {
timestamp_att->SetAttributeValue(timestamp_att->mapped_index(i),
&timestamp[i.value()]);
}
this->SetAttribute(kTimestampId, std::move(timestamp_att));
return true;
}
} // namespace draco

View file

@ -0,0 +1,107 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ANIMATION_KEYFRAME_ANIMATION_H_
#define DRACO_ANIMATION_KEYFRAME_ANIMATION_H_
#include <vector>
#include "draco/point_cloud/point_cloud.h"
namespace draco {
// Class for holding keyframe animation data. It will have two or more
// attributes as a point cloud. The first attribute is always the timestamp
// of the animation. Each KeyframeAnimation could have multiple animations with
// the same number of frames. Each animation will be treated as a point
// attribute.
class KeyframeAnimation : public PointCloud {
public:
// Force time stamp to be float type.
using TimestampType = float;
KeyframeAnimation();
// Animation must have only one timestamp attribute.
// This function must be called before adding any animation data.
// Returns false if timestamp already exists.
bool SetTimestamps(const std::vector<TimestampType> &timestamp);
// Returns an id for the added animation data. This id will be used to
// identify this animation.
// Returns -1 if error, e.g. number of frames is not consistent.
// Type |T| should be consistent with |DataType|, e.g:
// float - DT_FLOAT32,
// int32_t - DT_INT32, ...
template <typename T>
int32_t AddKeyframes(DataType data_type, uint32_t num_components,
const std::vector<T> &data);
const PointAttribute *timestamps() const {
return GetAttributeByUniqueId(kTimestampId);
}
const PointAttribute *keyframes(int32_t animation_id) const {
return GetAttributeByUniqueId(animation_id);
}
// Number of frames should be equal to number points in the point cloud.
void set_num_frames(int32_t num_frames) { set_num_points(num_frames); }
int32_t num_frames() const { return static_cast<int32_t>(num_points()); }
int32_t num_animations() const { return num_attributes() - 1; }
private:
// Attribute id of timestamp is fixed to 0.
static constexpr int32_t kTimestampId = 0;
};
template <typename T>
int32_t KeyframeAnimation::AddKeyframes(DataType data_type,
uint32_t num_components,
const std::vector<T> &data) {
// TODO(draco-eng): Verify T is consistent with |data_type|.
if (num_components == 0) {
return -1;
}
// If timestamps is not added yet, then reserve attribute 0 for timestamps.
if (!num_attributes()) {
// Add a temporary attribute with 0 points to fill attribute id 0.
std::unique_ptr<PointAttribute> temp_att =
std::unique_ptr<PointAttribute>(new PointAttribute());
temp_att->Init(GeometryAttribute::GENERIC, num_components, data_type, false,
0);
this->AddAttribute(std::move(temp_att));
set_num_frames(data.size() / num_components);
}
if (data.size() != num_components * num_frames()) {
return -1;
}
std::unique_ptr<PointAttribute> keyframe_att =
std::unique_ptr<PointAttribute>(new PointAttribute());
keyframe_att->Init(GeometryAttribute::GENERIC, num_components, data_type,
false, num_frames());
const size_t stride = num_components;
for (PointIndex i(0); i < num_frames(); ++i) {
keyframe_att->SetAttributeValue(keyframe_att->mapped_index(i),
&data[i.value() * stride]);
}
return this->AddAttribute(std::move(keyframe_att));
}
} // namespace draco
#endif // DRACO_ANIMATION_KEYFRAME_ANIMATION_H_

View file

@ -0,0 +1,30 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/keyframe_animation_decoder.h"
namespace draco {
Status KeyframeAnimationDecoder::Decode(const DecoderOptions &options,
DecoderBuffer *in_buffer,
KeyframeAnimation *animation) {
const auto status = PointCloudSequentialDecoder::Decode(
options, in_buffer, static_cast<PointCloud *>(animation));
if (!status.ok()) {
return status;
}
return OkStatus();
}
} // namespace draco

View file

@ -0,0 +1,34 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ANIMATION_KEYFRAME_ANIMATION_DECODER_H_
#define DRACO_ANIMATION_KEYFRAME_ANIMATION_DECODER_H_
#include "draco/animation/keyframe_animation.h"
#include "draco/compression/point_cloud/point_cloud_sequential_decoder.h"
namespace draco {
// Class for decoding keyframe animation.
class KeyframeAnimationDecoder : private PointCloudSequentialDecoder {
public:
KeyframeAnimationDecoder(){};
Status Decode(const DecoderOptions &options, DecoderBuffer *in_buffer,
KeyframeAnimation *animation);
};
} // namespace draco
#endif // DRACO_ANIMATION_KEYFRAME_ANIMATION_DECODER_H_

View file

@ -0,0 +1,28 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/keyframe_animation_encoder.h"
namespace draco {
KeyframeAnimationEncoder::KeyframeAnimationEncoder() {}
Status KeyframeAnimationEncoder::EncodeKeyframeAnimation(
const KeyframeAnimation &animation, const EncoderOptions &options,
EncoderBuffer *out_buffer) {
SetPointCloud(animation);
return Encode(options, out_buffer);
}
} // namespace draco

View file

@ -0,0 +1,39 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ANIMATION_KEYFRAME_ANIMATION_ENCODER_H_
#define DRACO_ANIMATION_KEYFRAME_ANIMATION_ENCODER_H_
#include "draco/animation/keyframe_animation.h"
#include "draco/compression/point_cloud/point_cloud_sequential_encoder.h"
namespace draco {
// Class for encoding keyframe animation. It takes KeyframeAnimation as a
// PointCloud and compress it. It's mostly a wrapper around PointCloudEncoder so
// that the animation module could be separated from geometry compression when
// exposed to developers.
class KeyframeAnimationEncoder : private PointCloudSequentialEncoder {
public:
KeyframeAnimationEncoder();
// Encode an animation to a buffer.
Status EncodeKeyframeAnimation(const KeyframeAnimation &animation,
const EncoderOptions &options,
EncoderBuffer *out_buffer);
};
} // namespace draco
#endif // DRACO_ANIMATION_KEYFRAME_ANIMATION_ENCODER_H_

View file

@ -0,0 +1,169 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/keyframe_animation.h"
#include "draco/animation/keyframe_animation_decoder.h"
#include "draco/animation/keyframe_animation_encoder.h"
#include "draco/core/draco_test_base.h"
#include "draco/core/draco_test_utils.h"
namespace draco {
class KeyframeAnimationEncodingTest : public ::testing::Test {
protected:
KeyframeAnimationEncodingTest() {}
bool CreateAndAddTimestamps(int32_t num_frames) {
timestamps_.resize(num_frames);
for (int i = 0; i < timestamps_.size(); ++i) {
timestamps_[i] = static_cast<draco::KeyframeAnimation::TimestampType>(i);
}
return keyframe_animation_.SetTimestamps(timestamps_);
}
int32_t CreateAndAddAnimationData(int32_t num_frames,
uint32_t num_components) {
// Create and add animation data with.
animation_data_.resize(num_frames * num_components);
for (int i = 0; i < animation_data_.size(); ++i) {
animation_data_[i] = static_cast<float>(i);
}
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
animation_data_);
}
template <int num_components_t>
void CompareAnimationData(const KeyframeAnimation &animation0,
const KeyframeAnimation &animation1,
bool quantized) {
ASSERT_EQ(animation0.num_frames(), animation1.num_frames());
ASSERT_EQ(animation0.num_animations(), animation1.num_animations());
if (quantized) {
// TODO(b/199760123) : Add test for stable quantization.
// Quantization will result in slightly different values.
// Skip comparing values.
return;
}
// Compare time stamp.
const auto timestamp_att0 = animation0.timestamps();
const auto timestamp_att1 = animation0.timestamps();
for (int i = 0; i < animation0.num_frames(); ++i) {
std::array<float, 1> att_value0;
std::array<float, 1> att_value1;
ASSERT_TRUE((timestamp_att0->GetValue<float, 1>(
draco::AttributeValueIndex(i), &att_value0)));
ASSERT_TRUE((timestamp_att1->GetValue<float, 1>(
draco::AttributeValueIndex(i), &att_value1)));
ASSERT_FLOAT_EQ(att_value0[0], att_value1[0]);
}
for (int animation_id = 1; animation_id < animation0.num_animations();
++animation_id) {
// Compare keyframe data.
const auto keyframe_att0 = animation0.keyframes(animation_id);
const auto keyframe_att1 = animation1.keyframes(animation_id);
ASSERT_EQ(keyframe_att0->num_components(),
keyframe_att1->num_components());
for (int i = 0; i < animation0.num_frames(); ++i) {
std::array<float, num_components_t> att_value0;
std::array<float, num_components_t> att_value1;
ASSERT_TRUE((keyframe_att0->GetValue<float, num_components_t>(
draco::AttributeValueIndex(i), &att_value0)));
ASSERT_TRUE((keyframe_att1->GetValue<float, num_components_t>(
draco::AttributeValueIndex(i), &att_value1)));
for (int j = 0; j < att_value0.size(); ++j) {
ASSERT_FLOAT_EQ(att_value0[j], att_value1[j]);
}
}
}
}
template <int num_components_t>
void TestKeyframeAnimationEncoding() {
TestKeyframeAnimationEncoding<num_components_t>(false);
}
template <int num_components_t>
void TestKeyframeAnimationEncoding(bool quantized) {
// Encode animation class.
draco::EncoderBuffer buffer;
draco::KeyframeAnimationEncoder encoder;
EncoderOptions options = EncoderOptions::CreateDefaultOptions();
if (quantized) {
// Set quantization for timestamps.
options.SetAttributeInt(0, "quantization_bits", 20);
// Set quantization for keyframes.
for (int i = 1; i <= keyframe_animation_.num_animations(); ++i) {
options.SetAttributeInt(i, "quantization_bits", 20);
}
}
DRACO_ASSERT_OK(
encoder.EncodeKeyframeAnimation(keyframe_animation_, options, &buffer));
draco::DecoderBuffer dec_decoder;
draco::KeyframeAnimationDecoder decoder;
DecoderBuffer dec_buffer;
dec_buffer.Init(buffer.data(), buffer.size());
// Decode animation class.
std::unique_ptr<KeyframeAnimation> decoded_animation(
new KeyframeAnimation());
DecoderOptions dec_options;
DRACO_ASSERT_OK(
decoder.Decode(dec_options, &dec_buffer, decoded_animation.get()));
// Verify if animation before and after compression is identical.
CompareAnimationData<num_components_t>(keyframe_animation_,
*decoded_animation, quantized);
}
draco::KeyframeAnimation keyframe_animation_;
std::vector<draco::KeyframeAnimation::TimestampType> timestamps_;
std::vector<float> animation_data_;
};
TEST_F(KeyframeAnimationEncodingTest, OneComponent) {
const int num_frames = 1;
ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
ASSERT_EQ(CreateAndAddAnimationData(num_frames, 1), 1);
TestKeyframeAnimationEncoding<1>();
}
TEST_F(KeyframeAnimationEncodingTest, ManyComponents) {
const int num_frames = 100;
ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
ASSERT_EQ(CreateAndAddAnimationData(num_frames, 100), 1);
TestKeyframeAnimationEncoding<100>();
}
TEST_F(KeyframeAnimationEncodingTest, ManyComponentsWithQuantization) {
const int num_frames = 100;
ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
ASSERT_EQ(CreateAndAddAnimationData(num_frames, 4), 1);
// Test compression with quantization.
TestKeyframeAnimationEncoding<4>(true);
}
TEST_F(KeyframeAnimationEncodingTest, MultipleAnimations) {
const int num_frames = 5;
ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
ASSERT_EQ(CreateAndAddAnimationData(num_frames, 3), 1);
ASSERT_EQ(CreateAndAddAnimationData(num_frames, 3), 2);
TestKeyframeAnimationEncoding<3>();
}
} // namespace draco

View file

@ -0,0 +1,104 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/keyframe_animation.h"
#include "draco/core/draco_test_base.h"
namespace {
class KeyframeAnimationTest : public ::testing::Test {
protected:
KeyframeAnimationTest() {}
bool CreateAndAddTimestamps(int32_t num_frames) {
timestamps_.resize(num_frames);
for (int i = 0; i < timestamps_.size(); ++i) {
timestamps_[i] = static_cast<draco::KeyframeAnimation::TimestampType>(i);
}
return keyframe_animation_.SetTimestamps(timestamps_);
}
int32_t CreateAndAddAnimationData(int32_t num_frames,
uint32_t num_components) {
// Create and add animation data with.
animation_data_.resize(num_frames * num_components);
for (int i = 0; i < animation_data_.size(); ++i) {
animation_data_[i] = static_cast<float>(i);
}
return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
animation_data_);
}
template <int num_components_t>
void CompareAnimationData() {
// Compare time stamp.
const auto timestamp_att = keyframe_animation_.timestamps();
for (int i = 0; i < timestamps_.size(); ++i) {
std::array<float, 1> att_value;
ASSERT_TRUE((timestamp_att->GetValue<float, 1>(
draco::AttributeValueIndex(i), &att_value)));
ASSERT_FLOAT_EQ(att_value[0], i);
}
// Compare keyframe data.
const auto keyframe_att = keyframe_animation_.keyframes(1);
for (int i = 0; i < animation_data_.size() / num_components_t; ++i) {
std::array<float, num_components_t> att_value;
ASSERT_TRUE((keyframe_att->GetValue<float, num_components_t>(
draco::AttributeValueIndex(i), &att_value)));
for (int j = 0; j < num_components_t; ++j) {
ASSERT_FLOAT_EQ(att_value[j], i * num_components_t + j);
}
}
}
template <int num_components_t>
void TestKeyframeAnimation(int32_t num_frames) {
ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
ASSERT_EQ(CreateAndAddAnimationData(num_frames, num_components_t), 1);
CompareAnimationData<num_components_t>();
}
draco::KeyframeAnimation keyframe_animation_;
std::vector<draco::KeyframeAnimation::TimestampType> timestamps_;
std::vector<float> animation_data_;
};
// Test animation with 1 component and 10 frames.
TEST_F(KeyframeAnimationTest, OneComponent) { TestKeyframeAnimation<1>(10); }
// Test animation with 4 component and 10 frames.
TEST_F(KeyframeAnimationTest, FourComponent) { TestKeyframeAnimation<4>(10); }
// Test adding animation data before timestamp.
TEST_F(KeyframeAnimationTest, AddingAnimationFirst) {
ASSERT_EQ(CreateAndAddAnimationData(5, 1), 1);
ASSERT_TRUE(CreateAndAddTimestamps(5));
}
// Test adding timestamp more than once.
TEST_F(KeyframeAnimationTest, ErrorAddingTimestampsTwice) {
ASSERT_TRUE(CreateAndAddTimestamps(5));
ASSERT_FALSE(CreateAndAddTimestamps(5));
}
// Test animation with multiple animation data.
TEST_F(KeyframeAnimationTest, MultipleAnimationData) {
const int num_frames = 5;
ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
ASSERT_EQ(CreateAndAddAnimationData(num_frames, 1), 1);
ASSERT_EQ(CreateAndAddAnimationData(num_frames, 2), 2);
}
} // namespace

View file

@ -0,0 +1,150 @@
// Copyright 2019 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ANIMATION_NODE_ANIMATION_DATA_H_
#define DRACO_ANIMATION_NODE_ANIMATION_DATA_H_
#include "draco/draco_features.h"
#ifdef DRACO_TRANSCODER_SUPPORTED
#include "draco/core/hash_utils.h"
#include "draco/core/status.h"
#include "draco/core/status_or.h"
namespace draco {
// This class is used to store information and data for animations that only
// affect the nodes.
// TODO(fgalligan): Think about changing the name of this class now that Skin
// is using it.
class NodeAnimationData {
public:
enum class Type { SCALAR, VEC3, VEC4, MAT4 };
NodeAnimationData() : type_(Type::SCALAR), count_(0), normalized_(false) {}
void Copy(const NodeAnimationData &src) {
type_ = src.type_;
count_ = src.count_;
normalized_ = src.normalized_;
data_ = src.data_;
}
Type type() const { return type_; }
int count() const { return count_; }
bool normalized() const { return normalized_; }
std::vector<float> *GetMutableData() { return &data_; }
const std::vector<float> *GetData() const { return &data_; }
void SetType(Type type) { type_ = type; }
void SetCount(int count) { count_ = count; }
void SetNormalized(bool normalized) { normalized_ = normalized; }
int ComponentSize() const { return sizeof(float); }
int NumComponents() const {
switch (type_) {
case Type::SCALAR:
return 1;
case Type::VEC3:
return 3;
case Type::MAT4:
return 16;
default:
return 4;
}
}
std::string TypeAsString() const {
switch (type_) {
case Type::SCALAR:
return "SCALAR";
case Type::VEC3:
return "VEC3";
case Type::MAT4:
return "MAT4";
default:
return "VEC4";
}
}
bool operator==(const NodeAnimationData &nad) const {
return type_ == nad.type_ && count_ == nad.count_ &&
normalized_ == nad.normalized_ && data_ == nad.data_;
}
private:
Type type_;
int count_;
bool normalized_;
std::vector<float> data_;
};
// Wrapper class for hashing NodeAnimationData. When using different containers,
// this class is preferable instead of copying the data in NodeAnimationData
// every time.
class NodeAnimationDataHash {
public:
NodeAnimationDataHash() = delete;
NodeAnimationDataHash &operator=(const NodeAnimationDataHash &) = delete;
NodeAnimationDataHash(NodeAnimationDataHash &&) = delete;
NodeAnimationDataHash &operator=(NodeAnimationDataHash &&) = delete;
explicit NodeAnimationDataHash(const NodeAnimationData *nad)
: node_animation_data_(nad) {
hash_ = NodeAnimationDataHash::HashNodeAnimationData(*node_animation_data_);
}
NodeAnimationDataHash(const NodeAnimationDataHash &nadh) {
node_animation_data_ = nadh.node_animation_data_;
hash_ = nadh.hash_;
}
bool operator==(const NodeAnimationDataHash &nadh) const {
return *node_animation_data_ == *nadh.node_animation_data_;
}
struct Hash {
size_t operator()(const NodeAnimationDataHash &nadh) const {
return nadh.hash_;
}
};
const NodeAnimationData *GetNodeAnimationData() {
return node_animation_data_;
}
private:
// Returns a hash of |nad|.
static size_t HashNodeAnimationData(const NodeAnimationData &nad) {
size_t hash = 79; // Magic number.
hash = HashCombine(static_cast<int>(nad.type()), hash);
hash = HashCombine(nad.count(), hash);
hash = HashCombine(nad.normalized(), hash);
const uint64_t data_hash =
FingerprintString(reinterpret_cast<const char *>(nad.GetData()->data()),
nad.GetData()->size() * sizeof(float));
hash = HashCombine(data_hash, hash);
return hash;
}
const NodeAnimationData *node_animation_data_;
size_t hash_;
};
} // namespace draco
#endif // DRACO_TRANSCODER_SUPPORTED
#endif // DRACO_ANIMATION_NODE_ANIMATION_DATA_H_

View file

@ -0,0 +1,29 @@
// Copyright 2019 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/animation/skin.h"
#ifdef DRACO_TRANSCODER_SUPPORTED
namespace draco {
void Skin::Copy(const Skin &s) {
inverse_bind_matrices_.Copy(s.GetInverseBindMatrices());
joints_ = s.GetJoints();
joint_root_index_ = s.GetJointRoot();
}
} // namespace draco
#endif // DRACO_TRANSCODER_SUPPORTED

View file

@ -0,0 +1,64 @@
// Copyright 2019 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ANIMATION_SKIN_H_
#define DRACO_ANIMATION_SKIN_H_
#include "draco/draco_features.h"
#ifdef DRACO_TRANSCODER_SUPPORTED
#include <vector>
#include "draco/animation/node_animation_data.h"
#include "draco/scene/scene_indices.h"
namespace draco {
// This class is used to store information on animation skins.
class Skin {
public:
Skin() : joint_root_index_(-1) {}
void Copy(const Skin &s);
NodeAnimationData &GetInverseBindMatrices() { return inverse_bind_matrices_; }
const NodeAnimationData &GetInverseBindMatrices() const {
return inverse_bind_matrices_;
}
int AddJoint(SceneNodeIndex index) {
joints_.push_back(index);
return joints_.size() - 1;
}
int NumJoints() const { return joints_.size(); }
SceneNodeIndex GetJoint(int index) const { return joints_[index]; }
SceneNodeIndex &GetJoint(int index) { return joints_[index]; }
const std::vector<SceneNodeIndex> &GetJoints() const { return joints_; }
void SetJointRoot(SceneNodeIndex index) { joint_root_index_ = index; }
SceneNodeIndex GetJointRoot() const { return joint_root_index_; }
private:
NodeAnimationData inverse_bind_matrices_;
// List of node indices that make up the joint hierarchy.
std::vector<SceneNodeIndex> joints_;
SceneNodeIndex joint_root_index_;
};
} // namespace draco
#endif // DRACO_TRANSCODER_SUPPORTED
#endif // DRACO_ANIMATION_SKIN_H_

View file

@ -0,0 +1,145 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/attributes/attribute_octahedron_transform.h"
#include "draco/attributes/attribute_transform_type.h"
#include "draco/compression/attributes/normal_compression_utils.h"
namespace draco {
bool AttributeOctahedronTransform::InitFromAttribute(
const PointAttribute &attribute) {
const AttributeTransformData *const transform_data =
attribute.GetAttributeTransformData();
if (!transform_data ||
transform_data->transform_type() != ATTRIBUTE_OCTAHEDRON_TRANSFORM) {
return false; // Wrong transform type.
}
quantization_bits_ = transform_data->GetParameterValue<int32_t>(0);
return true;
}
void AttributeOctahedronTransform::CopyToAttributeTransformData(
AttributeTransformData *out_data) const {
out_data->set_transform_type(ATTRIBUTE_OCTAHEDRON_TRANSFORM);
out_data->AppendParameterValue(quantization_bits_);
}
bool AttributeOctahedronTransform::TransformAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
PointAttribute *target_attribute) {
return GeneratePortableAttribute(attribute, point_ids,
target_attribute->size(), target_attribute);
}
bool AttributeOctahedronTransform::InverseTransformAttribute(
const PointAttribute &attribute, PointAttribute *target_attribute) {
if (target_attribute->data_type() != DT_FLOAT32) {
return false;
}
const int num_points = target_attribute->size();
const int num_components = target_attribute->num_components();
if (num_components != 3) {
return false;
}
constexpr int kEntrySize = sizeof(float) * 3;
float att_val[3];
const int32_t *source_attribute_data = reinterpret_cast<const int32_t *>(
attribute.GetAddress(AttributeValueIndex(0)));
uint8_t *target_address =
target_attribute->GetAddress(AttributeValueIndex(0));
OctahedronToolBox octahedron_tool_box;
if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) {
return false;
}
for (uint32_t i = 0; i < num_points; ++i) {
const int32_t s = *source_attribute_data++;
const int32_t t = *source_attribute_data++;
octahedron_tool_box.QuantizedOctahedralCoordsToUnitVector(s, t, att_val);
// Store the decoded floating point values into the attribute buffer.
std::memcpy(target_address, att_val, kEntrySize);
target_address += kEntrySize;
}
return true;
}
void AttributeOctahedronTransform::SetParameters(int quantization_bits) {
quantization_bits_ = quantization_bits;
}
bool AttributeOctahedronTransform::EncodeParameters(
EncoderBuffer *encoder_buffer) const {
if (is_initialized()) {
encoder_buffer->Encode(static_cast<uint8_t>(quantization_bits_));
return true;
}
return false;
}
bool AttributeOctahedronTransform::DecodeParameters(
const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
uint8_t quantization_bits;
if (!decoder_buffer->Decode(&quantization_bits)) {
return false;
}
quantization_bits_ = quantization_bits;
return true;
}
bool AttributeOctahedronTransform::GeneratePortableAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
int num_points, PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
// Quantize all values in the order given by point_ids into portable
// attribute.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
target_attribute->GetAddress(AttributeValueIndex(0)));
float att_val[3];
int32_t dst_index = 0;
OctahedronToolBox converter;
if (!converter.SetQuantizationBits(quantization_bits_)) {
return false;
}
if (!point_ids.empty()) {
for (uint32_t i = 0; i < point_ids.size(); ++i) {
const AttributeValueIndex att_val_id =
attribute.mapped_index(point_ids[i]);
attribute.GetValue(att_val_id, att_val);
// Encode the vector into a s and t octahedral coordinates.
int32_t s, t;
converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
portable_attribute_data[dst_index++] = s;
portable_attribute_data[dst_index++] = t;
}
} else {
for (PointIndex i(0); i < num_points; ++i) {
const AttributeValueIndex att_val_id = attribute.mapped_index(i);
attribute.GetValue(att_val_id, att_val);
// Encode the vector into a s and t octahedral coordinates.
int32_t s, t;
converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
portable_attribute_data[dst_index++] = s;
portable_attribute_data[dst_index++] = t;
}
}
return true;
}
} // namespace draco

View file

@ -0,0 +1,81 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_
#define DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_
#include "draco/attributes/attribute_transform.h"
#include "draco/attributes/point_attribute.h"
#include "draco/core/encoder_buffer.h"
namespace draco {
// Attribute transform for attributes transformed to octahedral coordinates.
class AttributeOctahedronTransform : public AttributeTransform {
public:
AttributeOctahedronTransform() : quantization_bits_(-1) {}
// Return attribute transform type.
AttributeTransformType Type() const override {
return ATTRIBUTE_OCTAHEDRON_TRANSFORM;
}
// Try to init transform from attribute.
bool InitFromAttribute(const PointAttribute &attribute) override;
// Copy parameter values into the provided AttributeTransformData instance.
void CopyToAttributeTransformData(
AttributeTransformData *out_data) const override;
bool TransformAttribute(const PointAttribute &attribute,
const std::vector<PointIndex> &point_ids,
PointAttribute *target_attribute) override;
bool InverseTransformAttribute(const PointAttribute &attribute,
PointAttribute *target_attribute) override;
// Set number of quantization bits.
void SetParameters(int quantization_bits);
// Encode relevant parameters into buffer.
bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
bool DecodeParameters(const PointAttribute &attribute,
DecoderBuffer *decoder_buffer) override;
bool is_initialized() const { return quantization_bits_ != -1; }
int32_t quantization_bits() const { return quantization_bits_; }
protected:
DataType GetTransformedDataType(
const PointAttribute &attribute) const override {
return DT_UINT32;
}
int GetTransformedNumComponents(
const PointAttribute &attribute) const override {
return 2;
}
// Perform the actual transformation.
bool GeneratePortableAttribute(const PointAttribute &attribute,
const std::vector<PointIndex> &point_ids,
int num_points,
PointAttribute *target_attribute) const;
private:
int32_t quantization_bits_;
};
} // namespace draco
#endif // DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_

View file

@ -0,0 +1,268 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/attributes/attribute_quantization_transform.h"
#include <cmath>
#include <cstring>
#include <memory>
#include <vector>
#include "draco/attributes/attribute_transform_type.h"
#include "draco/core/quantization_utils.h"
namespace draco {
bool AttributeQuantizationTransform::InitFromAttribute(
const PointAttribute &attribute) {
const AttributeTransformData *const transform_data =
attribute.GetAttributeTransformData();
if (!transform_data ||
transform_data->transform_type() != ATTRIBUTE_QUANTIZATION_TRANSFORM) {
return false; // Wrong transform type.
}
int32_t byte_offset = 0;
quantization_bits_ = transform_data->GetParameterValue<int32_t>(byte_offset);
byte_offset += 4;
min_values_.resize(attribute.num_components());
for (int i = 0; i < attribute.num_components(); ++i) {
min_values_[i] = transform_data->GetParameterValue<float>(byte_offset);
byte_offset += 4;
}
range_ = transform_data->GetParameterValue<float>(byte_offset);
return true;
}
// Copy parameter values into the provided AttributeTransformData instance.
void AttributeQuantizationTransform::CopyToAttributeTransformData(
AttributeTransformData *out_data) const {
out_data->set_transform_type(ATTRIBUTE_QUANTIZATION_TRANSFORM);
out_data->AppendParameterValue(quantization_bits_);
for (int i = 0; i < min_values_.size(); ++i) {
out_data->AppendParameterValue(min_values_[i]);
}
out_data->AppendParameterValue(range_);
}
bool AttributeQuantizationTransform::TransformAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
PointAttribute *target_attribute) {
if (point_ids.empty()) {
GeneratePortableAttribute(attribute, target_attribute->size(),
target_attribute);
} else {
GeneratePortableAttribute(attribute, point_ids, target_attribute->size(),
target_attribute);
}
return true;
}
bool AttributeQuantizationTransform::InverseTransformAttribute(
const PointAttribute &attribute, PointAttribute *target_attribute) {
if (target_attribute->data_type() != DT_FLOAT32) {
return false;
}
// Convert all quantized values back to floats.
const int32_t max_quantized_value =
(1u << static_cast<uint32_t>(quantization_bits_)) - 1;
const int num_components = target_attribute->num_components();
const int entry_size = sizeof(float) * num_components;
const std::unique_ptr<float[]> att_val(new float[num_components]);
int quant_val_id = 0;
int out_byte_pos = 0;
Dequantizer dequantizer;
if (!dequantizer.Init(range_, max_quantized_value)) {
return false;
}
const int32_t *const source_attribute_data =
reinterpret_cast<const int32_t *>(
attribute.GetAddress(AttributeValueIndex(0)));
const int num_values = target_attribute->size();
for (uint32_t i = 0; i < num_values; ++i) {
for (int c = 0; c < num_components; ++c) {
float value =
dequantizer.DequantizeFloat(source_attribute_data[quant_val_id++]);
value = value + min_values_[c];
att_val[c] = value;
}
// Store the floating point value into the attribute buffer.
target_attribute->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
out_byte_pos += entry_size;
}
return true;
}
bool AttributeQuantizationTransform::IsQuantizationValid(
int quantization_bits) {
// Currently we allow only up to 30 bit quantization.
return quantization_bits >= 1 && quantization_bits <= 30;
}
bool AttributeQuantizationTransform::SetParameters(int quantization_bits,
const float *min_values,
int num_components,
float range) {
if (!IsQuantizationValid(quantization_bits)) {
return false;
}
quantization_bits_ = quantization_bits;
min_values_.assign(min_values, min_values + num_components);
range_ = range;
return true;
}
bool AttributeQuantizationTransform::ComputeParameters(
const PointAttribute &attribute, const int quantization_bits) {
if (quantization_bits_ != -1) {
return false; // already initialized.
}
if (!IsQuantizationValid(quantization_bits)) {
return false;
}
quantization_bits_ = quantization_bits;
const int num_components = attribute.num_components();
range_ = 0.f;
min_values_ = std::vector<float>(num_components, 0.f);
const std::unique_ptr<float[]> max_values(new float[num_components]);
const std::unique_ptr<float[]> att_val(new float[num_components]);
// Compute minimum values and max value difference.
attribute.GetValue(AttributeValueIndex(0), att_val.get());
attribute.GetValue(AttributeValueIndex(0), min_values_.data());
attribute.GetValue(AttributeValueIndex(0), max_values.get());
for (AttributeValueIndex i(1); i < static_cast<uint32_t>(attribute.size());
++i) {
attribute.GetValue(i, att_val.get());
for (int c = 0; c < num_components; ++c) {
if (std::isnan(att_val[c])) {
return false;
}
if (min_values_[c] > att_val[c]) {
min_values_[c] = att_val[c];
}
if (max_values[c] < att_val[c]) {
max_values[c] = att_val[c];
}
}
}
for (int c = 0; c < num_components; ++c) {
if (std::isnan(min_values_[c]) || std::isinf(min_values_[c]) ||
std::isnan(max_values[c]) || std::isinf(max_values[c])) {
return false;
}
const float dif = max_values[c] - min_values_[c];
if (dif > range_) {
range_ = dif;
}
}
// In case all values are the same, initialize the range to unit length. This
// will ensure that all values are quantized properly to the same value.
if (range_ == 0.f) {
range_ = 1.f;
}
return true;
}
bool AttributeQuantizationTransform::EncodeParameters(
EncoderBuffer *encoder_buffer) const {
if (is_initialized()) {
encoder_buffer->Encode(min_values_.data(),
sizeof(float) * min_values_.size());
encoder_buffer->Encode(range_);
encoder_buffer->Encode(static_cast<uint8_t>(quantization_bits_));
return true;
}
return false;
}
bool AttributeQuantizationTransform::DecodeParameters(
const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
min_values_.resize(attribute.num_components());
if (!decoder_buffer->Decode(&min_values_[0],
sizeof(float) * min_values_.size())) {
return false;
}
if (!decoder_buffer->Decode(&range_)) {
return false;
}
uint8_t quantization_bits;
if (!decoder_buffer->Decode(&quantization_bits)) {
return false;
}
if (!IsQuantizationValid(quantization_bits)) {
return false;
}
quantization_bits_ = quantization_bits;
return true;
}
void AttributeQuantizationTransform::GeneratePortableAttribute(
const PointAttribute &attribute, int num_points,
PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
const int num_components = attribute.num_components();
// Quantize all values using the order given by point_ids.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
target_attribute->GetAddress(AttributeValueIndex(0)));
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
Quantizer quantizer;
quantizer.Init(range(), max_quantized_value);
int32_t dst_index = 0;
const std::unique_ptr<float[]> att_val(new float[num_components]);
for (PointIndex i(0); i < num_points; ++i) {
const AttributeValueIndex att_val_id = attribute.mapped_index(i);
attribute.GetValue(att_val_id, att_val.get());
for (int c = 0; c < num_components; ++c) {
const float value = (att_val[c] - min_values()[c]);
const int32_t q_val = quantizer.QuantizeFloat(value);
portable_attribute_data[dst_index++] = q_val;
}
}
}
void AttributeQuantizationTransform::GeneratePortableAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
int num_points, PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
const int num_components = attribute.num_components();
// Quantize all values using the order given by point_ids.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
target_attribute->GetAddress(AttributeValueIndex(0)));
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
Quantizer quantizer;
quantizer.Init(range(), max_quantized_value);
int32_t dst_index = 0;
const std::unique_ptr<float[]> att_val(new float[num_components]);
for (uint32_t i = 0; i < point_ids.size(); ++i) {
const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]);
attribute.GetValue(att_val_id, att_val.get());
for (int c = 0; c < num_components; ++c) {
const float value = (att_val[c] - min_values()[c]);
const int32_t q_val = quantizer.QuantizeFloat(value);
portable_attribute_data[dst_index++] = q_val;
}
}
}
} // namespace draco

View file

@ -0,0 +1,102 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_QUANTIZATION_TRANSFORM_H_
#define DRACO_ATTRIBUTES_ATTRIBUTE_QUANTIZATION_TRANSFORM_H_
#include <vector>
#include "draco/attributes/attribute_transform.h"
#include "draco/attributes/point_attribute.h"
#include "draco/core/encoder_buffer.h"
namespace draco {
// Attribute transform for quantized attributes.
class AttributeQuantizationTransform : public AttributeTransform {
public:
AttributeQuantizationTransform() : quantization_bits_(-1), range_(0.f) {}
// Return attribute transform type.
AttributeTransformType Type() const override {
return ATTRIBUTE_QUANTIZATION_TRANSFORM;
}
// Try to init transform from attribute.
bool InitFromAttribute(const PointAttribute &attribute) override;
// Copy parameter values into the provided AttributeTransformData instance.
void CopyToAttributeTransformData(
AttributeTransformData *out_data) const override;
bool TransformAttribute(const PointAttribute &attribute,
const std::vector<PointIndex> &point_ids,
PointAttribute *target_attribute) override;
bool InverseTransformAttribute(const PointAttribute &attribute,
PointAttribute *target_attribute) override;
bool SetParameters(int quantization_bits, const float *min_values,
int num_components, float range);
bool ComputeParameters(const PointAttribute &attribute,
const int quantization_bits);
// Encode relevant parameters into buffer.
bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
bool DecodeParameters(const PointAttribute &attribute,
DecoderBuffer *decoder_buffer) override;
int32_t quantization_bits() const { return quantization_bits_; }
float min_value(int axis) const { return min_values_[axis]; }
const std::vector<float> &min_values() const { return min_values_; }
float range() const { return range_; }
bool is_initialized() const { return quantization_bits_ != -1; }
protected:
// Create portable attribute using 1:1 mapping between points in the input and
// output attribute.
void GeneratePortableAttribute(const PointAttribute &attribute,
int num_points,
PointAttribute *target_attribute) const;
// Create portable attribute using custom mapping between input and output
// points.
void GeneratePortableAttribute(const PointAttribute &attribute,
const std::vector<PointIndex> &point_ids,
int num_points,
PointAttribute *target_attribute) const;
DataType GetTransformedDataType(
const PointAttribute &attribute) const override {
return DT_UINT32;
}
int GetTransformedNumComponents(
const PointAttribute &attribute) const override {
return attribute.num_components();
}
static bool IsQuantizationValid(int quantization_bits);
private:
int32_t quantization_bits_;
// Minimal dequantized value for each component of the attribute.
std::vector<float> min_values_;
// Bounds of the dequantized attribute (max delta over all components).
float range_;
};
} // namespace draco
#endif // DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTE_DEQUANTIZATION_TRANSFORM_H_

View file

@ -0,0 +1,41 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/attributes/attribute_transform.h"
namespace draco {
bool AttributeTransform::TransferToAttribute(PointAttribute *attribute) const {
std::unique_ptr<AttributeTransformData> transform_data(
new AttributeTransformData());
this->CopyToAttributeTransformData(transform_data.get());
attribute->SetAttributeTransformData(std::move(transform_data));
return true;
}
std::unique_ptr<PointAttribute> AttributeTransform::InitTransformedAttribute(
const PointAttribute &src_attribute, int num_entries) {
const int num_components = GetTransformedNumComponents(src_attribute);
const DataType dt = GetTransformedDataType(src_attribute);
GeometryAttribute ga;
ga.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
num_components * DataTypeLength(dt), 0);
std::unique_ptr<PointAttribute> transformed_attribute(new PointAttribute(ga));
transformed_attribute->Reset(num_entries);
transformed_attribute->SetIdentityMapping();
transformed_attribute->set_unique_id(src_attribute.unique_id());
return transformed_attribute;
}
} // namespace draco

View file

@ -0,0 +1,76 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_H_
#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_H_
#include "draco/attributes/attribute_transform_data.h"
#include "draco/attributes/point_attribute.h"
#include "draco/core/decoder_buffer.h"
#include "draco/core/encoder_buffer.h"
namespace draco {
// Virtual base class for various attribute transforms, enforcing common
// interface where possible.
class AttributeTransform {
public:
virtual ~AttributeTransform() = default;
// Return attribute transform type.
virtual AttributeTransformType Type() const = 0;
// Try to init transform from attribute.
virtual bool InitFromAttribute(const PointAttribute &attribute) = 0;
// Copy parameter values into the provided AttributeTransformData instance.
virtual void CopyToAttributeTransformData(
AttributeTransformData *out_data) const = 0;
bool TransferToAttribute(PointAttribute *attribute) const;
// Applies the transform to |attribute| and stores the result in
// |target_attribute|. |point_ids| is an optional vector that can be used to
// remap values during the transform.
virtual bool TransformAttribute(const PointAttribute &attribute,
const std::vector<PointIndex> &point_ids,
PointAttribute *target_attribute) = 0;
// Applies an inverse transform to |attribute| and stores the result in
// |target_attribute|. In this case, |attribute| is an attribute that was
// already transformed (e.g. quantized) and |target_attribute| is the
// attribute before the transformation.
virtual bool InverseTransformAttribute(const PointAttribute &attribute,
PointAttribute *target_attribute) = 0;
// Encodes all data needed by the transformation into the |encoder_buffer|.
virtual bool EncodeParameters(EncoderBuffer *encoder_buffer) const = 0;
// Decodes all data needed to transform |attribute| back to the original
// format.
virtual bool DecodeParameters(const PointAttribute &attribute,
DecoderBuffer *decoder_buffer) = 0;
// Initializes a transformed attribute that can be used as target in the
// TransformAttribute() function call.
virtual std::unique_ptr<PointAttribute> InitTransformedAttribute(
const PointAttribute &src_attribute, int num_entries);
protected:
virtual DataType GetTransformedDataType(
const PointAttribute &attribute) const = 0;
virtual int GetTransformedNumComponents(
const PointAttribute &attribute) const = 0;
};
} // namespace draco
#endif // DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_

View file

@ -0,0 +1,71 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_
#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_
#include <memory>
#include "draco/attributes/attribute_transform_type.h"
#include "draco/core/data_buffer.h"
namespace draco {
// Class for holding parameter values for an attribute transform of a
// PointAttribute. This can be for example quantization data for an attribute
// that holds quantized values. This class provides only a basic storage for
// attribute transform parameters and it should be accessed only through wrapper
// classes for a specific transform (e.g. AttributeQuantizationTransform).
class AttributeTransformData {
public:
AttributeTransformData() : transform_type_(ATTRIBUTE_INVALID_TRANSFORM) {}
AttributeTransformData(const AttributeTransformData &data) = default;
// Returns the type of the attribute transform that is described by the class.
AttributeTransformType transform_type() const { return transform_type_; }
void set_transform_type(AttributeTransformType type) {
transform_type_ = type;
}
// Returns a parameter value on a given |byte_offset|.
template <typename DataTypeT>
DataTypeT GetParameterValue(int byte_offset) const {
DataTypeT out_data;
buffer_.Read(byte_offset, &out_data, sizeof(DataTypeT));
return out_data;
}
// Sets a parameter value on a given |byte_offset|.
template <typename DataTypeT>
void SetParameterValue(int byte_offset, const DataTypeT &in_data) {
if (byte_offset + sizeof(DataTypeT) > buffer_.data_size()) {
buffer_.Resize(byte_offset + sizeof(DataTypeT));
}
buffer_.Write(byte_offset, &in_data, sizeof(DataTypeT));
}
// Sets a parameter value at the end of the |buffer_|.
template <typename DataTypeT>
void AppendParameterValue(const DataTypeT &in_data) {
SetParameterValue(static_cast<int>(buffer_.data_size()), in_data);
}
private:
AttributeTransformType transform_type_;
DataBuffer buffer_;
};
} // namespace draco
#endif // DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_

View file

@ -0,0 +1,30 @@
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_
#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_
namespace draco {
// List of all currently supported attribute transforms.
enum AttributeTransformType {
ATTRIBUTE_INVALID_TRANSFORM = -1,
ATTRIBUTE_NO_TRANSFORM = 0,
ATTRIBUTE_QUANTIZATION_TRANSFORM = 1,
ATTRIBUTE_OCTAHEDRON_TRANSFORM = 2,
};
} // namespace draco
#endif // DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_

Some files were not shown because too many files have changed in this diff Show more