Adding support for floating point input/output. Work in progress.
This commit is contained in:
parent
3161fca9d9
commit
e9002a7d86
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
nvCheck(bitCount == 8 || bitCount == 16 || bitCount == 24 || bitCount == 32);
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -45,6 +45,10 @@ namespace nvtt
|
||||
uint gmask;
|
||||
uint bmask;
|
||||
uint amask;
|
||||
uint8 rsize;
|
||||
uint8 gsize;
|
||||
uint8 bsize;
|
||||
uint8 asize;
|
||||
|
||||
PixelType pixelType;
|
||||
|
||||
|
@ -393,7 +393,49 @@ bool Compressor::Private::outputHeader(const InputOptions::Private & inputOption
|
||||
if (compressionOptions.format == Format_RGBA)
|
||||
{
|
||||
header.setPitch(computePitch(inputOptions.targetWidth, compressionOptions.bitcount));
|
||||
header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask);
|
||||
|
||||
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
|
||||
{
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user