diff --git a/src/nvtt/CompressorRGB.cpp b/src/nvtt/CompressorRGB.cpp index 880e408..f6f708c 100644 --- a/src/nvtt/CompressorRGB.cpp +++ b/src/nvtt/CompressorRGB.cpp @@ -58,6 +58,13 @@ namespace memcpy(dst, src, 4 * w); } + static uint16 to_half(float f) + { + union { float f; uint32 u; } c; + c.f = f; + return half_from_float(c.u); + } + } // namespace @@ -126,15 +133,19 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo uint byteCount = (bitCount + 7) / 8; uint pitch = computePitch(w, bitCount); - uint srcPitchDiv4 = w; - if (inputFormat == nvtt::InputFormat_RGBA_32F) srcPitchDiv4 = w * 4; + uint srcPitch = w; + uint srcPlane = w * h; + // Allocate output scanline. uint8 * dst = (uint8 *)mem::malloc(pitch + 4); for (uint y = 0; y < h; y++) { - const uint * src = (const uint *)data + srcPitchDiv4; + const uint * src = (const uint *)data + y * srcPitch; + const float * fsrc = (const float *)data + y * srcPitch; + + uint8 * ptr = dst; for (uint x = 0; x < w; x++) { @@ -147,20 +158,68 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo b = float(c.b) / 255.0f; a = float(c.a) / 255.0f; } - else /*if (inputFormat == nvtt::InputFormat_RGBA_32F)*/ { - r = src[4 * x + 0]; - g = src[4 * x + 1]; - b = src[4 * x + 2]; - a = src[4 * x + 3]; + else { + nvDebugCheck (inputFormat == nvtt::InputFormat_RGBA_32F); + + //r = ((float *)src)[4 * x + 0]; // Color components not interleaved. + //g = ((float *)src)[4 * x + 1]; + //b = ((float *)src)[4 * x + 2]; + //a = ((float *)src)[4 * x + 3]; + r = fsrc[x + 0 * srcPlane]; + g = fsrc[x + 1 * srcPlane]; + b = fsrc[x + 2 * srcPlane]; + a = fsrc[x + 3 * srcPlane]; } if (compressionOptions.pixelType == nvtt::PixelType_Float) { + if (rsize == 32) *((float *)ptr) = r; + else if (rsize == 16) *((uint16 *)ptr) = to_half(r); + ptr += rsize / 8; + if (gsize == 32) *((float *)ptr) = g; + else if (gsize == 16) *((uint16 *)ptr) = to_half(g); + ptr += gsize / 8; + + if (bsize == 32) *((float *)ptr) = b; + else if (bsize == 16) *((uint16 *)ptr) = to_half(b); + ptr += bsize / 8; + + if (asize == 32) *((float *)ptr) = a; + else if (asize == 16) *((uint16 *)ptr) = to_half(a); + ptr += asize / 8; + } + else + { + Color32 c; + if (compressionOptions.pixelType == nvtt::PixelType_UnsignedNorm) { + c.r = uint8(clamp(r * 255, 0.0f, 255.0f)); + c.g = uint8(clamp(g * 255, 0.0f, 255.0f)); + c.b = uint8(clamp(b * 255, 0.0f, 255.0f)); + c.a = uint8(clamp(a * 255, 0.0f, 255.0f)); + } + // @@ Add support for nvtt::PixelType_SignedInt, nvtt::PixelType_SignedNorm, nvtt::PixelType_UnsignedInt + + uint p = 0; + p |= PixelFormat::convert(c.r, 8, rsize) << rshift; + p |= PixelFormat::convert(c.g, 8, gsize) << gshift; + p |= PixelFormat::convert(c.b, 8, bsize) << bshift; + p |= PixelFormat::convert(c.a, 8, asize) << ashift; + + // Output one byte at a time. + for (uint i = 0; i < byteCount; i++) + { + *(dst + x * byteCount + i) = (p >> (i * 8)) & 0xFF; + } } - } + // Zero padding. + for (uint x = w * byteCount; x < pitch; x++) + { + *(dst + x) = 0; + } + if (outputOptions.outputHandler != NULL) { outputOptions.outputHandler->writeData(dst, pitch); @@ -169,182 +228,3 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo mem::free(dst); } - - - -// Pixel format converter. -void compressRGB(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) -{ - nvCheck(image != NULL); - - const uint w = image->width(); - const uint h = image->height(); - - 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; - - - // Determine pitch. - uint pitch = computePitch(w, bitCount); - - uint8 * dst = (uint8 *)mem::malloc(pitch + 4); - - for (uint y = 0; y < h; y++) - { - const Color32 * src = image->scanline(y); - - if (bitCount == 32 && rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0xFF000000) - { - convert_to_a8r8g8b8(src, dst, w); - } - else if (bitCount == 32 && rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0) - { - convert_to_x8r8g8b8(src, dst, w); - } - else - { - // Generic pixel format conversion. - for (uint x = 0; x < w; x++) - { - uint c = 0; - c |= PixelFormat::convert(src[x].r, 8, rsize) << rshift; - c |= PixelFormat::convert(src[x].g, 8, gsize) << gshift; - c |= PixelFormat::convert(src[x].b, 8, bsize) << bshift; - c |= PixelFormat::convert(src[x].a, 8, asize) << ashift; - - // Output one byte at a time. - for (uint i = 0; i < byteCount; i++) - { - *(dst + x * byteCount + i) = (c >> (i * 8)) & 0xFF; - } - } - - // Zero padding. - for (uint x = w * byteCount; x < pitch; x++) - { - *(dst + x) = 0; - } - } - - if (outputOptions.outputHandler != NULL) - { - outputOptions.outputHandler->writeData(dst, pitch); - } - } - - mem::free(dst); -} - - -void 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); - - union FLOAT - { - float f; - uint32 u; - }; - - uint8 * ptr = dst; - - for (uint x = 0; x < w; x++) - { - FLOAT r, g, b, a; - r.f = rchannel[x]; - g.f = gchannel[x]; - b.f = bchannel[x]; - a.f = achannel[x]; - - if (rsize == 32) *((uint32 *)ptr) = r.u; - else if (rsize == 16) *((uint16 *)ptr) = half_from_float(r.u); - ptr += rsize / 8; - - if (gsize == 32) *((uint32 *)ptr) = g.u; - else if (gsize == 16) *((uint16 *)ptr) = half_from_float(g.u); - ptr += gsize / 8; - - if (bsize == 32) *((uint32 *)ptr) = b.u; - else if (bsize == 16) *((uint16 *)ptr) = half_from_float(b.u); - ptr += bsize / 8; - - if (asize == 32) *((uint32 *)ptr) = a.u; - else if (asize == 16) *((uint16 *)ptr) = half_from_float(a.u); - ptr += asize / 8; - } - - if (outputOptions.outputHandler != NULL) - { - outputOptions.outputHandler->writeData(dst, pitch); - } - } - - mem::free(dst); -}