From fb7d80b385e6e792009b5703adb1bb86fc21b321 Mon Sep 17 00:00:00 2001 From: Pavel Krajcevski Date: Mon, 10 Mar 2014 14:59:45 -0400 Subject: [PATCH] Break out the integer sequence encoding into its own module. --- ASTCEncoder/CMakeLists.txt | 2 + ASTCEncoder/src/Decompressor.cpp | 365 +++++++++++++++------------- ASTCEncoder/src/IntegerEncoding.cpp | 268 ++++++++++++++++++++ ASTCEncoder/src/IntegerEncoding.h | 143 +++++++++++ 4 files changed, 613 insertions(+), 165 deletions(-) create mode 100644 ASTCEncoder/src/IntegerEncoding.cpp create mode 100644 ASTCEncoder/src/IntegerEncoding.h diff --git a/ASTCEncoder/CMakeLists.txt b/ASTCEncoder/CMakeLists.txt index 43a9f70..e25e836 100644 --- a/ASTCEncoder/CMakeLists.txt +++ b/ASTCEncoder/CMakeLists.txt @@ -57,10 +57,12 @@ INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/Base/include) SET( HEADERS include/ASTCCompressor.h + src/IntegerEncoding.h ) SET( SOURCES src/Decompressor.cpp + src/IntegerEncoding.cpp ) #CONFIGURE_FILE( diff --git a/ASTCEncoder/src/Decompressor.cpp b/ASTCEncoder/src/Decompressor.cpp index 8392d26..54287f9 100644 --- a/ASTCEncoder/src/Decompressor.cpp +++ b/ASTCEncoder/src/Decompressor.cpp @@ -58,43 +58,16 @@ #include #include "Utils.h" +#include "IntegerEncoding.h" #include "TexCompTypes.h" -#include "Bits.h" -using FasTC::Bits; - #include "BitStream.h" using FasTC::BitStreamReadOnly; namespace ASTCC { - // According to table C.2.7 - void GetBitEncoding(uint8 &nQuints, uint8 &nTrits, uint8 &nBits, - const uint32 maxWeight) { - nQuints = nTrits = nBits = 0; - switch(maxWeight) { - case 1: nBits = 1; return; - case 2: nTrits = 1; return; - case 3: nBits = 2; return; - case 4: nQuints = 1; return; - case 5: nTrits = 1; nBits = 1; return; - case 7: nBits = 3; return; - case 9: nQuints = 1; nBits = 1; return; - case 11: nTrits = 1; nBits = 2; return; - case 15: nBits = 4; return; - case 19: nQuints = 1; nBits = 2; return; - case 23: nTrits = 1; nBits = 3; return; - case 31: nBits = 5; return; - - default: - assert(!"Invalid maximum weight"); - return; - } - } - - class TexelWeightParams { - public: + struct TexelWeightParams { uint32 m_Width; uint32 m_Height; bool m_bDualPlane; @@ -113,19 +86,7 @@ namespace ASTCC { nIdxs *= 2; } - // How are they encoded? - uint8 nQuints, nTrits, nBits; - GetBitEncoding(nQuints, nTrits, nBits, m_MaxWeight); - - // nQuints and nTrits are mutually exclusive values of one. - assert(nQuints != 1 || nTrits == 0); - assert(nTrits != 1 || nQuints == 0); - - // each index has at least as many bits per index as described. - uint32 totalBits = nBits * nIdxs; - totalBits += (nIdxs * 8 * nTrits + 4) / 5; - totalBits += (nIdxs * 7 * nQuints + 2) / 3; - return totalBits; + return IntegerEncodedValue::CreateEncoding(m_MaxWeight).GetBitLength(nIdxs); } }; @@ -326,140 +287,192 @@ namespace ASTCC { } } - void DecodeTritBlock(BitStreamReadOnly &bits, - std::vector &result, - uint32 nBitsPerValue) { - // Implement the algorithm in section C.2.12 - uint32 m[5]; - uint32 t[5]; - uint32 T; + void DecodeColorValues(uint32 *out, uint8 *data, uint32 *modes, const uint32 nBitsForColorData) { + // First figure out how many color values we have + uint32 nValues = 0; + for(uint32 i = 0; i < 4; i++) { + nValues += ((modes[i]>>2) + 1) << 1; + } - // Read the trit encoded block according to - // table C.2.14 - m[0] = bits.ReadBits(nBitsPerValue); - T = bits.ReadBits(2); - m[1] = bits.ReadBits(nBitsPerValue); - T |= bits.ReadBits(2) << 2; - m[2] = bits.ReadBits(nBitsPerValue); - T |= bits.ReadBit() << 4; - m[3] = bits.ReadBits(nBitsPerValue); - T |= bits.ReadBits(2) << 5; - m[4] = bits.ReadBits(nBitsPerValue); - T |= bits.ReadBit() << 7; + // Then based on the number of values and the remaining number of bits, + // figure out the max value for each of them... + uint32 range = 255; + while(range > 0) { + IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(range); + uint32 bitLength = val.GetBitLength(nValues); + if(bitLength < nBitsForColorData) { + // Find the smallest possible range that matches the given encoding + while(--range > 0) { + IntegerEncodedValue newval = IntegerEncodedValue::CreateEncoding(range); + if(!newval.MatchesEncoding(val)) { + break; + } + } - uint32 C = 0; - - Bits Tb(T); - if(Tb(2, 4) == 7) { - C = (Tb(5, 7) << 2) | Tb(0, 1); - t[4] = t[3] = 2; - } else { - C = Tb(0, 4); - if(Tb(5, 6) == 3) { - t[4] = 2; - t[3] = Tb[7]; - } else { - t[4] = Tb[7]; - t[3] = Tb(5, 6); + // Return to last matching range. + range++; + break; } } - Bits Cb(C); - if(Cb(0, 1) == 3) { - t[2] = 2; - t[1] = Cb[4]; - t[0] = (Cb[3] << 1) | (Cb[2] & ~Cb[3]); - } else if(Cb(2, 3) == 3) { - t[2] = 2; - t[1] = 2; - t[0] = Cb(0, 1); - } else { - t[2] = Cb[4]; - t[1] = Cb(2, 3); - t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]); - } + // We now have enough to decode our integer sequence. + std::vector decodedColorValues; + FasTC::BitStreamReadOnly colorStream (data); + IntegerEncodedValue:: + DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues); + assert(nValues == decodedColorValues.size()); - for(uint32 i = 0; i < 5; i++) { - assert(t[i] < 3); - uint32 val = (t[i] << nBitsPerValue) + m[i]; - result.push_back(val); - } - } + // Once we have the decoded values, we need to dequantize them to the 0-255 range + // This procedure is outlined in ASTC spec C.2.13 + uint32 outIdx = 0; + std::vector::const_iterator itr; + for(itr = decodedColorValues.begin(); itr != decodedColorValues.end(); itr++) { + const IntegerEncodedValue &val = *itr; + uint32 bitlen = val.BaseBitLength(); + uint32 bitval = val.GetBitValue(); - void DecodeQuintBlock(BitStreamReadOnly &bits, - std::vector &result, - uint32 nBitsPerValue) { - // Implement the algorithm in section C.2.12 - uint32 m[3]; - uint32 q[3]; - uint32 Q; + assert(bitlen >= 1); - // Read the trit encoded block according to - // table C.2.15 - m[0] = bits.ReadBits(nBitsPerValue); - Q = bits.ReadBits(3); - m[1] = bits.ReadBits(nBitsPerValue); - Q |= bits.ReadBits(2) << 3; - m[2] = bits.ReadBits(nBitsPerValue); - Q |= bits.ReadBits(2) << 5; - - Bits Qb(Q); - if(Qb(1, 2) == 3 && Qb(5, 6) == 0) { - q[0] = q[1] = 4; - q[2] = (Qb[0] << 2) | ((Qb[4] & ~Qb[0]) << 1) | (Qb[3] & ~Qb[0]); - } else { - uint32 C = 0; - if(Qb(1, 2) == 3) { - q[2] = 4; - C = (Qb(3, 4) << 3) | ((~Qb(5, 6) & 3) << 1) | Qb[0]; - } else { - q[2] = Qb(5, 6); - C = Qb(0, 4); + uint32 A = 0, B = 0, C = 0, D = 0; + // A is just the lsb replicated 8 times. + for(uint32 i = 0; i < 9; i++) { + A |= bitval & 1; + A <<= 1; } - Bits Cb(C); - if(Cb(0, 2) == 5) { - q[1] = 4; - q[0] = Cb(3, 4); - } else { - q[1] = Cb(3, 4); - q[0] = Cb(0, 2); + switch(val.GetEncoding()) { + // Replicate bits + case eIntegerEncoding_JustBits: { + uint32 result = bitval; + uint32 resultLen = bitlen; + while(resultLen < 8) { + result <<= bitlen; + result |= bitval & ((1 << std::min(8 - bitlen, bitlen)) - 1); + resultLen += bitlen; + } + out[outIdx++] = result; + } + break; + + // Use algorithm in C.2.13 + case eIntegerEncoding_Trit: { + + D = val.GetTritValue(); + + switch(bitlen) { + case 1: { + C = 204; + } + break; + + case 2: { + C = 93; + // B = b000b0bb0 + uint32 b = (bitval >> 1) & 1; + B = (b << 8) | (b << 4) | (b << 2) | (b << 1); + } + break; + + case 3: { + C = 44; + // B = cb000cbcb + uint32 cb = (bitval >> 1) & 3; + B = (cb << 7) | (cb << 2) | cb; + } + break; + + case 4: { + C = 22; + // B = dcb000dcb + uint32 dcb = (bitval >> 1) & 7; + B = (dcb << 6) | dcb; + } + break; + + case 5: { + C = 11; + // B = edcb000ed + uint32 edcb = (bitval >> 1) & 0xF; + B = (edcb << 5) | (edcb >> 2); + } + break; + + case 6: { + C = 5; + // B = fedcb000f + uint32 fedcb = (bitval >> 1) & 0x1F; + B = (fedcb << 4) | (fedcb >> 4); + } + break; + + default: + assert(!"Unsupported trit encoding for color values!"); + break; + } // switch(bitlen) + } // case eIntegerEncoding_Trit + break; + + case eIntegerEncoding_Quint: { + + D = val.GetQuintValue(); + + switch(bitlen) { + case 1: { + C = 113; + } + break; + + case 2: { + C = 54; + // B = b0000bb00 + uint32 b = (bitval >> 1) & 1; + B = (b << 8) | (b << 3) | (b << 2); + } + break; + + case 3: { + C = 26; + // B = cb0000cbc + uint32 cb = (bitval >> 1) & 3; + B = (cb << 7) | (cb << 1) | (cb >> 1); + } + break; + + case 4: { + C = 13; + // B = dcb000dcb + uint32 dcb = (bitval >> 1) & 7; + B = (dcb << 6) | dcb; + } + break; + + case 5: { + C = 6; + // B = edcb0000e + uint32 edcb = (bitval >> 1) & 0xF; + B = (edcb << 5) | (edcb >> 3); + } + break; + + default: + assert(!"Unsupported quint encoding for color values!"); + break; + } // switch(bitlen) + } // case eIntegerEncoding_Quint + break; + } // switch(val.GetEncoding()) + + if(val.GetEncoding() != eIntegerEncoding_JustBits) { + uint32 T = D * C + B; + T ^= A; + T = (A & 0x80) | (T >> 2); + out[outIdx++] = T; } } - for(uint32 i = 0; i < 3; i++) { - assert(q[i] < 5); - uint32 val = (q[i] << nBitsPerValue) + m[i]; - result.push_back(val); - } - } - - void DecodeIntegerSequence(BitStreamReadOnly &bits, - std::vector &result, - uint32 maxRange, - uint32 nValues) { - // Clean our result vector - result.clear(); - result.reserve(nValues); - - // Determine encoding parameters - uint8 nQuints, nTrits, nBits; - GetBitEncoding(nQuints, nTrits, nBits, maxRange); - - // Start decoding - uint32 nValsDecoded = 0; - while(nValsDecoded < nValues) { - if(nQuints) { - DecodeQuintBlock(bits, result, nBits); - nValsDecoded += 3; - } else if(nTrits) { - DecodeTritBlock(bits, result, nBits); - nValsDecoded += 5; - } else { - // Decode bit by bit - result.push_back(bits.ReadBits(nBits)); - nValsDecoded++; - } + // Make sure that each of our values is in the proper range... + for(uint32 i = 0; i < nValues; i++) { + assert(out[i] <= 255); } } @@ -546,6 +559,7 @@ namespace ASTCC { remainingBits -= planeSelectorBits; // Read color data... + uint32 colorDataBits = remainingBits; while(remainingBits > 0) { uint32 nb = std::min(remainingBits, 8); uint32 b = strm.ReadBits(nb); @@ -588,16 +602,37 @@ namespace ASTCC { } } -#ifndef NDEBUG // Make sure everything up till here is sane. for(uint32 i = 0; i < nPartitions; i++) { assert(colorEndpointMode[i] < 16); } assert(strm.GetBitsRead() + weightParams.GetPackedBitSize() == 128); -#endif // Read the texel weight data.. + uint8 texelWeightData[16]; + memset(texelWeightData, 0, sizeof(texelWeightData)); + FasTC::BitStream texelWeightStream (texelWeightData, 16*8, 0); + int32 texelWeightBits = weightParams.GetPackedBitSize(); + while(texelWeightBits > 0) { + uint32 nb = std::min(texelWeightBits, 8); + uint32 b = strm.ReadBits(nb); + texelWeightStream.WriteBits(b, nb); + texelWeightBits -= 8; + } + + assert(strm.GetBitsRead() == 128); + + // Decode both color data and texel weight data + uint32 colorValues[32]; // Four values, two endpoints, four maximum paritions + DecodeColorValues(colorValues, colorEndpointData, colorEndpointMode, colorDataBits); + + std::vector texelWeightValues; + FasTC::BitStreamReadOnly weightStream (texelWeightData); + IntegerEncodedValue:: + DecodeIntegerSequence(texelWeightValues, weightStream, + weightParams.m_MaxWeight, + weightParams.m_Width * weightParams.m_Height); } void Decompress(const FasTC::DecompressionJob &dcj, EASTCBlockSize blockSize) { diff --git a/ASTCEncoder/src/IntegerEncoding.cpp b/ASTCEncoder/src/IntegerEncoding.cpp new file mode 100644 index 0000000..48026d1 --- /dev/null +++ b/ASTCEncoder/src/IntegerEncoding.cpp @@ -0,0 +1,268 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#include "ASTCCompressor.h" + +#include +#include +#include +#include + +#include "Utils.h" +#include "IntegerEncoding.h" + +#include "Bits.h" +using FasTC::Bits; + +#include "BitStream.h" +using FasTC::BitStreamReadOnly; + +namespace ASTCC { + + // Returns the number of bits required to encode nVals values. + uint32 IntegerEncodedValue::GetBitLength(uint32 nVals) { + uint32 totalBits = m_NumBits * nVals; + if(m_Encoding == eIntegerEncoding_Trit) { + totalBits += (nVals * 8 + 4) / 5; + } else if(m_Encoding == eIntegerEncoding_Quint) { + totalBits += (nVals * 7 + 2) / 3; + } + return totalBits; + } + + IntegerEncodedValue IntegerEncodedValue::CreateEncoding(uint32 maxVal) { + while(maxVal > 0) { + uint32 check = maxVal + 1; + + // Is maxVal a power of two? + if(!(check & (check - 1))) { + return IntegerEncodedValue(eIntegerEncoding_JustBits, Popcnt(maxVal)); + } + + // Is maxVal of the type 3*2^n - 1? + if((check % 3 == 0) && !((check/3) & ((check/3) - 1))) { + return IntegerEncodedValue(eIntegerEncoding_Trit, Popcnt(check/3 - 1)); + } + + // Is maxVal of the type 5*2^n - 1? + if((check % 5 == 0) && !((check/5) & ((check/5) - 1))) { + return IntegerEncodedValue(eIntegerEncoding_Quint, Popcnt(check/5 - 1)); + } + + // Apparently it can't be represented with a bounded integer sequence... + // just iterate. + maxVal--; + } + return IntegerEncodedValue(eIntegerEncoding_JustBits, 0); + } + + uint32 IntegerEncodedValue::GetValue() { + switch(m_Encoding) { + case eIntegerEncoding_JustBits: + return m_BitValue; + + case eIntegerEncoding_Trit: + return (m_TritValue << m_NumBits) + m_BitValue; + + case eIntegerEncoding_Quint: + return (m_QuintValue << m_NumBits) + m_BitValue; + } + + return 0; + } + + void IntegerEncodedValue::DecodeTritBlock( + BitStreamReadOnly &bits, + std::vector &result, + uint32 nBitsPerValue + ) { + // Implement the algorithm in section C.2.12 + uint32 m[5]; + uint32 t[5]; + uint32 T; + + // Read the trit encoded block according to + // table C.2.14 + m[0] = bits.ReadBits(nBitsPerValue); + T = bits.ReadBits(2); + m[1] = bits.ReadBits(nBitsPerValue); + T |= bits.ReadBits(2) << 2; + m[2] = bits.ReadBits(nBitsPerValue); + T |= bits.ReadBit() << 4; + m[3] = bits.ReadBits(nBitsPerValue); + T |= bits.ReadBits(2) << 5; + m[4] = bits.ReadBits(nBitsPerValue); + T |= bits.ReadBit() << 7; + + uint32 C = 0; + + Bits Tb(T); + if(Tb(2, 4) == 7) { + C = (Tb(5, 7) << 2) | Tb(0, 1); + t[4] = t[3] = 2; + } else { + C = Tb(0, 4); + if(Tb(5, 6) == 3) { + t[4] = 2; + t[3] = Tb[7]; + } else { + t[4] = Tb[7]; + t[3] = Tb(5, 6); + } + } + + Bits Cb(C); + if(Cb(0, 1) == 3) { + t[2] = 2; + t[1] = Cb[4]; + t[0] = (Cb[3] << 1) | (Cb[2] & ~Cb[3]); + } else if(Cb(2, 3) == 3) { + t[2] = 2; + t[1] = 2; + t[0] = Cb(0, 1); + } else { + t[2] = Cb[4]; + t[1] = Cb(2, 3); + t[0] = (Cb[1] << 1) | (Cb[0] & ~Cb[1]); + } + + for(uint32 i = 0; i < 5; i++) { + IntegerEncodedValue val(eIntegerEncoding_Trit, nBitsPerValue); + val.SetBitValue(m[i]); + val.SetTritValue(t[i]); + result.push_back(val); + } + } + + void IntegerEncodedValue::DecodeQuintBlock( + BitStreamReadOnly &bits, + std::vector &result, + uint32 nBitsPerValue + ) { + // Implement the algorithm in section C.2.12 + uint32 m[3]; + uint32 q[3]; + uint32 Q; + + // Read the trit encoded block according to + // table C.2.15 + m[0] = bits.ReadBits(nBitsPerValue); + Q = bits.ReadBits(3); + m[1] = bits.ReadBits(nBitsPerValue); + Q |= bits.ReadBits(2) << 3; + m[2] = bits.ReadBits(nBitsPerValue); + Q |= bits.ReadBits(2) << 5; + + Bits Qb(Q); + if(Qb(1, 2) == 3 && Qb(5, 6) == 0) { + q[0] = q[1] = 4; + q[2] = (Qb[0] << 2) | ((Qb[4] & ~Qb[0]) << 1) | (Qb[3] & ~Qb[0]); + } else { + uint32 C = 0; + if(Qb(1, 2) == 3) { + q[2] = 4; + C = (Qb(3, 4) << 3) | ((~Qb(5, 6) & 3) << 1) | Qb[0]; + } else { + q[2] = Qb(5, 6); + C = Qb(0, 4); + } + + Bits Cb(C); + if(Cb(0, 2) == 5) { + q[1] = 4; + q[0] = Cb(3, 4); + } else { + q[1] = Cb(3, 4); + q[0] = Cb(0, 2); + } + } + + for(uint32 i = 0; i < 3; i++) { + IntegerEncodedValue val(eIntegerEncoding_Quint, nBitsPerValue); + val.m_BitValue = m[i]; + val.m_QuintValue = q[i]; + result.push_back(val); + } + } + + void IntegerEncodedValue::DecodeIntegerSequence( + std::vector &result, + BitStreamReadOnly &bits, + uint32 maxRange, + uint32 nValues + ) { + // Determine encoding parameters + IntegerEncodedValue val = IntegerEncodedValue::CreateEncoding(maxRange); + + // Start decoding + uint32 nValsDecoded = 0; + while(nValsDecoded < nValues) { + switch(val.GetEncoding()) { + case eIntegerEncoding_Quint: + DecodeQuintBlock(bits, result, val.BaseBitLength()); + nValsDecoded += 3; + break; + + case eIntegerEncoding_Trit: + DecodeTritBlock(bits, result, val.BaseBitLength()); + nValsDecoded += 5; + break; + + case eIntegerEncoding_JustBits: + val.SetBitValue(bits.ReadBits(val.BaseBitLength())); + result.push_back(val); + nValsDecoded++; + break; + } + } + } +} // namespace ASTCC diff --git a/ASTCEncoder/src/IntegerEncoding.h b/ASTCEncoder/src/IntegerEncoding.h new file mode 100644 index 0000000..6a7e2d1 --- /dev/null +++ b/ASTCEncoder/src/IntegerEncoding.h @@ -0,0 +1,143 @@ +/* FasTC + * Copyright (c) 2014 University of North Carolina at Chapel Hill. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for educational, research, and non-profit purposes, without + * fee, and without a written agreement is hereby granted, provided that the + * above copyright notice, this paragraph, and the following four paragraphs + * appear in all copies. + * + * Permission to incorporate this software into commercial products may be + * obtained by contacting the authors or the Office of Technology Development + * at the University of North Carolina at Chapel Hill . + * + * This software program and documentation are copyrighted by the University of + * North Carolina at Chapel Hill. The software program and documentation are + * supplied "as is," without any accompanying services from the University of + * North Carolina at Chapel Hill or the authors. The University of North + * Carolina at Chapel Hill and the authors do not warrant that the operation of + * the program will be uninterrupted or error-free. The end-user understands + * that the program was developed for research purposes and is advised not to + * rely exclusively on the program for any reason. + * + * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE + * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF + * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA + * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY + * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY + * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON + * AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND + * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. + * + * Please send all BUG REPORTS to . + * + * The authors may be contacted via: + * + * Pavel Krajcevski + * Dept of Computer Science + * 201 S Columbia St + * Frederick P. Brooks, Jr. Computer Science Bldg + * Chapel Hill, NC 27599-3175 + * USA + * + * + */ + +#ifndef _ASTCENCODER_SRC_INTEGERENCODING_H_ +#define _ASTCENCODER_SRC_INTEGERENCODING_H_ + +#include "TexCompTypes.h" + +// Forward declares +namespace FasTC { + class BitStreamReadOnly; +} + +namespace ASTCC { + + enum EIntegerEncoding { + eIntegerEncoding_JustBits, + eIntegerEncoding_Quint, + eIntegerEncoding_Trit + }; + + class IntegerEncodedValue { + private: + const EIntegerEncoding m_Encoding; + const uint32 m_NumBits; + uint32 m_BitValue; + union { + uint32 m_QuintValue; + uint32 m_TritValue; + }; + + public: + + // Jank, but we're not doing any heavy lifting in this class, so it's + // probably OK. It allows us to use these in std::vectors... + IntegerEncodedValue &operator=(const IntegerEncodedValue &other) { + new (this) IntegerEncodedValue(other); + return *this; + } + + IntegerEncodedValue(EIntegerEncoding encoding, uint32 numBits) + : m_Encoding(encoding), m_NumBits(numBits) { } + + EIntegerEncoding GetEncoding() const { return m_Encoding; } + uint32 BaseBitLength() const { return m_NumBits; } + + uint32 GetBitValue() const { return m_BitValue; } + void SetBitValue(uint32 val) { m_BitValue = val; } + + uint32 GetTritValue() const { return m_TritValue; } + void SetTritValue(uint32 val) { m_TritValue = val; } + + uint32 GetQuintValue() const { return m_QuintValue; } + void SetQuintValue(uint32 val) { m_QuintValue = val; } + + bool MatchesEncoding(const IntegerEncodedValue &other) { + return m_Encoding == other.m_Encoding && m_NumBits == other.m_NumBits; + } + + // Returns the number of bits required to encode nVals values. + uint32 GetBitLength(uint32 nVals); + + // Returns the value of this integer encoding. + uint32 GetValue(); + + // Returns a new instance of this struct that corresponds to the + // can take no more than maxval values + static IntegerEncodedValue CreateEncoding(uint32 maxVal); + + // Fills result with the values that are encoded in the given + // bitstream. We must know beforehand what the maximum possible + // value is, and how many values we're decoding. + static void DecodeIntegerSequence( + std::vector &result, + FasTC::BitStreamReadOnly &bits, + uint32 maxRange, + uint32 nValues + ); + + private: + static void DecodeTritBlock( + FasTC::BitStreamReadOnly &bits, + std::vector &result, + uint32 nBitsPerValue + ); + static void DecodeQuintBlock( + FasTC::BitStreamReadOnly &bits, + std::vector &result, + uint32 nBitsPerValue + ); + }; +}; // namespace ASTCC + +#endif // _ASTCENCODER_SRC_INTEGERENCODING_H_