Improved floating point random number generation.
Fixed loading RGB images, as reported in issue 15. Moved pixel format conversion helpers to PixelFormat.h
This commit is contained in:
parent
c9c7c42d2b
commit
e7aca55ba3
@ -29,6 +29,7 @@
|
|||||||
#include <nvimage/ColorBlock.h>
|
#include <nvimage/ColorBlock.h>
|
||||||
#include <nvimage/Image.h>
|
#include <nvimage/Image.h>
|
||||||
#include <nvimage/BlockDXT.h>
|
#include <nvimage/BlockDXT.h>
|
||||||
|
#include <nvimage/PixelFormat.h>
|
||||||
|
|
||||||
#include <string.h> // memset
|
#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)
|
void DirectDrawSurface::readLinearImage(Image * img)
|
||||||
{
|
{
|
||||||
nvDebugCheck(stream != NULL);
|
nvDebugCheck(stream != NULL);
|
||||||
@ -807,16 +775,16 @@ void DirectDrawSurface::readLinearImage(Image * img)
|
|||||||
const uint h = img->height();
|
const uint h = img->height();
|
||||||
|
|
||||||
uint rshift, rsize;
|
uint rshift, rsize;
|
||||||
maskShiftAndSize(header.pf.rmask, &rshift, &rsize);
|
PixelFormat::maskShiftAndSize(header.pf.rmask, &rshift, &rsize);
|
||||||
|
|
||||||
uint gshift, gsize;
|
uint gshift, gsize;
|
||||||
maskShiftAndSize(header.pf.gmask, &gshift, &gsize);
|
PixelFormat::maskShiftAndSize(header.pf.gmask, &gshift, &gsize);
|
||||||
|
|
||||||
uint bshift, bsize;
|
uint bshift, bsize;
|
||||||
maskShiftAndSize(header.pf.bmask, &bshift, &bsize);
|
PixelFormat::maskShiftAndSize(header.pf.bmask, &bshift, &bsize);
|
||||||
|
|
||||||
uint ashift, asize;
|
uint ashift, asize;
|
||||||
maskShiftAndSize(header.pf.amask, &ashift, &asize);
|
PixelFormat::maskShiftAndSize(header.pf.amask, &ashift, &asize);
|
||||||
|
|
||||||
uint byteCount = (header.pf.bitcount + 7) / 8;
|
uint byteCount = (header.pf.bitcount + 7) / 8;
|
||||||
|
|
||||||
@ -834,10 +802,10 @@ void DirectDrawSurface::readLinearImage(Image * img)
|
|||||||
stream->serialize(&c, byteCount);
|
stream->serialize(&c, byteCount);
|
||||||
|
|
||||||
Color32 pixel(0, 0, 0, 0xFF);
|
Color32 pixel(0, 0, 0, 0xFF);
|
||||||
pixel.r = convert(c >> rshift, rsize, 8);
|
pixel.r = PixelFormat::convert(c >> rshift, rsize, 8);
|
||||||
pixel.g = convert(c >> gshift, gsize, 8);
|
pixel.g = PixelFormat::convert(c >> gshift, gsize, 8);
|
||||||
pixel.b = convert(c >> bshift, bsize, 8);
|
pixel.b = PixelFormat::convert(c >> bshift, bsize, 8);
|
||||||
pixel.a = convert(c >> ashift, asize, 8);
|
pixel.a = PixelFormat::convert(c >> ashift, asize, 8);
|
||||||
|
|
||||||
img->pixel(x, y) = pixel;
|
img->pixel(x, y) = pixel;
|
||||||
}
|
}
|
||||||
|
84
src/nvimage/PixelFormat.h
Normal file
84
src/nvimage/PixelFormat.h
Normal file
@ -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 <nvcore/Debug.h>
|
||||||
|
|
||||||
#include <nvimage/Image.h>
|
#include <nvimage/Image.h>
|
||||||
|
#include <nvimage/PixelFormat.h>
|
||||||
#include <nvmath/Color.h>
|
#include <nvmath/Color.h>
|
||||||
|
|
||||||
#include "CompressRGB.h"
|
#include "CompressRGB.h"
|
||||||
@ -54,35 +55,6 @@ namespace
|
|||||||
memcpy(dst, src, 4 * w);
|
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
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
@ -101,21 +73,19 @@ void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, c
|
|||||||
|
|
||||||
const uint rmask = compressionOptions.rmask;
|
const uint rmask = compressionOptions.rmask;
|
||||||
uint rshift, rsize;
|
uint rshift, rsize;
|
||||||
maskShiftAndSize(rmask, &rshift, &rsize);
|
PixelFormat::maskShiftAndSize(rmask, &rshift, &rsize);
|
||||||
|
|
||||||
const uint gmask = compressionOptions.gmask;
|
const uint gmask = compressionOptions.gmask;
|
||||||
uint gshift, gsize;
|
uint gshift, gsize;
|
||||||
maskShiftAndSize(gmask, &gshift, &gsize);
|
PixelFormat::maskShiftAndSize(gmask, &gshift, &gsize);
|
||||||
|
|
||||||
const uint bmask = compressionOptions.bmask;
|
const uint bmask = compressionOptions.bmask;
|
||||||
uint bshift, bsize;
|
uint bshift, bsize;
|
||||||
maskShiftAndSize(bmask, &bshift, &bsize);
|
PixelFormat::maskShiftAndSize(bmask, &bshift, &bsize);
|
||||||
|
|
||||||
const uint amask = compressionOptions.amask;
|
const uint amask = compressionOptions.amask;
|
||||||
uint ashift, asize;
|
uint ashift, asize;
|
||||||
maskShiftAndSize(amask, &ashift, &asize);
|
PixelFormat::maskShiftAndSize(amask, &ashift, &asize);
|
||||||
|
|
||||||
// @@ Perform error diffusion dithering.
|
|
||||||
|
|
||||||
// Determine pitch.
|
// Determine pitch.
|
||||||
uint pitch = computePitch(w, compressionOptions.bitcount);
|
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++)
|
for (uint x = 0; x < w; x++)
|
||||||
{
|
{
|
||||||
uint c = 0;
|
uint c = 0;
|
||||||
c |= convert(src[x].r, 8, rsize) << rshift;
|
c |= PixelFormat::convert(src[x].r, 8, rsize) << rshift;
|
||||||
c |= convert(src[x].g, 8, gsize) << gshift;
|
c |= PixelFormat::convert(src[x].g, 8, gsize) << gshift;
|
||||||
c |= convert(src[x].b, 8, bsize) << bshift;
|
c |= PixelFormat::convert(src[x].b, 8, bsize) << bshift;
|
||||||
c |= convert(src[x].a, 8, asize) << ashift;
|
c |= PixelFormat::convert(src[x].a, 8, asize) << ashift;
|
||||||
|
|
||||||
// @@ This is wrong, this pixels overlaps with the previous one!
|
// Output one byte at a time. @@ Not tested... Does this work on LE and BE?
|
||||||
*(uint *)(dst + x * byteCount) = c;
|
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!
|
// This is the worst method possible!
|
||||||
for(uint i = 0; i < sampleCount; i++)
|
for(uint i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
float x = m_rand.getReal();
|
float x = m_rand.getFloat();
|
||||||
float y = m_rand.getReal();
|
float y = m_rand.getFloat();
|
||||||
|
|
||||||
// Map uniform distribution in the square to the (hemi)sphere.
|
// Map uniform distribution in the square to the (hemi)sphere.
|
||||||
if( dist == Distribution_Uniform ) {
|
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.
|
// Create a uniform distribution of points on the hemisphere with low variance.
|
||||||
for(uint v = 0, i = 0; v < sqrtSampleCount; v++) {
|
for(uint v = 0, i = 0; v < sqrtSampleCount; v++) {
|
||||||
for(uint u = 0; u < sqrtSampleCount; u++, i++) {
|
for(uint u = 0; u < sqrtSampleCount; u++, i++) {
|
||||||
float x = (u + m_rand.getReal()) / float(sqrtSampleCount);
|
float x = (u + m_rand.getFloat()) / float(sqrtSampleCount);
|
||||||
float y = (v + m_rand.getReal()) / float(sqrtSampleCount);
|
float y = (v + m_rand.getFloat()) / float(sqrtSampleCount);
|
||||||
|
|
||||||
// Map uniform distribution in the square to the (hemi)sphere.
|
// Map uniform distribution in the square to the (hemi)sphere.
|
||||||
if( dist == Distribution_Uniform ) {
|
if( dist == Distribution_Uniform ) {
|
||||||
@ -82,7 +82,7 @@ void SampleDistribution::multiStageNRooks(const int size, int* cells)
|
|||||||
int size2 = size >> 1;
|
int size2 = size >> 1;
|
||||||
|
|
||||||
if (size & 1) {
|
if (size & 1) {
|
||||||
if (m_rand.getReal() > 0.5) {
|
if (m_rand.getFloat() > 0.5) {
|
||||||
size1++;
|
size1++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -138,8 +138,8 @@ void SampleDistribution::redistributeNRook(const Distribution dist)
|
|||||||
|
|
||||||
for(uint i = 0; i < sampleCount; i++)
|
for(uint i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
float x = (i + m_rand.getReal()) / sampleCount;
|
float x = (i + m_rand.getFloat()) / sampleCount;
|
||||||
float y = (cells[i] + m_rand.getReal()) / sampleCount;
|
float y = (cells[i] + m_rand.getFloat()) / sampleCount;
|
||||||
|
|
||||||
// Map uniform distribution in the square to the (hemi)sphere.
|
// Map uniform distribution in the square to the (hemi)sphere.
|
||||||
if( dist == Distribution_Uniform ) {
|
if( dist == Distribution_Uniform ) {
|
||||||
|
@ -35,6 +35,20 @@ public:
|
|||||||
return n;
|
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.
|
/// Random number on [0.0, 1.0] interval.
|
||||||
double getReal()
|
double getReal()
|
||||||
{
|
{
|
||||||
@ -46,6 +60,7 @@ public:
|
|||||||
{
|
{
|
||||||
return double(get()) * (1.0/4294967296.0); // 2^32
|
return double(get()) * (1.0/4294967296.0); // 2^32
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Get the max value of the random number.
|
/// Get the max value of the random number.
|
||||||
uint max() const { return 4294967295U; }
|
uint max() const { return 4294967295U; }
|
||||||
@ -301,7 +316,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get a random number. */
|
/** Get a random number. */
|
||||||
virtual uint Get() {
|
virtual uint get() {
|
||||||
|
|
||||||
advance();
|
advance();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user