From e7aca55ba33dbdcce7a948c36ed02338b6a005ea Mon Sep 17 00:00:00 2001 From: castano Date: Mon, 8 Oct 2007 00:56:58 +0000 Subject: [PATCH] Improved floating point random number generation. Fixed loading RGB images, as reported in issue 15. Moved pixel format conversion helpers to PixelFormat.h --- src/nvimage/DirectDrawSurface.cpp | 50 ++++-------------- src/nvimage/PixelFormat.h | 84 +++++++++++++++++++++++++++++++ src/nvimage/nvtt/CompressRGB.cpp | 55 ++++++-------------- src/nvmath/Montecarlo.cpp | 14 +++--- src/nvmath/Random.h | 19 ++++++- 5 files changed, 131 insertions(+), 91 deletions(-) create mode 100644 src/nvimage/PixelFormat.h diff --git a/src/nvimage/DirectDrawSurface.cpp b/src/nvimage/DirectDrawSurface.cpp index d597979..f885bbe 100644 --- a/src/nvimage/DirectDrawSurface.cpp +++ b/src/nvimage/DirectDrawSurface.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include // memset @@ -765,39 +766,6 @@ void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap) } } -// @@ Move this code to format conversion!! -namespace -{ - static uint convert(uint c, uint inbits, uint outbits) - { - if (inbits <= outbits) - { - // truncate - return c >> (inbits - outbits); - } - else - { - // bitexpand - return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits); - } - } - - static void maskShiftAndSize(uint mask, uint * shift, uint * size) - { - *shift = 0; - while((mask & 1) == 0) { - ++(*shift); - mask >>= 1; - } - - *size = 0; - while((mask & 1) == 1) { - ++(*size); - mask >>= 1; - } - } -} - void DirectDrawSurface::readLinearImage(Image * img) { nvDebugCheck(stream != NULL); @@ -807,16 +775,16 @@ void DirectDrawSurface::readLinearImage(Image * img) const uint h = img->height(); uint rshift, rsize; - maskShiftAndSize(header.pf.rmask, &rshift, &rsize); + PixelFormat::maskShiftAndSize(header.pf.rmask, &rshift, &rsize); uint gshift, gsize; - maskShiftAndSize(header.pf.gmask, &gshift, &gsize); + PixelFormat::maskShiftAndSize(header.pf.gmask, &gshift, &gsize); uint bshift, bsize; - maskShiftAndSize(header.pf.bmask, &bshift, &bsize); + PixelFormat::maskShiftAndSize(header.pf.bmask, &bshift, &bsize); uint ashift, asize; - maskShiftAndSize(header.pf.amask, &ashift, &asize); + PixelFormat::maskShiftAndSize(header.pf.amask, &ashift, &asize); uint byteCount = (header.pf.bitcount + 7) / 8; @@ -834,10 +802,10 @@ void DirectDrawSurface::readLinearImage(Image * img) stream->serialize(&c, byteCount); Color32 pixel(0, 0, 0, 0xFF); - pixel.r = convert(c >> rshift, rsize, 8); - pixel.g = convert(c >> gshift, gsize, 8); - pixel.b = convert(c >> bshift, bsize, 8); - pixel.a = convert(c >> ashift, asize, 8); + pixel.r = PixelFormat::convert(c >> rshift, rsize, 8); + pixel.g = PixelFormat::convert(c >> gshift, gsize, 8); + pixel.b = PixelFormat::convert(c >> bshift, bsize, 8); + pixel.a = PixelFormat::convert(c >> ashift, asize, 8); img->pixel(x, y) = pixel; } diff --git a/src/nvimage/PixelFormat.h b/src/nvimage/PixelFormat.h new file mode 100644 index 0000000..801adc2 --- /dev/null +++ b/src/nvimage/PixelFormat.h @@ -0,0 +1,84 @@ +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef NV_IMAGE_PIXELFORMAT_H +#define NV_IMAGE_PIXELFORMAT_H + + +#include + + +// @@ Move this code to format conversion!! +namespace nv +{ + namespace PixelFormat + { + + // Convert component @a c having @a inbits to the returned value having @a outbits. + inline uint convert(uint c, uint inbits, uint outbits) + { + if (inbits == 0) + { + return 0; + } + else if (inbits >= outbits) + { + // truncate + return c >> (inbits - outbits); + } + else + { + // bitexpand + return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits); + } + } + + // Get pixel component shift and size given its mask. + static void maskShiftAndSize(uint mask, uint * shift, uint * size) + { + if (!mask) + { + *shift = 0; + *size = 0; + return; + } + + *shift = 0; + while((mask & 1) == 0) { + ++(*shift); + mask >>= 1; + } + + *size = 0; + while((mask & 1) == 1) { + ++(*size); + mask >>= 1; + } + } + + } // PixelFormat namespace + +} // nv namespace + + +#endif // NV_IMAGE_PIXELFORMAT_H diff --git a/src/nvimage/nvtt/CompressRGB.cpp b/src/nvimage/nvtt/CompressRGB.cpp index c10d0f1..0435e50 100644 --- a/src/nvimage/nvtt/CompressRGB.cpp +++ b/src/nvimage/nvtt/CompressRGB.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "CompressRGB.h" @@ -54,35 +55,6 @@ namespace memcpy(dst, src, 4 * w); } - static uint convert(uint c, uint inbits, uint outbits) - { - if (inbits <= outbits) - { - // truncate - return c >> (inbits - outbits); - } - else - { - // bitexpand - return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits); - } - } - - static void maskShiftAndSize(uint mask, uint * shift, uint * size) - { - *shift = 0; - while((mask & 1) == 0) { - ++(*shift); - mask >>= 1; - } - - *size = 0; - while((mask & 1) == 1) { - ++(*size); - mask >>= 1; - } - } - } // namespace @@ -101,21 +73,19 @@ void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, c const uint rmask = compressionOptions.rmask; uint rshift, rsize; - maskShiftAndSize(rmask, &rshift, &rsize); + PixelFormat::maskShiftAndSize(rmask, &rshift, &rsize); const uint gmask = compressionOptions.gmask; uint gshift, gsize; - maskShiftAndSize(gmask, &gshift, &gsize); + PixelFormat::maskShiftAndSize(gmask, &gshift, &gsize); const uint bmask = compressionOptions.bmask; uint bshift, bsize; - maskShiftAndSize(bmask, &bshift, &bsize); + PixelFormat::maskShiftAndSize(bmask, &bshift, &bsize); const uint amask = compressionOptions.amask; uint ashift, asize; - maskShiftAndSize(amask, &ashift, &asize); - - // @@ Perform error diffusion dithering. + PixelFormat::maskShiftAndSize(amask, &ashift, &asize); // Determine pitch. uint pitch = computePitch(w, compressionOptions.bitcount); @@ -140,13 +110,16 @@ void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, c for (uint x = 0; x < w; x++) { uint c = 0; - c |= convert(src[x].r, 8, rsize) << rshift; - c |= convert(src[x].g, 8, gsize) << gshift; - c |= convert(src[x].b, 8, bsize) << bshift; - c |= convert(src[x].a, 8, asize) << ashift; + 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; - // @@ This is wrong, this pixels overlaps with the previous one! - *(uint *)(dst + x * byteCount) = c; + // Output one byte at a time. @@ Not tested... Does this work on LE and BE? + for (int i = 0; i < byteCount; i++) + { + *(dst + x * byteCount) = (c >> (i * 8)) & 0xFF; + } } } diff --git a/src/nvmath/Montecarlo.cpp b/src/nvmath/Montecarlo.cpp index 05a988d..4cd23a5 100644 --- a/src/nvmath/Montecarlo.cpp +++ b/src/nvmath/Montecarlo.cpp @@ -28,8 +28,8 @@ void SampleDistribution::redistributeRandom(const Distribution dist) // This is the worst method possible! for(uint i = 0; i < sampleCount; i++) { - float x = m_rand.getReal(); - float y = m_rand.getReal(); + float x = m_rand.getFloat(); + float y = m_rand.getFloat(); // Map uniform distribution in the square to the (hemi)sphere. if( dist == Distribution_Uniform ) { @@ -53,8 +53,8 @@ void SampleDistribution::redistributeStratified(const Distribution dist) // Create a uniform distribution of points on the hemisphere with low variance. for(uint v = 0, i = 0; v < sqrtSampleCount; v++) { for(uint u = 0; u < sqrtSampleCount; u++, i++) { - float x = (u + m_rand.getReal()) / float(sqrtSampleCount); - float y = (v + m_rand.getReal()) / float(sqrtSampleCount); + float x = (u + m_rand.getFloat()) / float(sqrtSampleCount); + float y = (v + m_rand.getFloat()) / float(sqrtSampleCount); // Map uniform distribution in the square to the (hemi)sphere. if( dist == Distribution_Uniform ) { @@ -82,7 +82,7 @@ void SampleDistribution::multiStageNRooks(const int size, int* cells) int size2 = size >> 1; if (size & 1) { - if (m_rand.getReal() > 0.5) { + if (m_rand.getFloat() > 0.5) { size1++; } else { @@ -138,8 +138,8 @@ void SampleDistribution::redistributeNRook(const Distribution dist) for(uint i = 0; i < sampleCount; i++) { - float x = (i + m_rand.getReal()) / sampleCount; - float y = (cells[i] + m_rand.getReal()) / sampleCount; + float x = (i + m_rand.getFloat()) / sampleCount; + float y = (cells[i] + m_rand.getFloat()) / sampleCount; // Map uniform distribution in the square to the (hemi)sphere. if( dist == Distribution_Uniform ) { diff --git a/src/nvmath/Random.h b/src/nvmath/Random.h index 0e38de9..0f76949 100644 --- a/src/nvmath/Random.h +++ b/src/nvmath/Random.h @@ -35,6 +35,20 @@ public: return n; } + /// Random number on [0.0, 1.0] interval. + float getFloat() + { + union + { + uint32 i; + float f; + } pun; + + pun.i = 0x3f800000UL | (get() & 0x007fffffUL); + return pun.f - 1.0f; + } + + /* /// Random number on [0.0, 1.0] interval. double getReal() { @@ -45,7 +59,8 @@ public: double getRealExclusive() { return double(get()) * (1.0/4294967296.0); // 2^32 - } + } + */ /// Get the max value of the random number. uint max() const { return 4294967295U; } @@ -301,7 +316,7 @@ public: } /** Get a random number. */ - virtual uint Get() { + virtual uint get() { advance();