diff options
Diffstat (limited to 'thirdparty/cvtt/ConvectionKernels_EndpointSelector.h')
-rw-r--r-- | thirdparty/cvtt/ConvectionKernels_EndpointSelector.h | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/thirdparty/cvtt/ConvectionKernels_EndpointSelector.h b/thirdparty/cvtt/ConvectionKernels_EndpointSelector.h new file mode 100644 index 0000000000..e09dfd248c --- /dev/null +++ b/thirdparty/cvtt/ConvectionKernels_EndpointSelector.h @@ -0,0 +1,153 @@ +#pragma once +#ifndef __CVTT_ENDPOINTSELECTOR_H__ +#define __CVTT_ENDPOINTSELECTOR_H__ + +#include "ConvectionKernels_ParallelMath.h" +#include "ConvectionKernels_UnfinishedEndpoints.h" +#include "ConvectionKernels_PackedCovarianceMatrix.h" + +namespace cvtt +{ + namespace Internal + { + static const int NumEndpointSelectorPasses = 3; + + template<int TVectorSize, int TIterationCount> + class EndpointSelector + { + public: + typedef ParallelMath::Float MFloat; + + EndpointSelector() + { + for (int ch = 0; ch < TVectorSize; ch++) + { + m_centroid[ch] = ParallelMath::MakeFloatZero(); + m_direction[ch] = ParallelMath::MakeFloatZero(); + } + m_weightTotal = ParallelMath::MakeFloatZero(); + m_minDist = ParallelMath::MakeFloat(FLT_MAX); + m_maxDist = ParallelMath::MakeFloat(-FLT_MAX); + } + + void ContributePass(const MFloat *value, int pass, const MFloat &weight) + { + if (pass == 0) + ContributeCentroid(value, weight); + else if (pass == 1) + ContributeDirection(value, weight); + else if (pass == 2) + ContributeMinMax(value); + } + + void FinishPass(int pass) + { + if (pass == 0) + FinishCentroid(); + else if (pass == 1) + FinishDirection(); + } + + UnfinishedEndpoints<TVectorSize> GetEndpoints(const float channelWeights[TVectorSize]) const + { + MFloat unweightedBase[TVectorSize]; + MFloat unweightedOffset[TVectorSize]; + + for (int ch = 0; ch < TVectorSize; ch++) + { + MFloat min = m_centroid[ch] + m_direction[ch] * m_minDist; + MFloat max = m_centroid[ch] + m_direction[ch] * m_maxDist; + + float safeWeight = channelWeights[ch]; + if (safeWeight == 0.f) + safeWeight = 1.0f; + + unweightedBase[ch] = min / channelWeights[ch]; + unweightedOffset[ch] = (max - min) / channelWeights[ch]; + } + + return UnfinishedEndpoints<TVectorSize>(unweightedBase, unweightedOffset); + } + + private: + void ContributeCentroid(const MFloat *value, const MFloat &weight) + { + for (int ch = 0; ch < TVectorSize; ch++) + m_centroid[ch] = m_centroid[ch] + value[ch] * weight; + m_weightTotal = m_weightTotal + weight; + } + + void FinishCentroid() + { + MFloat denom = m_weightTotal; + ParallelMath::MakeSafeDenominator(denom); + + for (int ch = 0; ch < TVectorSize; ch++) + m_centroid[ch] = m_centroid[ch] / denom; + } + + void ContributeDirection(const MFloat *value, const MFloat &weight) + { + MFloat diff[TVectorSize]; + for (int ch = 0; ch < TVectorSize; ch++) + diff[ch] = value[ch] - m_centroid[ch]; + + m_covarianceMatrix.Add(diff, weight); + } + + void FinishDirection() + { + MFloat approx[TVectorSize]; + for (int ch = 0; ch < TVectorSize; ch++) + approx[ch] = ParallelMath::MakeFloat(1.0f); + + for (int i = 0; i < TIterationCount; i++) + { + MFloat product[TVectorSize]; + m_covarianceMatrix.Product(product, approx); + + MFloat largestComponent = product[0]; + for (int ch = 1; ch < TVectorSize; ch++) + largestComponent = ParallelMath::Max(largestComponent, product[ch]); + + // product = largestComponent*newApprox + ParallelMath::MakeSafeDenominator(largestComponent); + for (int ch = 0; ch < TVectorSize; ch++) + approx[ch] = product[ch] / largestComponent; + } + + // Normalize + MFloat approxLen = ParallelMath::MakeFloatZero(); + for (int ch = 0; ch < TVectorSize; ch++) + approxLen = approxLen + approx[ch] * approx[ch]; + + approxLen = ParallelMath::Sqrt(approxLen); + + ParallelMath::MakeSafeDenominator(approxLen); + + for (int ch = 0; ch < TVectorSize; ch++) + m_direction[ch] = approx[ch] / approxLen; + } + + void ContributeMinMax(const MFloat *value) + { + MFloat dist = ParallelMath::MakeFloatZero(); + for (int ch = 0; ch < TVectorSize; ch++) + dist = dist + m_direction[ch] * (value[ch] - m_centroid[ch]); + + m_minDist = ParallelMath::Min(m_minDist, dist); + m_maxDist = ParallelMath::Max(m_maxDist, dist); + } + + ParallelMath::Float m_centroid[TVectorSize]; + ParallelMath::Float m_direction[TVectorSize]; + PackedCovarianceMatrix<TVectorSize> m_covarianceMatrix; + ParallelMath::Float m_weightTotal; + + ParallelMath::Float m_minDist; + ParallelMath::Float m_maxDist; + }; + } +} + +#endif |