/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. /* SH compression implementation */ namespace NSH { template inline CSHCompressor::SCompressedCoeffListDesc::SCompressedCoeffListDesc() : bytesPerCoeff(0), coeffsPerList(0), preSwizzled(false) {} template inline CSHCompressor::SCompressionProp::SCompressionProp ( const EBumpVisUsage cCoeffUsage, const bool cByteCompression, const bool cDropCoefficient, const bool cPreSwizzle ) : coeffUsage(cCoeffUsage), byteCompression(cByteCompression), dropCoefficient(cDropCoefficient), preSwizzle(cPreSwizzle) {} template CSHCompressor::CSHCompressor(const SCompressionProp& crProp, TIteratorSink iterBegin, const TIteratorSink cIterEnd, const uint32 cBands) : m_CoeffCount(0), m_DoByteCompression(crProp.byteCompression) { assert(cBands > 0); m_ComprCoeffListDesc.bytesPerCoeff = TCoeffType::Components() * (crProp.byteCompression?1:4); m_ComprCoeffListDesc.coeffsPerList = cBands * cBands - (crProp.dropCoefficient?1:0); GenerateCoeffMapping(crProp); if((TCoeffType::Components() == 1) && crProp.preSwizzle)//indirect coefficients need another coeff to drop, convolution formula must be derived if needed m_ComprCoeffListDesc.preSwizzled = true; GenerateCompressionMatrix(crProp, iterBegin, cIterEnd); CompressCoeffs(crProp, iterBegin, cIterEnd); InvertCompressionMatrix(); } template inline const typename CSHCompressor::SCompressedCoeffListDesc CSHCompressor::GetCompressedCoeffDesc() const { return m_ComprCoeffListDesc; } template inline typename CSHCompressor::TComprIter CSHCompressor::begin() const { return m_CompressBuffer.begin(); } template inline const typename CSHCompressor::TComprIter CSHCompressor::end() const { return m_CompressBuffer.end(); } template inline const TFloatPairVec& CSHCompressor::GetDecompressionMatrix() const { return m_CompressionMatrix; } template void CSHCompressor::GenerateCompressionMatrix (const SCompressionProp& crProp, TIteratorSink iterBegin, const TIteratorSink cIterEnd) { m_CompressionMatrix.resize(m_ComprCoeffListDesc.coeffsPerList); if(crProp.byteCompression) { TFloatPairVec minMaxVec(m_CompressionMatrix.size()); const TFloatPairVec::const_iterator cEnd = minMaxVec.end(); for(TFloatPairVec::iterator pairIter = minMaxVec.begin(); pairIter != cEnd; ++pairIter) { //initialize max/min accumulators pairIter->first = std::numeric_limits::max(); pairIter->second = std::numeric_limits::min(); } //now iterate all coefficients and record min/max values for(TIteratorSink iter = iterBegin; iter != cIterEnd; ++iter) { ++m_CoeffCount; const SCoeffList_tpl cCoeffList = m_ComprCoeffListDesc.preSwizzled? PreSwizzleDirect(crProp, *iter) : *iter; for(int c=0; c cCoeffValue) rMinMax.first = cCoeffValue; if(rMinMax.second < cCoeffValue) rMinMax.second = cCoeffValue; } } } //create compression matrix from min/max values for(int c=0; cfirst = 1.f; pairIter->second = 0.f; } } } template void CSHCompressor::CompressCoeffs(const SCompressionProp& crProp, TIteratorSink iterBegin, const TIteratorSink cIterEnd) { //first allocate buffer vec assert((iterBegin == cIterEnd) || m_CoeffCount > 0); if(m_CoeffCount == 0) return; m_CompressBuffer.resize(m_CoeffCount); std::vector::iterator comprBufferIter = m_CompressBuffer.begin(); const size_t cBufElemSize = m_ComprCoeffListDesc.bytesPerCoeff * m_ComprCoeffListDesc.coeffsPerList; //now iterate all coefficients and record min/max values for(TIteratorSink iter = iterBegin; iter != cIterEnd; ++iter) { TComprCoeffList& rComprElem = *comprBufferIter++;//current compressed coefficient destination rComprElem.resize(cBufElemSize); //allocate buffer size size_t bufIndex = 0; //current write index into rComprElem const SCoeffList_tpl cCoeffList = m_ComprCoeffListDesc.preSwizzled? PreSwizzleDirect(crProp, *iter) : *iter; for(int c=0; c -0.1f && coeffValue < 255.1f); //clamp values, it is just about some inaccuracies coeffValue = std::max(coeffValue, (typename TCoeffType::TComponentType)0.0); coeffValue = std::min(coeffValue, (typename TCoeffType::TComponentType)255.0); rComprElem[bufIndex++] = (uint8)((coeffValue - floor(coeffValue) < 0.5f)?floor(coeffValue) : ceil(coeffValue)); } else { *reinterpret_cast(&rComprElem[bufIndex]) = coeffValue; bufIndex += 4; } } } assert(bufIndex == cBufElemSize); } } template void CSHCompressor::InvertCompressionMatrix() { //turn compression matrix into decompression matrix assert(m_CompressionMatrix.size() == m_ComprCoeffListDesc.coeffsPerList); for(int i=0; i 0.00001f); m_CompressionMatrix[i].first = 1.f / m_CompressionMatrix[i].first; m_CompressionMatrix[i].second = -m_CompressionMatrix[i].second; } } template void CSHCompressor::GenerateCoeffMapping(const SCompressionProp& crProp) { m_MappingVec.resize(m_ComprCoeffListDesc.coeffsPerList); std::vector::iterator iter = m_MappingVec.begin(); for(int i=0; i::const_iterator cEnd = m_MappingVec.end(); for(; iter != cEnd; ++iter) //last coeffs stay the same *iter = curDestIndex++; } template const SCoeffList_tpl CSHCompressor::PreSwizzleDirect(const SCompressionProp& crProp, const SCoeffList_tpl& crCoeff) { SCoeffList_tpl coeff = crCoeff; //cache current coefficient list to swizzle assert(crProp.preSwizzle && (TCoeffType::Components() == 1)); //pre-swizzle first 8 coefficients, leave 9. coeff as it is //only valid for direct coeff stream const float cv0 = (crProp.coeffUsage == BUMP_VIS_USAGE_LOOKUP)? SCoeffUsage::cv0 : SCoeffUsage::cv0; const float cv1 = (crProp.coeffUsage == BUMP_VIS_USAGE_LOOKUP)? SCoeffUsage::cv1 : SCoeffUsage::cv1; const float cv2 = (crProp.coeffUsage == BUMP_VIS_USAGE_LOOKUP)? SCoeffUsage::cv2 : SCoeffUsage::cv2; const float cv3 = (crProp.coeffUsage == BUMP_VIS_USAGE_LOOKUP)? SCoeffUsage::cv3 : SCoeffUsage::cv3; const float cv4 = (crProp.coeffUsage == BUMP_VIS_USAGE_LOOKUP)? SCoeffUsage::cv4 : SCoeffUsage::cv4; //first 8 coefficients stay as they are, Y2-2 is put to the end unswizzled if not to drop const TCoeffType cSwizzledCoeffs[8] = {coeff[3] * cv1, coeff[1] * cv1, coeff[2]* cv1, coeff[0] * cv0 - coeff[6] * cv3, coeff[8] * cv4, coeff[5] * cv2, coeff[6]* 3 * cv3, coeff[7] * cv2}; if(crProp.dropCoefficient) { for(int c0=0; c0<4; ++c0) coeff[c0] = cSwizzledCoeffs[c0]; coeff[4] = 0;//unset Y2-2, mapping takes care of the correct mapping for the 9 coeffs with respect to the dropped one for(int c1=4; c1<8; ++c1) coeff[c1+1] = cSwizzledCoeffs[c1]; } else { coeff[8] = coeff[4];//put Y2-2 back to the end for(int c0=0; c0<8; ++c0) coeff[c0] = cSwizzledCoeffs[c0]; coeff[8] *= (crProp.coeffUsage == BUMP_VIS_USAGE_LOOKUP)?SCoeffUsage::cv2 : (SCoeffUsage::cv4 * 2.f); } return coeff; } }