Adding support for floating point input/output. Work in progress.

This commit is contained in:
castano 2008-07-31 02:04:44 +00:00
parent 3161fca9d9
commit e9002a7d86
12 changed files with 282 additions and 27 deletions

View File

@ -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.

View File

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

View File

@ -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<void *>(m_mem) );
m_mem = NULL;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -45,6 +45,10 @@ namespace nvtt
uint gmask;
uint bmask;
uint amask;
uint8 rsize;
uint8 gsize;
uint8 bsize;
uint8 asize;
PixelType pixelType;

View File

@ -393,9 +393,51 @@ bool Compressor::Private::outputHeader(const InputOptions::Private & inputOption
if (compressionOptions.format == Format_RGBA)
{
header.setPitch(computePitch(inputOptions.targetWidth, compressionOptions.bitcount));
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
{
header.setLinearSize(computeImageSize(inputOptions.targetWidth, inputOptions.targetHeight, inputOptions.targetDepth, compressionOptions.bitcount, compressionOptions.format));
@ -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);
}

View File

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

View File

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

View File

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