diff --git a/src/nvimage/DirectDrawSurface.cpp b/src/nvimage/DirectDrawSurface.cpp index e7d6ee6..a0d1eec 100644 --- a/src/nvimage/DirectDrawSurface.cpp +++ b/src/nvimage/DirectDrawSurface.cpp @@ -654,6 +654,20 @@ void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3) this->pf.amask = 0; } +void DDSHeader::setFormatCode(uint32 code) +{ + // set fourcc pixel format. + this->pf.flags = DDPF_FOURCC; + this->pf.fourcc = code; + + this->pf.bitcount = 0; + this->pf.rmask = 0; + this->pf.gmask = 0; + this->pf.bmask = 0; + this->pf.amask = 0; +} + + void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask) { // Make sure the masks are correct. diff --git a/src/nvimage/DirectDrawSurface.h b/src/nvimage/DirectDrawSurface.h index c56967f..c5fea9c 100644 --- a/src/nvimage/DirectDrawSurface.h +++ b/src/nvimage/DirectDrawSurface.h @@ -93,6 +93,7 @@ namespace nv void setLinearSize(uint size); void setPitch(uint pitch); void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3); + void setFormatCode(uint code); void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask); void setDX10Format(uint format); void setNormalFlag(bool b); diff --git a/src/nvimage/FloatImage.cpp b/src/nvimage/FloatImage.cpp index 40ac8b2..7bb191d 100644 --- a/src/nvimage/FloatImage.cpp +++ b/src/nvimage/FloatImage.cpp @@ -141,7 +141,8 @@ Image * FloatImage::createImageGammaCorrect(float gamma/*= 2.2f*/) const /// Allocate a 2d float image of the given format and the given extents. void FloatImage::allocate(uint c, uint w, uint h) { - nvCheck(m_mem == NULL); + free(); + m_width = w; m_height = h; m_componentNum = c; @@ -152,7 +153,6 @@ void FloatImage::allocate(uint c, uint w, uint h) /// Free the image, but don't clear the members. void FloatImage::free() { - nvCheck(m_mem != NULL); nv::mem::free( reinterpret_cast(m_mem) ); m_mem = NULL; } diff --git a/src/nvimage/Image.cpp b/src/nvimage/Image.cpp index 6830992..77f7bc8 100644 --- a/src/nvimage/Image.cpp +++ b/src/nvimage/Image.cpp @@ -39,9 +39,10 @@ const Image & Image::operator=(const Image & img) void Image::allocate(uint w, uint h) { + free(); m_width = w; m_height = h; - m_data = (Color32 *)realloc(m_data, w * h * sizeof(Color32)); + m_data = (Color32 *)nv::mem::malloc(w * h * sizeof(Color32)); } bool Image::load(const char * name) diff --git a/src/nvtt/CompressRGB.cpp b/src/nvtt/CompressRGB.cpp index f45f5b6..136c703 100644 --- a/src/nvtt/CompressRGB.cpp +++ b/src/nvtt/CompressRGB.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -66,29 +67,53 @@ void nv::compressRGB(const Image * image, const OutputOptions::Private & outputO const uint w = image->width(); const uint h = image->height(); - const uint bitCount = compressionOptions.bitcount; - nvCheck(bitCount == 8 || bitCount == 16 || bitCount == 24 || bitCount == 32); + uint bitCount; + uint rmask, rshift, rsize; + uint gmask, gshift, gsize; + uint bmask, bshift, bsize; + uint amask, ashift, asize; + + if (compressionOptions.bitcount != 0) + { + bitCount = compressionOptions.bitcount; + nvCheck(bitCount == 8 || bitCount == 16 || bitCount == 24 || bitCount == 32); + + rmask = compressionOptions.rmask; + gmask = compressionOptions.gmask; + bmask = compressionOptions.bmask; + amask = compressionOptions.amask; + + PixelFormat::maskShiftAndSize(rmask, &rshift, &rsize); + PixelFormat::maskShiftAndSize(gmask, &gshift, &gsize); + PixelFormat::maskShiftAndSize(bmask, &bshift, &bsize); + PixelFormat::maskShiftAndSize(amask, &ashift, &asize); + } + else + { + rsize = compressionOptions.rsize; + gsize = compressionOptions.gsize; + bsize = compressionOptions.bsize; + asize = compressionOptions.asize; + + bitCount = rsize + gsize + bsize + asize; + nvCheck(bitCount <= 32); + + ashift = 0; + bshift = ashift + asize; + gshift = bshift + bsize; + rshift = gshift + gsize; + + rmask = ((1 << rsize) - 1) << rshift; + gmask = ((1 << gsize) - 1) << gshift; + bmask = ((1 << bsize) - 1) << bshift; + amask = ((1 << asize) - 1) << ashift; + } const uint byteCount = bitCount / 8; - const uint rmask = compressionOptions.rmask; - uint rshift, rsize; - PixelFormat::maskShiftAndSize(rmask, &rshift, &rsize); - - const uint gmask = compressionOptions.gmask; - uint gshift, gsize; - PixelFormat::maskShiftAndSize(gmask, &gshift, &gsize); - - const uint bmask = compressionOptions.bmask; - uint bshift, bsize; - PixelFormat::maskShiftAndSize(bmask, &bshift, &bsize); - - const uint amask = compressionOptions.amask; - uint ashift, asize; - PixelFormat::maskShiftAndSize(amask, &ashift, &asize); // Determine pitch. - uint pitch = computePitch(w, compressionOptions.bitcount); + uint pitch = computePitch(w, bitCount); uint8 * dst = (uint8 *)mem::malloc(pitch + 4); @@ -138,3 +163,66 @@ void nv::compressRGB(const Image * image, const OutputOptions::Private & outputO mem::free(dst); } + +void nv::compressRGB(const FloatImage * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) +{ + nvCheck(image != NULL); + + const uint w = image->width(); + const uint h = image->height(); + + const uint rsize = compressionOptions.rsize; + const uint gsize = compressionOptions.gsize; + const uint bsize = compressionOptions.bsize; + const uint asize = compressionOptions.asize; + + nvCheck(rsize == 0 || rsize == 16 || rsize == 32); + nvCheck(gsize == 0 || gsize == 16 || gsize == 32); + nvCheck(bsize == 0 || bsize == 16 || bsize == 32); + nvCheck(asize == 0 || asize == 16 || asize == 32); + + const uint bitCount = rsize + gsize + bsize + asize; + const uint byteCount = bitCount / 8; + const uint pitch = w * byteCount; + + uint8 * dst = (uint8 *)mem::malloc(pitch); + + for (uint y = 0; y < h; y++) + { + const float * rchannel = image->scanline(y, 0); + const float * gchannel = image->scanline(y, 1); + const float * bchannel = image->scanline(y, 2); + const float * achannel = image->scanline(y, 3); + + for (uint x = 0; x < w; x++) + { + float r = rchannel[x]; + float g = gchannel[x]; + float b = bchannel[x]; + float a = achannel[x]; + + if (rsize == 32) *((float *)dst) = r; + //else if (rsize == 16) *((half *)dst) = half(r); + dst += rsize / 8; + + if (gsize == 32) *((float *)dst) = g; + //else if (gsize == 16) *((half *)dst) = half(g); + dst += gsize / 8; + + if (bsize == 32) *((float *)dst) = b; + //else if (bsize == 16) *((half *)dst) = half(b); + dst += bsize / 8; + + if (asize == 32) *((float *)dst) = a; + //else if (asize == 16) *((half *)dst) = half(a); + dst += asize / 8; + } + + if (outputOptions.outputHandler != NULL) + { + outputOptions.outputHandler->writeData(dst, pitch); + } + } + + mem::free(dst); +} diff --git a/src/nvtt/CompressRGB.h b/src/nvtt/CompressRGB.h index 3bab47d..7d8ae6b 100644 --- a/src/nvtt/CompressRGB.h +++ b/src/nvtt/CompressRGB.h @@ -29,9 +29,11 @@ namespace nv { class Image; + class FloatImage; // Pixel format converter. void compressRGB(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); + void compressRGB(const FloatImage * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); } // nv namespace diff --git a/src/nvtt/CompressionOptions.cpp b/src/nvtt/CompressionOptions.cpp index 944256e..c338de0 100644 --- a/src/nvtt/CompressionOptions.cpp +++ b/src/nvtt/CompressionOptions.cpp @@ -117,8 +117,36 @@ void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, u m.gmask = gmask; m.bmask = bmask; m.amask = amask; + + m.rsize = 0; + m.gsize = 0; + m.bsize = 0; + m.asize = 0; } +void CompressionOptions::setPixelFormat(uint8 rsize, uint8 gsize, uint8 bsize, uint8 asize) +{ + nvCheck(rsize <= 32 || gsize <= 32 || bsize <= 32 || asize <= 32); + + m.bitcount = 0; + m.rmask = 0; + m.gmask = 0; + m.bmask = 0; + m.amask = 0; + + m.rsize = rsize; + m.gsize = gsize; + m.bsize = bsize; + m.asize = asize; +} + +/// Set pixel type. +void CompressionOptions::setPixelType(PixelType pixelType) +{ + m.pixelType = pixelType; +} + + /// Use external compressor. void CompressionOptions::setExternalCompressor(const char * name) { diff --git a/src/nvtt/CompressionOptions.h b/src/nvtt/CompressionOptions.h index 3508ff3..1e45bd0 100644 --- a/src/nvtt/CompressionOptions.h +++ b/src/nvtt/CompressionOptions.h @@ -45,6 +45,10 @@ namespace nvtt uint gmask; uint bmask; uint amask; + uint8 rsize; + uint8 gsize; + uint8 bsize; + uint8 asize; PixelType pixelType; diff --git a/src/nvtt/Compressor.cpp b/src/nvtt/Compressor.cpp index 2b337bb..651cb28 100644 --- a/src/nvtt/Compressor.cpp +++ b/src/nvtt/Compressor.cpp @@ -393,7 +393,49 @@ bool Compressor::Private::outputHeader(const InputOptions::Private & inputOption if (compressionOptions.format == Format_RGBA) { header.setPitch(computePitch(inputOptions.targetWidth, compressionOptions.bitcount)); - header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask); + + if (compressionOptions.bitcount != 0) + { + header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask); + } + else + { + if (compressionOptions.pixelType == PixelType_Float) + { + if (compressionOptions.rsize == 16 && compressionOptions.gsize == 0 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) + { + header.setFormatCode(111); // D3DFMT_R16F + } + else if (compressionOptions.rsize == 16 && compressionOptions.gsize == 16 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) + { + header.setFormatCode(112); // D3DFMT_G16R16F + } + else if (compressionOptions.rsize == 16 && compressionOptions.gsize == 16 && compressionOptions.bsize == 16 && compressionOptions.asize == 16) + { + header.setFormatCode(113); // D3DFMT_A16B16G16R16F + } + else if (compressionOptions.rsize == 32 && compressionOptions.gsize == 0 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) + { + header.setFormatCode(114); // D3DFMT_R32F + } + else if (compressionOptions.rsize == 32 && compressionOptions.gsize == 32 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) + { + header.setFormatCode(115); // D3DFMT_G32R32F + } + else if (compressionOptions.rsize == 32 && compressionOptions.gsize == 32 && compressionOptions.bsize == 32 && compressionOptions.asize == 32) + { + header.setFormatCode(116); // D3DFMT_A32B32G32R32F + } + else + { + supported = false; + } + } + else + { + supported = false; + } + } } else { @@ -503,6 +545,8 @@ bool Compressor::Private::compressMipmaps(uint f, const InputOptions::Private & } } + // @@ Do alpha premultiplication and YCoCg transformation here. Allow these operations to be done in floating point. + quantizeMipmap(mipmap, compressionOptions); compressMipmap(mipmap, inputOptions, compressionOptions, outputOptions); @@ -805,6 +849,8 @@ bool Compressor::Private::compressMipmap(const Mipmap & mipmap, const InputOptio const Image * image = mipmap.asFixedImage(); nvDebugCheck(image != NULL); + // @@ Use FastCompressor::isSupported(compressionOptions.format) to chose compressor. + FastCompressor fast; fast.setImage(image, inputOptions.alphaMode); @@ -812,7 +858,7 @@ bool Compressor::Private::compressMipmap(const Mipmap & mipmap, const InputOptio slow.setImage(image, inputOptions.alphaMode); - if (compressionOptions.format == Format_RGBA || compressionOptions.format == Format_RGB) + if (compressionOptions.format == Format_RGBA) { compressRGB(image, outputOptions, compressionOptions); } diff --git a/src/nvtt/InputOptions.cpp b/src/nvtt/InputOptions.cpp index 474c16c..b08d735 100644 --- a/src/nvtt/InputOptions.cpp +++ b/src/nvtt/InputOptions.cpp @@ -252,6 +252,68 @@ bool InputOptions::setMipmapData(const void * data, int width, int height, int d } +// Copies data +bool InputOptions::setMipmapChannelData(const void * data, int channel, int width, int height, int depth /*= 1*/, int face /*= 0*/, int mipLevel /*= 0*/) +{ + nvCheck(depth == 1); + nvCheck(channel >= 0 && channel < 4); + + const int idx = face * m.mipmapCount + mipLevel; + + if (m.images[idx].width != width || m.images[idx].height != height || m.images[idx].depth != depth || m.images[idx].mipLevel != mipLevel || m.images[idx].face != face) + { + // Invalid dimension or index. + return false; + } + + // Allocate image if not allocated already. + if (m.inputFormat == InputFormat_BGRA_8UB) + { + m.images[idx].floatdata = NULL; + if (m.images[idx].uint8data == NULL) + { + m.images[idx].uint8data = new Image(); + } + + m.images[idx].uint8data->allocate(width, height); + } + else if (m.inputFormat == InputFormat_RGBA_32F) + { + m.images[idx].uint8data = NULL; + if (m.images[idx].floatdata == NULL) + { + m.images[idx].floatdata = new FloatImage(); + } + + m.images[idx].floatdata->allocate(4, width, height); + } + else + { + m.images[idx].floatdata = NULL; + m.images[idx].uint8data = NULL; + return false; + } + + // Copy channel data to image. + if (m.inputFormat == InputFormat_BGRA_8UB) + { + // @@ TODO + } + else if (m.inputFormat == InputFormat_RGBA_32F) + { + const float * floatData = (const float *)data; + float * channelPtr = m.images[idx].floatdata->channel(channel); + + for (int i = 0; i < width * height; i++) + { + channelPtr[i] = floatData[i]; + } + } + + return true; +} + + /// Describe the format of the input. void InputOptions::setFormat(InputFormat format) { diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index 1bf67b8..05194b7 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -125,9 +125,7 @@ namespace nvtt // Set color mask to describe the RGB/RGBA format. NVTT_API void setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask); - - // As - NVTT_API void setPixelFormat2(unsigned int rsize, unsigned int gsize, unsigned int bsize, unsigned int asize); + NVTT_API void setPixelFormat(unsigned char rsize, unsigned char gsize, unsigned char bsize, unsigned char asize); NVTT_API void setPixelType(PixelType pixelType); @@ -220,6 +218,7 @@ namespace nvtt // Set mipmap data. Copies the data. NVTT_API bool setMipmapData(const void * data, int w, int h, int d = 1, int face = 0, int mipmap = 0); + NVTT_API bool setMipmapChannelData(const void * data, int channel, int w, int h, int d = 1, int face = 0, int mipmap = 0); // Describe the format of the input. NVTT_API void setFormat(InputFormat format); diff --git a/src/nvtt/tools/compress.cpp b/src/nvtt/tools/compress.cpp index bdea54f..af1bd45 100644 --- a/src/nvtt/tools/compress.cpp +++ b/src/nvtt/tools/compress.cpp @@ -392,7 +392,10 @@ int main(int argc, char *argv[]) inputOptions.setFormat(nvtt::InputFormat_RGBA_32F); inputOptions.setTextureLayout(nvtt::TextureType_2D, image->width(), image->height()); - inputOptions.setMipmapData(image->channel(0), image->width(), image->height()); + for (uint i = 0; i < image->componentNum(); i++) + { + inputOptions.setMipmapChannelData(image->channel(i), i, image->width(), image->height()); + } } else { @@ -446,6 +449,13 @@ int main(int argc, char *argv[]) nvtt::CompressionOptions compressionOptions; compressionOptions.setFormat(format); + + if (format == nvtt::Format_RGBA) + { + compressionOptions.setPixelType(nvtt::PixelType_Float); + compressionOptions.setPixelFormat(32, 32, 32, 32); + } + if (fast) { compressionOptions.setQuality(nvtt::Quality_Fastest);