diff --git a/src/nvimage/FloatImage.cpp b/src/nvimage/FloatImage.cpp index 1c51bbb..a5388b4 100644 --- a/src/nvimage/FloatImage.cpp +++ b/src/nvimage/FloatImage.cpp @@ -194,10 +194,16 @@ void FloatImage::scaleBias(uint base_component, uint num, float scale, float bia } /// Clamp the elements of the image. -void FloatImage::clamp(float low, float high) +void FloatImage::clamp(uint base_component, uint num, float low, float high) { - for(uint i = 0; i < m_count; i++) { - m_mem[i] = nv::clamp(m_mem[i], low, high); + const uint size = m_width * m_height; + + for(uint c = 0; c < num; c++) { + float * ptr = this->channel(base_component + c); + + for(uint i = 0; i < size; i++) { + ptr[i] = nv::clamp(ptr[i], low, high); + } } } @@ -945,6 +951,54 @@ void FloatImage::flip() } } + +float FloatImage::alphaTestCoverage(float alphaRef, int alphaChannel) const +{ + const uint w = m_width; + const uint h = m_height; + + float coverage = 0.0f; + + for (uint y = 0; y < h; y++) { + const float * alpha = scanline(y, alphaChannel); + for (uint x = 0; x < w; x++) { + if (alpha[x] > alphaRef) coverage += 1.0f; // @@ gt or lt? + } + } + + return coverage / float(w * h); +} + +void FloatImage::scaleAlphaToCoverage(float desiredCoverage, float alphaRef, int alphaChannel) +{ + float minAlphaRef = 0.0f; + float maxAlphaRef = 1.0f; + float midAlphaRef = 0.5f; + + // Determine desired scale using a binary search. Hardcoded to 8 steps max. + for (int i = 0; i < 8; i++) { + float currentCoverage = alphaTestCoverage(midAlphaRef, alphaChannel); + + if (currentCoverage > desiredCoverage) { + maxAlphaRef = midAlphaRef; + } + else if (currentCoverage < desiredCoverage) { + minAlphaRef = midAlphaRef; + } + else { + break; + } + + midAlphaRef = (minAlphaRef + maxAlphaRef) * 0.5f; + } + + float alphaScale = alphaRef / midAlphaRef; + + // Scale alpha channel. + scaleBias(alphaChannel, 1, alphaScale, 0.0f); +} + + FloatImage* FloatImage::clone() const { FloatImage* copy = new FloatImage(); diff --git a/src/nvimage/FloatImage.h b/src/nvimage/FloatImage.h index 5f6152c..a8388ee 100644 --- a/src/nvimage/FloatImage.h +++ b/src/nvimage/FloatImage.h @@ -59,10 +59,9 @@ public: NVIMAGE_API void packNormals(uint base_component); NVIMAGE_API void expandNormals(uint base_component); - NVIMAGE_API void scaleBias(uint base_component, uint num, float scale, float add); + NVIMAGE_API void scaleBias(uint base_component, uint num, float scale, float bias); - //NVIMAGE_API void clamp(uint base_component, uint num); - NVIMAGE_API void clamp(float low, float high); + NVIMAGE_API void clamp(uint base_component, uint num, float low, float high); NVIMAGE_API void toLinear(uint base_component, uint num, float gamma = 2.2f); NVIMAGE_API void toGamma(uint base_component, uint num, float gamma = 2.2f); @@ -87,6 +86,9 @@ public: NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, uint a, WrapMode wm, float * output) const; NVIMAGE_API void flip(); + + NVIMAGE_API float alphaTestCoverage(float alphaRef, int alphaChannel) const; + NVIMAGE_API void scaleAlphaToCoverage(float coverage, float alphaRef, int alphaChannel); //@} uint width() const { return m_width; } diff --git a/src/nvtt/OutputOptions.cpp b/src/nvtt/OutputOptions.cpp index 6bd09ec..05c18ef 100644 --- a/src/nvtt/OutputOptions.cpp +++ b/src/nvtt/OutputOptions.cpp @@ -112,7 +112,7 @@ void OutputOptions::Private::beginImage(int size, int width, int height, int dep bool OutputOptions::Private::writeData(const void * data, int size) const { - if (outputHandler != NULL) return outputHandler->writeData(data, size); + return outputHandler == NULL || outputHandler->writeData(data, size); } void OutputOptions::Private::error(Error e) const diff --git a/src/nvtt/TexImage.cpp b/src/nvtt/TexImage.cpp index 7d07546..2499301 100644 --- a/src/nvtt/TexImage.cpp +++ b/src/nvtt/TexImage.cpp @@ -244,6 +244,29 @@ int TexImage::countMipmaps() const return ::countMipmaps(width(), height(), depth()); } +float TexImage::alphaTestCoverage(float alphaRef/*= 0.5*/) const +{ + int imageCount = 0.0f; + float coverage = 0.0f; + + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + + if (img == NULL) continue; + + imageCount++; + coverage += img->alphaTestCoverage(alphaRef, 3); + } + + if (imageCount > 0) { + return coverage / imageCount; + } + else { + return 0.0f; + } +} + bool TexImage::load(const char * fileName) { @@ -937,6 +960,21 @@ void TexImage::fill(float red, float green, float blue, float alpha) } } + +void TexImage::scaleAlphaToCoverage(float coverage, float alphaRef/*= 0.5f*/) +{ + detach(); + + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; + + img->scaleAlphaToCoverage(coverage, alphaRef, 3); + } +} + + // Set normal map options. void TexImage::toNormalMap(float sm, float medium, float big, float large) { diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index 499cd55..911858f 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -412,6 +412,7 @@ namespace nvtt NVTT_API AlphaMode alphaMode() const; NVTT_API bool isNormalMap() const; NVTT_API int countMipmaps() const; + NVTT_API float alphaTestCoverage(float alphaRef = 0.5) const; // Texture data. NVTT_API bool load(const char * fileName); @@ -424,7 +425,7 @@ namespace nvtt NVTT_API void resize(int w, int h, ResizeFilter filter); NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter); NVTT_API bool buildNextMipmap(MipmapFilter filter); - + // Color transforms. NVTT_API void toLinear(float gamma); NVTT_API void toGamma(float gamma); @@ -438,6 +439,7 @@ namespace nvtt NVTT_API void toGreyScale(float redScale, float greenScale, float blueScale, float alphaScale); NVTT_API void setBorder(float r, float g, float b, float a); NVTT_API void fill(float r, float g, float b, float a); + NVTT_API void scaleAlphaToCoverage(float coverage, float alphaRef = 0.5f); // Set normal map options. NVTT_API void toNormalMap(float sm, float medium, float big, float large); diff --git a/src/nvtt/tools/compress.cpp b/src/nvtt/tools/compress.cpp index d57a285..9b5b8b3 100644 --- a/src/nvtt/tools/compress.cpp +++ b/src/nvtt/tools/compress.cpp @@ -386,7 +386,7 @@ int main(int argc, char *argv[]) } else { - if (nv::strCaseCmp(input.extension(), ".exr") == 0) + if (nv::strCaseCmp(input.extension(), ".exr") == 0 || nv::strCaseCmp(input.extension(), ".hdr") == 0) { loadAsFloat = true; }