Improved floating point random number generation.

Fixed loading RGB images, as reported in issue 15.
Moved pixel format conversion helpers to PixelFormat.h
2.0
castano 17 years ago
parent c9c7c42d2b
commit e7aca55ba3

@ -29,6 +29,7 @@
#include <nvimage/ColorBlock.h>
#include <nvimage/Image.h>
#include <nvimage/BlockDXT.h>
#include <nvimage/PixelFormat.h>
#include <string.h> // 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;
}

@ -0,0 +1,84 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// 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 <nvimage.h>
// @@ 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

@ -24,6 +24,7 @@
#include <nvcore/Debug.h>
#include <nvimage/Image.h>
#include <nvimage/PixelFormat.h>
#include <nvmath/Color.h>
#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;
}
}
}

@ -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 ) {

@ -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();

Loading…
Cancel
Save