From a28ebb4ccf1a722c30cfcba7271168c0eb245335 Mon Sep 17 00:00:00 2001 From: castano Date: Sat, 7 Mar 2009 07:14:00 +0000 Subject: [PATCH] Some more progress in the imperative API. --- src/nvtt/Context.cpp | 5 + src/nvtt/Texture.cpp | 293 +++++++++++++++++++++++++++++-- src/nvtt/Texture.h | 21 +++ src/nvtt/nvtt.h | 28 ++- src/nvtt/tests/imperativeapi.cpp | 4 +- 5 files changed, 331 insertions(+), 20 deletions(-) diff --git a/src/nvtt/Context.cpp b/src/nvtt/Context.cpp index cda7bf7..d4b4d3f 100644 --- a/src/nvtt/Context.cpp +++ b/src/nvtt/Context.cpp @@ -286,6 +286,11 @@ int Compressor::estimateSize(const InputOptions & inputOptions, const Compressio return m.estimateSize(inputOptions.m, compressionOptions.m); } +/// Estimate the size of compressing the input with the given options. +Texture Compressor::createTexture() +{ + return *new Texture(); +} diff --git a/src/nvtt/Texture.cpp b/src/nvtt/Texture.cpp index 1bfb2a3..ed604db 100644 --- a/src/nvtt/Texture.cpp +++ b/src/nvtt/Texture.cpp @@ -23,20 +23,52 @@ #include "Texture.h" +#include +#include + +#include + +using namespace nv; using namespace nvtt; +namespace +{ + // 1 -> 1, 2 -> 2, 3 -> 2, 4 -> 4, 5 -> 4, ... + static uint previousPowerOfTwo(const uint v) + { + return nextPowerOfTwo(v + 1) / 2; + } -Texture::Texture() : m(NULL) + static uint nearestPowerOfTwo(const uint v) + { + const uint np2 = nextPowerOfTwo(v); + const uint pp2 = previousPowerOfTwo(v); + + if (np2 - v <= v - pp2) + { + return np2; + } + else + { + return pp2; + } + } +} + + +Texture::Texture() : m(new Texture::Private()) { } Texture::Texture(const Texture & tex) : m(tex.m) { + m->addRef(); } Texture::~Texture() { - delete m; + m->release(); + m = NULL; } void Texture::operator=(const Texture & tex) @@ -46,15 +78,56 @@ void Texture::operator=(const Texture & tex) m->release(); } -bool Texture::load(const char * fileName) +void Texture::detach() { - // @@ Not implemented. - return false; + if (m->refCount() > 1) + { + m = new Texture::Private(*m); + m->addRef(); + nvDebugCheck(m->refCount() == 1); + } } void Texture::setType(TextureType type) { - m->type = type; + if (m->type != type) + { + detach(); + m->type = type; + } +} + +void Texture::setWrapMode(WrapMode wrapMode) +{ + if (m->wrapMode != wrapMode) + { + detach(); + m->wrapMode = wrapMode; + } +} + +void Texture::setAlphaMode(AlphaMode alphaMode) +{ + if (m->alphaMode != alphaMode) + { + detach(); + m->alphaMode = alphaMode; + } +} + +void Texture::setNormalMap(bool isNormalMap) +{ + if (m->isNormalMap != isNormalMap) + { + detach(); + m->isNormalMap = isNormalMap; + } +} + +bool Texture::load(const char * fileName) +{ + // @@ Not implemented. + return false; } void Texture::setTexture2D(InputFormat format, int w, int h, int idx, void * data) @@ -62,20 +135,182 @@ void Texture::setTexture2D(InputFormat format, int w, int h, int idx, void * dat // @@ Not implemented. } + void Texture::resize(int w, int h, ResizeFilter filter) { - // if cubemap, make sure w==h.s - // @@ Not implemented. + if (m->imageArray.count() > 0) + { + if (w == m->imageArray[0].width() && h == m->imageArray[0].height()) return; + } + + // @TODO: if cubemap, make sure w == h. + + detach(); + + foreach(i, m->imageArray) + { + FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode; + + if (m->alphaMode == AlphaMode_Transparency) + { + if (filter == ResizeFilter_Box) + { + BoxFilter filter; + m->imageArray[i].resize(filter, w, h, wrapMode, 3); + } + else if (filter == ResizeFilter_Triangle) + { + TriangleFilter filter; + m->imageArray[i].resize(filter, w, h, wrapMode, 3); + } + else if (filter == ResizeFilter_Kaiser) + { + //KaiserFilter filter(inputOptions.kaiserWidth); + //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); + KaiserFilter filter(3); + m->imageArray[i].resize(filter, w, h, wrapMode, 3); + } + else //if (filter == ResizeFilter_Mitchell) + { + nvDebugCheck(filter == ResizeFilter_Mitchell); + MitchellFilter filter; + m->imageArray[i].resize(filter, w, h, wrapMode, 3); + } + } + else + { + if (filter == ResizeFilter_Box) + { + BoxFilter filter; + m->imageArray[i].resize(filter, w, h, wrapMode); + } + else if (filter == ResizeFilter_Triangle) + { + TriangleFilter filter; + m->imageArray[i].resize(filter, w, h, wrapMode); + } + else if (filter == ResizeFilter_Kaiser) + { + //KaiserFilter filter(inputOptions.kaiserWidth); + //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); + KaiserFilter filter(3); + m->imageArray[i].resize(filter, w, h, wrapMode); + } + else //if (filter == ResizeFilter_Mitchell) + { + nvDebugCheck(filter == ResizeFilter_Mitchell); + MitchellFilter filter; + m->imageArray[i].resize(filter, w, h, wrapMode); + } + } + } +} + +void Texture::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter) +{ + if (m->imageArray.count() > 0) + { + int w = m->imageArray[0].width(); + int h = m->imageArray[0].height(); + + nvDebugCheck(w > 0); + nvDebugCheck(h > 0); + + if (roundMode != RoundMode_None) + { + // rounded max extent should never be higher than original max extent. + maxExtent = previousPowerOfTwo(maxExtent); + } + + // Scale extents without changing aspect ratio. + uint maxwh = max(w, h); + if (maxExtent != 0 && maxwh > maxExtent) + { + w = max((w * maxExtent) / maxwh, 1U); + h = max((h * maxExtent) / maxwh, 1U); + } + + // Round to power of two. + if (roundMode == RoundMode_ToNextPowerOfTwo) + { + w = nextPowerOfTwo(w); + h = nextPowerOfTwo(h); + } + else if (roundMode == RoundMode_ToNearestPowerOfTwo) + { + w = nearestPowerOfTwo(w); + h = nearestPowerOfTwo(h); + } + else if (roundMode == RoundMode_ToPreviousPowerOfTwo) + { + w = previousPowerOfTwo(w); + h = previousPowerOfTwo(h); + } + + resize(w, h, filter); + } } bool Texture::buildNextMipmap(MipmapFilter filter) { - // @@ Not implemented. + detach(); + + + foreach(i, m->imageArray) + { + FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode; + + if (m->alphaMode == AlphaMode_Transparency) + { + if (filter == MipmapFilter_Box) + { + BoxFilter filter; + m->imageArray[i].downSample(filter, wrapMode, 3); + } + else if (filter == MipmapFilter_Triangle) + { + TriangleFilter filter; + m->imageArray[i].downSample(filter, wrapMode, 3); + } + else if (filter == MipmapFilter_Kaiser) + { + nvDebugCheck(filter == MipmapFilter_Kaiser); + //KaiserFilter filter(inputOptions.kaiserWidth); + //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); + KaiserFilter filter(3); + m->imageArray[i].downSample(filter, wrapMode, 3); + } + } + else + { + if (filter == MipmapFilter_Box) + { + m->imageArray[i].fastDownSample(); + } + else if (filter == MipmapFilter_Triangle) + { + TriangleFilter filter; + m->imageArray[i].downSample(filter, wrapMode); + } + else //if (filter == MipmapFilter_Kaiser) + { + nvDebugCheck(filter == MipmapFilter_Kaiser); + //KaiserFilter filter(inputOptions.kaiserWidth); + //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); + KaiserFilter filter(3); + m->imageArray[i].downSample(filter, wrapMode); + } + } + } } // Color transforms. void Texture::toLinear(float gamma) { + if (equal(gamma, 1.0f)) return; + + detach(); + foreach(i, m->imageArray) { m->imageArray[i].toLinear(0, 3, gamma); @@ -84,6 +319,10 @@ void Texture::toLinear(float gamma) void Texture::toGamma(float gamma) { + if (equal(gamma, 1.0f)) return; + + detach(); + foreach(i, m->imageArray) { m->imageArray[i].toGamma(0, 3, gamma); @@ -92,11 +331,28 @@ void Texture::toGamma(float gamma) void Texture::transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4]) { - // @@ Not implemented. + detach(); + + Matrix xform( + Vector4(w0[0], w0[1], w0[2], w0[3]), + Vector4(w1[0], w1[1], w1[2], w1[3]), + Vector4(w2[0], w2[1], w2[2], w2[3]), + Vector4(w3[0], w3[1], w3[2], w3[3])); + + Vector4 voffset(offset[0], offset[1], offset[2], offset[3]); + + foreach(i, m->imageArray) + { + m->imageArray[i].transform(0, xform, voffset); + } } void Texture::swizzle(int r, int g, int b, int a) { + if (r == 0 && g == 1 && b == 2 && a == 3) return; + + detach(); + foreach(i, m->imageArray) { m->imageArray[i].swizzle(0, r, g, b, a); @@ -105,14 +361,20 @@ void Texture::swizzle(int r, int g, int b, int a) void Texture::scaleBias(int channel, float scale, float bias) { + if (equal(scale, 1.0f) && equal(bias, 0.0f)) return; + + detach(); + foreach(i, m->imageArray) { m->imageArray[i].scaleBias(channel, 1, scale, bias); } } -void Texture::normalize() +void Texture::normalizeNormals() { + detach(); + foreach(i, m->imageArray) { m->imageArray[i].normalize(0); @@ -121,11 +383,18 @@ void Texture::normalize() void Texture::blend(float r, float g, float b, float a) { - // @@ Not implemented. + detach(); + + foreach(i, m->imageArray) + { + // @@ Not implemented. + } } void Texture::premultiplyAlpha() { + detach(); + // @@ Not implemented. } diff --git a/src/nvtt/Texture.h b/src/nvtt/Texture.h index ff8ee99..c273d64 100644 --- a/src/nvtt/Texture.h +++ b/src/nvtt/Texture.h @@ -37,7 +37,28 @@ namespace nvtt struct Texture::Private : public nv::RefCounted { + Private() + { + type = TextureType_2D; + wrapMode = WrapMode_Mirror; + alphaMode = AlphaMode_None; + isNormalMap = false; + } + Private(const Private & p) + { + type = p.type; + wrapMode = p.wrapMode; + alphaMode = p.alphaMode; + isNormalMap = p.isNormalMap; + + imageArray = p.imageArray; + } + TextureType type; + WrapMode wrapMode; + AlphaMode alphaMode; + bool isNormalMap; + nv::Array imageArray; }; diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index 86fe48b..ba74f30 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -246,7 +246,7 @@ namespace nvtt // Set gamma settings. NVTT_API void setGamma(float inputGamma, float outputGamma); - // Set texture wrappign mode. + // Set texture wrapping mode. NVTT_API void setWrapMode(WrapMode mode); // Set mipmapping options. @@ -357,8 +357,6 @@ namespace nvtt // Estimate the size of compressing the input with the given options. NVTT_API int estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions) const; - NVTT_API void outputCompressed(const Texture & tex, const OutputOptions & outputOptions); - NVTT_API Texture createTexture(); }; @@ -375,13 +373,19 @@ namespace nvtt NVTT_API void operator=(const Texture & tex); - NVTT_API bool load(const char * fileName); // @@ Input callbacks? - + // Texture parameters. NVTT_API void setType(TextureType type); + NVTT_API void setWrapMode(WrapMode mode); + NVTT_API void setAlphaMode(AlphaMode alphaMode); + NVTT_API void setNormalMap(bool isNormalMap); + + // Texture data. + NVTT_API bool load(const char * fileName); NVTT_API void setTexture2D(InputFormat format, int w, int h, int idx, void * data); - // Resizing + // Resizing methods. 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. @@ -390,11 +394,21 @@ namespace nvtt NVTT_API void transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4]); NVTT_API void swizzle(int r, int g, int b, int a); NVTT_API void scaleBias(int channel, float scale, float bias); - NVTT_API void normalize(); NVTT_API void blend(float r, float g, float b, float a); NVTT_API void premultiplyAlpha(); + NVTT_API void toGreyScale(float redScale, float greenScale, float blueScale, float alphaScale); + + // Set normal map options. + NVTT_API void toNormalMap(float sm, float medium, float big, float large); + NVTT_API void toHeightMap(); + NVTT_API void normalizeNormals(); + + // Compress. + NVTT_API void process(const CompressionOptions & compressionOptions, const OutputOptions & outputOptions); private: + void detach(); + struct Private; Private * m; }; diff --git a/src/nvtt/tests/imperativeapi.cpp b/src/nvtt/tests/imperativeapi.cpp index 4872bc4..33edd40 100644 --- a/src/nvtt/tests/imperativeapi.cpp +++ b/src/nvtt/tests/imperativeapi.cpp @@ -43,7 +43,9 @@ int main(int argc, char *argv[]) { nvtt::Texture tmp = texture; tmp.toGamma(gamma); - //tmp.compress(compressionOptions, outputOptions); + + // context.process(tmp, compressionOptions, outputOptions); + // tmp.process(compressionOptions, outputOptions); } return EXIT_SUCCESS;