Add support for 3D texture. Integrate patch provided in issue 28 plus some additional changes.

pull/216/head
castano 13 years ago
parent 4906642ac3
commit af9ba8ae90

@ -2,6 +2,7 @@
#include "ColorBlock.h" #include "ColorBlock.h"
#include "Image.h" #include "Image.h"
#include "FloatImage.h"
#include "nvmath/Box.h" #include "nvmath/Box.h"
#include "nvcore/Utils.h" // swap #include "nvcore/Utils.h" // swap
@ -458,7 +459,6 @@ float ColorBlock::volume() const
return bounds.volume(); return bounds.volume();
}*/ }*/
#include "FloatImage.h"
void ColorSet::setColors(const float * data, uint img_w, uint img_h, uint img_x, uint img_y) void ColorSet::setColors(const float * data, uint img_w, uint img_h, uint img_x, uint img_y)
{ {

@ -983,12 +983,6 @@ bool DirectDrawSurface::isSupported() const
// Cubemaps must contain all faces. // Cubemaps must contain all faces.
return false; return false;
} }
if (isTexture3D())
{
// @@ 3D textures not supported yet.
return false;
}
} }
return true; return true;
@ -1127,15 +1121,17 @@ void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap)
uint w = width(); uint w = width();
uint h = height(); uint h = height();
uint d = depth();
// Compute width and height. // Compute width and height.
for (uint m = 0; m < mipmap; m++) for (uint m = 0; m < mipmap; m++)
{ {
w = max(1U, w / 2); w = max(1U, w / 2);
h = max(1U, h / 2); h = max(1U, h / 2);
d = max(1U, d / 2);
} }
img->allocate(w, h); img->allocate(w, h, d);
if (hasAlpha()) if (hasAlpha())
{ {
@ -1416,7 +1412,7 @@ uint DirectDrawSurface::mipmapSize(uint mipmap) const
// @@ How are 3D textures aligned? // @@ How are 3D textures aligned?
w = (w + 3) / 4; w = (w + 3) / 4;
h = (h + 3) / 4; h = (h + 3) / 4;
return blockSize() * w * h; return blockSize() * w * h * d;
} }
else else
{ {

@ -11,15 +11,15 @@ using namespace nv;
float nv::rmsColorError(const FloatImage * img, const FloatImage * ref, bool alphaWeight) float nv::rmsColorError(const FloatImage * img, const FloatImage * ref, bool alphaWeight)
{ {
if (img == NULL || ref == NULL || img->width() != ref->width() || img->height() != ref->height()) { if (!sameLayout(img, ref)) {
return FLT_MAX; return FLT_MAX;
} }
nvDebugCheck(img->componentNum() == 4); nvDebugCheck(img->componentCount() == 4);
nvDebugCheck(ref->componentNum() == 4); nvDebugCheck(ref->componentCount() == 4);
double mse = 0; double mse = 0;
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
float r0 = img->pixel(i + count * 0); float r0 = img->pixel(i + count * 0);
@ -48,14 +48,14 @@ float nv::rmsColorError(const FloatImage * img, const FloatImage * ref, bool alp
float nv::rmsAlphaError(const FloatImage * img, const FloatImage * ref) float nv::rmsAlphaError(const FloatImage * img, const FloatImage * ref)
{ {
if (img == NULL || ref == NULL || img->width() != ref->width() || img->height() != ref->height()) { if (!sameLayout(img, ref)) {
return FLT_MAX; return FLT_MAX;
} }
nvDebugCheck(img->componentNum() == 4 && ref->componentNum() == 4); nvDebugCheck(img->componentCount() == 4 && ref->componentCount() == 4);
double mse = 0; double mse = 0;
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
float a0 = img->pixel(i + count * 3); float a0 = img->pixel(i + count * 3);
@ -72,15 +72,15 @@ float nv::rmsAlphaError(const FloatImage * img, const FloatImage * ref)
float nv::averageColorError(const FloatImage * img, const FloatImage * ref, bool alphaWeight) float nv::averageColorError(const FloatImage * img, const FloatImage * ref, bool alphaWeight)
{ {
if (img == NULL || ref == NULL || img->width() != ref->width() || img->height() != ref->height()) { if (!sameLayout(img, ref)) {
return FLT_MAX; return FLT_MAX;
} }
nvDebugCheck(img->componentNum() == 4); nvDebugCheck(img->componentCount() == 4);
nvDebugCheck(ref->componentNum() == 4); nvDebugCheck(ref->componentCount() == 4);
double mae = 0; double mae = 0;
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
float r0 = img->pixel(i + count * 0); float r0 = img->pixel(i + count * 0);
@ -112,7 +112,7 @@ float nv::averageAlphaError(const FloatImage * img, const FloatImage * ref)
if (img == NULL || ref == NULL || img->width() != ref->width() || img->height() != ref->height()) { if (img == NULL || ref == NULL || img->width() != ref->width() || img->height() != ref->height()) {
return FLT_MAX; return FLT_MAX;
} }
nvDebugCheck(img->componentNum() == 4 && ref->componentNum() == 4); nvDebugCheck(img->componentCount() == 4 && ref->componentCount() == 4);
double mae = 0; double mae = 0;
@ -227,7 +227,7 @@ static void rgbToCieLab(const FloatImage * rgbImage, FloatImage * LabImage)
{ {
nvDebugCheck(rgbImage != NULL && LabImage != NULL); nvDebugCheck(rgbImage != NULL && LabImage != NULL);
nvDebugCheck(rgbImage->width() == LabImage->width() && rgbImage->height() == LabImage->height()); nvDebugCheck(rgbImage->width() == LabImage->width() && rgbImage->height() == LabImage->height());
nvDebugCheck(rgbImage->componentNum() >= 3 && LabImage->componentNum() >= 3); nvDebugCheck(rgbImage->componentCount() >= 3 && LabImage->componentCount() >= 3);
const uint w = rgbImage->width(); const uint w = rgbImage->width();
const uint h = LabImage->height(); const uint h = LabImage->height();
@ -254,13 +254,8 @@ static void rgbToCieLab(const FloatImage * rgbImage, FloatImage * LabImage)
// Assumes input images are in linear sRGB space. // Assumes input images are in linear sRGB space.
float nv::cieLabError(const FloatImage * img0, const FloatImage * img1) float nv::cieLabError(const FloatImage * img0, const FloatImage * img1)
{ {
if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) { if (!sameLayout(img0, img1)) return FLT_MAX;
return FLT_MAX; nvDebugCheck(img0->componentCount() == 4 && img0->componentCount() == 4);
}
nvDebugCheck(img0->componentNum() == 4 && img0->componentNum() == 4);
uint w = img0->width();
uint h = img0->height();
const float * r0 = img0->channel(0); const float * r0 = img0->channel(0);
const float * g0 = img0->channel(1); const float * g0 = img0->channel(1);
@ -272,7 +267,7 @@ float nv::cieLabError(const FloatImage * img0, const FloatImage * img1)
double error = 0.0f; double error = 0.0f;
const uint count = w*h; const uint count = img0->pixelCount();
for (uint i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
Vector3 lab0 = rgbToCieLab(Vector3(r0[i], g0[i], b0[i])); Vector3 lab0 = rgbToCieLab(Vector3(r0[i], g0[i], b0[i]));
@ -292,14 +287,15 @@ float nv::spatialCieLabError(const FloatImage * img0, const FloatImage * img1)
if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) { if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) {
return FLT_MAX; return FLT_MAX;
} }
nvDebugCheck(img0->componentNum() == 4 && img0->componentNum() == 4); nvDebugCheck(img0->componentCount() == 4 && img0->componentCount() == 4);
uint w = img0->width(); uint w = img0->width();
uint h = img0->height(); uint h = img0->height();
uint d = img0->depth();
FloatImage lab0, lab1; // Original images in CIE-Lab space. FloatImage lab0, lab1; // Original images in CIE-Lab space.
lab0.allocate(3, w, h); lab0.allocate(3, w, h, d);
lab1.allocate(3, w, h); lab1.allocate(3, w, h, d);
// Convert input images to CIE-Lab. // Convert input images to CIE-Lab.
rgbToCieLab(img0, &lab0); rgbToCieLab(img0, &lab0);
@ -331,7 +327,7 @@ float nv::averageAngularError(const FloatImage * img0, const FloatImage * img1)
if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) { if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) {
return FLT_MAX; return FLT_MAX;
} }
nvDebugCheck(img0->componentNum() == 4 && img0->componentNum() == 4); nvDebugCheck(img0->componentCount() == 4 && img0->componentCount() == 4);
uint w = img0->width(); uint w = img0->width();
uint h = img0->height(); uint h = img0->height();
@ -369,7 +365,7 @@ float nv::rmsAngularError(const FloatImage * img0, const FloatImage * img1)
if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) { if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) {
return FLT_MAX; return FLT_MAX;
} }
nvDebugCheck(img0->componentNum() == 4 && img0->componentNum() == 4); nvDebugCheck(img0->componentCount() == 4 && img0->componentCount() == 4);
uint w = img0->width(); uint w = img0->width();
uint h = img0->height(); uint h = img0->height();

File diff suppressed because it is too large Load Diff

@ -5,6 +5,8 @@
#include "nvimage.h" #include "nvimage.h"
#include "nvmath/nvmath.h" // lerp
#include "nvcore/Debug.h" #include "nvcore/Debug.h"
#include "nvcore/Utils.h" // clamp #include "nvcore/Utils.h" // clamp
@ -45,7 +47,7 @@ namespace nv
/** @name Allocation. */ /** @name Allocation. */
//@{ //@{
NVIMAGE_API void allocate(uint c, uint w, uint h); NVIMAGE_API void allocate(uint c, uint w, uint h, uint d = 1);
NVIMAGE_API void free(); // Does not clear members. NVIMAGE_API void free(); // Does not clear members.
NVIMAGE_API void resizeChannelCount(uint c); NVIMAGE_API void resizeChannelCount(uint c);
//@} //@}
@ -74,21 +76,30 @@ namespace nv
NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm) const; NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm) const;
NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm, uint alpha) const; NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm, uint alpha) const;
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm) const; NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm) const;
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, uint d, WrapMode wm) const;
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm, uint alpha) const; NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm, uint alpha) const;
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, uint d, WrapMode wm, uint alpha) const;
//NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, WrapMode wm) const; //NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, WrapMode wm) const;
//NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, uint w, uint h, WrapMode wm) const; //NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, uint w, uint h, WrapMode wm) const;
//@} //@}
NVIMAGE_API float applyKernel(const Kernel2 * k, int x, int y, uint c, WrapMode wm) const; NVIMAGE_API float applyKernelXY(const Kernel2 * k, int x, int y, int z, uint c, WrapMode wm) const;
NVIMAGE_API float applyKernelVertical(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const; NVIMAGE_API float applyKernelX(const Kernel1 * k, int x, int y, int z, uint c, WrapMode wm) const;
NVIMAGE_API float applyKernelHorizontal(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const; NVIMAGE_API float applyKernelY(const Kernel1 * k, int x, int y, int z, uint c, WrapMode wm) const;
NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, WrapMode wm, float * output) const; NVIMAGE_API float applyKernelZ(const Kernel1 * k, int x, int y, int z, uint c, WrapMode wm) const;
NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, WrapMode wm, float * output) const; NVIMAGE_API void applyKernelX(const PolyphaseKernel & k, int y, int z, uint c, WrapMode wm, float * output) const;
NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, uint a, WrapMode wm, float * output) const; NVIMAGE_API void applyKernelY(const PolyphaseKernel & k, int x, int z, uint c, WrapMode wm, float * output) const;
NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, uint a, WrapMode wm, float * output) const; NVIMAGE_API void applyKernelZ(const PolyphaseKernel & k, int x, int y, uint c, WrapMode wm, float * output) const;
NVIMAGE_API void applyKernelX(const PolyphaseKernel & k, int y, int z, uint c, uint a, WrapMode wm, float * output) const;
NVIMAGE_API void applyKernelY(const PolyphaseKernel & k, int x, int z, uint c, uint a, WrapMode wm, float * output) const;
NVIMAGE_API void applyKernelZ(const PolyphaseKernel & k, int x, int y, uint c, uint a, WrapMode wm, float * output) const;
NVIMAGE_API void flip(); NVIMAGE_API void flipX();
NVIMAGE_API void flipY();
NVIMAGE_API void flipZ();
NVIMAGE_API float alphaTestCoverage(float alphaRef, int alphaChannel) const; NVIMAGE_API float alphaTestCoverage(float alphaRef, int alphaChannel) const;
NVIMAGE_API void scaleAlphaToCoverage(float coverage, float alphaRef, int alphaChannel); NVIMAGE_API void scaleAlphaToCoverage(float coverage, float alphaRef, int alphaChannel);
@ -96,37 +107,58 @@ namespace nv
uint width() const { return m_width; } uint width() const { return m_width; }
uint height() const { return m_height; } uint height() const { return m_height; }
uint componentNum() const { return m_componentNum; } uint depth() const { return m_depth; }
uint count() const { return m_count; } uint componentCount() const { return m_componentCount; }
uint floatCount() const { return m_floatCount; }
uint pixelCount() const { return m_pixelCount; }
// @@ It would make sense to swap the order of the arguments so that 'c' is always first.
/** @name Pixel access. */ /** @name Pixel access. */
//@{ //@{
const float * channel(uint c) const; const float * channel(uint c) const;
float * channel(uint c); float * channel(uint c);
const float * scanline(uint y, uint c) const; const float * plane(uint c, uint z) const;
float * scanline(uint y, uint c); float * plane(uint c, uint z);
const float * scanline(uint c, uint y, uint z) const;
float * scanline(uint c, uint y, uint z);
float pixel(uint x, uint y, uint c) const; //float pixel(uint c, uint x, uint y) const;
float & pixel(uint x, uint y, uint c); //float & pixel(uint c, uint x, uint y);
float pixel(uint idx, uint c) const; float pixel(uint c, uint x, uint y, uint z) const;
float & pixel(uint idx, uint c); float & pixel(uint c, uint x, uint y, uint z);
float pixel(uint c, uint idx) const;
float & pixel(uint c, uint idx);
float pixel(uint idx) const; float pixel(uint idx) const;
float & pixel(uint idx); float & pixel(uint idx);
float sampleNearest(float x, float y, int c, WrapMode wm) const; float sampleNearest(uint c, float x, float y, WrapMode wm) const;
float sampleLinear(float x, float y, int c, WrapMode wm) const; float sampleLinear(uint c, float x, float y, WrapMode wm) const;
float sampleNearest(uint c, float x, float y, float z, WrapMode wm) const;
float sampleLinear(uint c, float x, float y, float z, WrapMode wm) const;
float sampleNearestClamp(uint c, float x, float y) const;
float sampleNearestRepeat(uint c, float x, float y) const;
float sampleNearestMirror(uint c, float x, float y) const;
float sampleNearestClamp(float x, float y, int c) const; float sampleNearestClamp(uint c, float x, float y, float z) const;
float sampleNearestRepeat(float x, float y, int c) const; float sampleNearestRepeat(uint c, float x, float y, float z) const;
float sampleNearestMirror(float x, float y, int c) const; float sampleNearestMirror(uint c, float x, float y, float z) const;
float sampleLinearClamp(float x, float y, int c) const; float sampleLinearClamp(uint c, float x, float y) const;
float sampleLinearRepeat(float x, float y, int c) const; float sampleLinearRepeat(uint c, float x, float y) const;
float sampleLinearMirror(float x, float y, int c) const; float sampleLinearMirror(uint c, float x, float y) const;
float sampleLinearClamp(uint c, float x, float y, float z) const;
float sampleLinearRepeat(uint c, float x, float y, float z) const;
float sampleLinearMirror(uint c, float x, float y, float z) const;
//@} //@}
@ -134,18 +166,23 @@ namespace nv
public: public:
uint index(uint x, uint y) const; uint index(uint x, uint y, uint z) const;
uint indexClamp(int x, int y) const; uint indexClamp(int x, int y, int z) const;
uint indexRepeat(int x, int y) const; uint indexRepeat(int x, int y, int z) const;
uint indexMirror(int x, int y) const; uint indexMirror(int x, int y, int z) const;
uint index(int x, int y, WrapMode wm) const; uint index(int x, int y, int z, WrapMode wm) const;
float bilerp(uint c, int ix0, int iy0, int ix1, int iy1, float fx, float fy) const;
float trilerp(uint c, int ix0, int iy0, int iz0, int ix1, int iy1, int iz1, float fx, float fy, float fz) const;
public: public:
uint16 m_width; ///< Width of the texture. uint16 m_componentCount;
uint16 m_height; ///< Height of the texture. uint16 m_width;
uint32 m_componentNum; ///< Number of components. uint16 m_height;
uint32 m_count; ///< Image pixel count. uint16 m_depth;
uint32 m_pixelCount;
uint32 m_floatCount;
float * m_mem; float * m_mem;
}; };
@ -155,132 +192,202 @@ namespace nv
inline const float * FloatImage::channel(uint c) const inline const float * FloatImage::channel(uint c) const
{ {
nvDebugCheck(m_mem != NULL); nvDebugCheck(m_mem != NULL);
nvDebugCheck(c < m_componentNum); nvDebugCheck(c < m_componentCount);
return m_mem + c * m_width * m_height; return m_mem + c * m_pixelCount;
} }
/// Get channel pointer. /// Get channel pointer.
inline float * FloatImage::channel(uint c) { inline float * FloatImage::channel(uint c) {
nvDebugCheck(m_mem != NULL); nvDebugCheck(m_mem != NULL);
nvDebugCheck(c < m_componentNum); nvDebugCheck(c < m_componentCount);
return m_mem + c * m_width * m_height; return m_mem + c * m_pixelCount;
}
inline const float * FloatImage::plane(uint c, uint z) const {
nvDebugCheck(z < m_depth);
return channel(c) + z * m_width * m_height;
}
inline float * FloatImage::plane(uint c, uint z) {
nvDebugCheck(z < m_depth);
return channel(c) + z * m_width * m_height;
} }
/// Get const scanline pointer. /// Get const scanline pointer.
inline const float * FloatImage::scanline(uint y, uint c) const inline const float * FloatImage::scanline(uint c, uint y, uint z) const
{ {
nvDebugCheck(y < m_height); nvDebugCheck(y < m_height);
return channel(c) + y * m_width; return plane(c, z) + y * m_width;
} }
/// Get scanline pointer. /// Get scanline pointer.
inline float * FloatImage::scanline(uint y, uint c) inline float * FloatImage::scanline(uint z, uint y, uint c)
{ {
nvDebugCheck(y < m_height); nvDebugCheck(y < m_height);
return channel(c) + y * m_width; return plane(c, z) + y * m_width;
} }
/// Get pixel component. /// Get pixel component.
inline float FloatImage::pixel(uint x, uint y, uint c) const inline float FloatImage::pixel(uint c, uint x, uint y, uint z) const
{ {
nvDebugCheck(m_mem != NULL); nvDebugCheck(m_mem != NULL);
nvDebugCheck(c < m_componentCount);
nvDebugCheck(x < m_width); nvDebugCheck(x < m_width);
nvDebugCheck(y < m_height); nvDebugCheck(y < m_height);
nvDebugCheck(c < m_componentNum); nvDebugCheck(z < m_depth);
return m_mem[(c * m_height + y) * m_width + x]; return m_mem[((c * m_depth + z) * m_height + y) * m_width + x];
} }
/// Get pixel component. /// Get pixel component.
inline float & FloatImage::pixel(uint x, uint y, uint c) inline float & FloatImage::pixel(uint c, uint x, uint y, uint z)
{ {
nvDebugCheck(m_mem != NULL); nvDebugCheck(m_mem != NULL);
nvDebugCheck(c < m_componentCount);
nvDebugCheck(x < m_width); nvDebugCheck(x < m_width);
nvDebugCheck(y < m_height); nvDebugCheck(y < m_height);
nvDebugCheck(c < m_componentNum); nvDebugCheck(z < m_depth);
return m_mem[(c * m_height + y) * m_width + x]; return m_mem[((c * m_depth + z) * m_height + y) * m_width + x];
} }
/// Get pixel component. /// Get pixel component.
inline float FloatImage::pixel(uint idx, uint c) const inline float FloatImage::pixel(uint c, uint idx) const
{ {
nvDebugCheck(m_mem != NULL); nvDebugCheck(m_mem != NULL);
nvDebugCheck(idx < uint(m_width*m_height)); nvDebugCheck(c < m_componentCount);
nvDebugCheck(c < m_componentNum); nvDebugCheck(idx < m_pixelCount);
return m_mem[c * m_height * m_width + idx]; return m_mem[c * m_height * m_width + idx];
} }
/// Get pixel component. /// Get pixel component.
inline float & FloatImage::pixel(uint idx, uint c) inline float & FloatImage::pixel(uint c, uint idx)
{ {
nvDebugCheck(m_mem != NULL); nvDebugCheck(m_mem != NULL);
nvDebugCheck(idx < uint(m_width*m_height)); nvDebugCheck(c < m_componentCount);
nvDebugCheck(c < m_componentNum); nvDebugCheck(idx < m_pixelCount);
return m_mem[c * m_height * m_width + idx]; return m_mem[c * m_height * m_width + idx];
} }
/// Get pixel component. /// Get pixel component.
inline float FloatImage::pixel(uint idx) const inline float FloatImage::pixel(uint idx) const
{ {
nvDebugCheck(idx < m_count); nvDebugCheck(m_mem != NULL);
nvDebugCheck(idx < m_floatCount);
return m_mem[idx]; return m_mem[idx];
} }
/// Get pixel component. /// Get pixel component.
inline float & FloatImage::pixel(uint idx) inline float & FloatImage::pixel(uint idx)
{ {
nvDebugCheck(idx < m_count); nvDebugCheck(m_mem != NULL);
nvDebugCheck(idx < m_floatCount);
return m_mem[idx]; return m_mem[idx];
} }
inline uint FloatImage::index(uint x, uint y) const inline uint FloatImage::index(uint x, uint y, uint z) const
{ {
nvDebugCheck(x < m_width); nvDebugCheck(x < m_width);
nvDebugCheck(y < m_height); nvDebugCheck(y < m_height);
return y * m_width + x; nvDebugCheck(z < m_depth);
return (z * m_height + y) * m_width + x;
} }
inline uint FloatImage::indexClamp(int x, int y) const
inline int wrapClamp(int x, int w)
{
return nv::clamp(x, 0, w - 1);
}
inline int wrapRepeat(int x, int w)
{ {
return nv::clamp(y, int(0), int(m_height-1)) * m_width + nv::clamp(x, int(0), int(m_width-1)); if (x >= 0) return x % w;
else return (x + 1) % w + w - 1;
} }
inline int wrapMirror(int x, int w)
{
if (w == 1) x = 0;
inline int repeat_remainder(int a, int b) x = abs(x);
while (x >= w) {
x = abs(w + w - x - 2);
}
return x;
}
inline uint FloatImage::indexClamp(int x, int y, int z) const
{ {
if (a >= 0) return a % b; x = wrapClamp(x, m_width - 1);
else return (a + 1) % b + b - 1; y = wrapClamp(y, m_height - 1);
z = wrapClamp(z, m_depth - 1);
return index(x, y, z);
} }
inline uint FloatImage::indexRepeat(int x, int y) const
inline uint FloatImage::indexRepeat(int x, int y, int z) const
{ {
return repeat_remainder(y, m_height) * m_width + repeat_remainder(x, m_width); x = wrapRepeat(x, m_width);
y = wrapRepeat(y, m_height);
z = wrapRepeat(z, m_depth);
return index(x, y, z);
}
inline uint FloatImage::indexMirror(int x, int y, int z) const
{
x = wrapMirror(x, m_width);
y = wrapMirror(y, m_height);
z = wrapMirror(z, m_depth);
return index(x, y, z);
} }
inline uint FloatImage::indexMirror(int x, int y) const inline uint FloatImage::index(int x, int y, int z, WrapMode wm) const
{ {
if (m_width == 1) x = 0; if (wm == WrapMode_Clamp) return indexClamp(x, y, z);
if (wm == WrapMode_Repeat) return indexRepeat(x, y, z);
/*if (wm == WrapMode_Mirror)*/ return indexMirror(x, y, z);
}
x = abs(x); inline float FloatImage::bilerp(uint c, int ix0, int iy0, int ix1, int iy1, float fx, float fy) const {
while (x >= m_width) { int iz = 0;
x = abs(m_width + m_width - x - 2); float f1 = pixel(c, ix0, iy0, iz);
} float f2 = pixel(c, ix1, iy0, iz);
float f3 = pixel(c, ix0, iy1, iz);
float f4 = pixel(c, ix1, iy1, iz);
if (m_height == 1) y = 0; float i1 = lerp(f1, f2, fx);
float i2 = lerp(f3, f4, fx);
y = abs(y); return lerp(i1, i2, fy);
while (y >= m_height) { }
y = abs(m_height + m_height - y - 2);
}
return index(x, y); inline float FloatImage::trilerp(uint c, int ix0, int iy0, int iz0, int ix1, int iy1, int iz1, float fx, float fy, float fz) const {
float f000 = pixel(c, ix0, iy0, iz0);
float f100 = pixel(c, ix1, iy0, iz0);
float f010 = pixel(c, ix0, iy1, iz0);
float f110 = pixel(c, ix1, iy1, iz0);
float f001 = pixel(c, ix0, iy0, iz1);
float f101 = pixel(c, ix1, iy0, iz1);
float f011 = pixel(c, ix0, iy1, iz1);
float f111 = pixel(c, ix1, iy1, iz1);
float i1 = lerp(f000, f001, fz);
float i2 = lerp(f010, f011, fz);
float j1 = lerp(f100, f101, fz);
float j2 = lerp(f110, f111, fz);
float w1 = lerp(i1, i2, fy);
float w2 = lerp(j1, j2, fy);
return lerp(w1, w2, fx);
} }
inline uint FloatImage::index(int x, int y, WrapMode wm) const // Does not compare channel count.
{ inline bool sameLayout(const FloatImage * img0, const FloatImage * img1) {
if (wm == WrapMode_Clamp) return indexClamp(x, y); if (img0 == NULL || img1 == NULL) return false;
if (wm == WrapMode_Repeat) return indexRepeat(x, y); return img0->width() == img1->width() && img0->height() == img1->height() && img0->depth() == img1->depth();
/*if (wm == WrapMode_Mirror)*/ return indexMirror(x, y);
} }
} // nv namespace } // nv namespace

@ -18,9 +18,9 @@ Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL)
Image::Image(const Image & img) : m_data(NULL) Image::Image(const Image & img) : m_data(NULL)
{ {
allocate(img.m_width, img.m_height); allocate(img.m_width, img.m_height, img.m_depth);
m_format = img.m_format; m_format = img.m_format;
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height); memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height * m_depth);
} }
Image::~Image() Image::~Image()
@ -30,19 +30,20 @@ Image::~Image()
const Image & Image::operator=(const Image & img) const Image & Image::operator=(const Image & img)
{ {
allocate(img.m_width, img.m_height); allocate(img.m_width, img.m_height, m_depth);
m_format = img.m_format; m_format = img.m_format;
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height); memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height * m_depth);
return *this; return *this;
} }
void Image::allocate(uint w, uint h) void Image::allocate(uint w, uint h, uint d)
{ {
free(); free();
m_width = w; m_width = w;
m_height = h; m_height = h;
m_data = realloc<Color32>(m_data, w * h); m_depth = d;
m_data = realloc<Color32>(m_data, w * h * d);
} }
bool Image::load(const char * name) bool Image::load(const char * name)
@ -56,18 +57,20 @@ bool Image::load(const char * name)
swap(m_width, img->m_width); swap(m_width, img->m_width);
swap(m_height, img->m_height); swap(m_height, img->m_height);
swap(m_depth, img->m_depth);
swap(m_format, img->m_format); swap(m_format, img->m_format);
swap(m_data, img->m_data); swap(m_data, img->m_data);
return true; return true;
} }
void Image::wrap(void * data, uint w, uint h) void Image::wrap(void * data, uint w, uint h, uint d)
{ {
free(); free();
m_data = (Color32 *)data; m_data = (Color32 *)data;
m_width = w; m_width = w;
m_height = h; m_height = h;
m_depth = d;
} }
void Image::unwrap() void Image::unwrap()
@ -75,6 +78,7 @@ void Image::unwrap()
m_data = NULL; m_data = NULL;
m_width = 0; m_width = 0;
m_height = 0; m_height = 0;
m_depth = 0;
} }
@ -95,6 +99,11 @@ uint Image::height() const
return m_height; return m_height;
} }
uint Image::depth() const
{
return m_depth;
}
const Color32 * Image::scanline(uint h) const const Color32 * Image::scanline(uint h) const
{ {
nvDebugCheck(h < m_height); nvDebugCheck(h < m_height);
@ -119,13 +128,13 @@ Color32 * Image::pixels()
const Color32 & Image::pixel(uint idx) const const Color32 & Image::pixel(uint idx) const
{ {
nvDebugCheck(idx < m_width * m_height); nvDebugCheck(idx < m_width * m_height * m_depth);
return m_data[idx]; return m_data[idx];
} }
Color32 & Image::pixel(uint idx) Color32 & Image::pixel(uint idx)
{ {
nvDebugCheck(idx < m_width * m_height); nvDebugCheck(idx < m_width * m_height * m_depth);
return m_data[idx]; return m_data[idx];
} }
@ -142,7 +151,7 @@ void Image::setFormat(Image::Format f)
void Image::fill(Color32 c) void Image::fill(Color32 c)
{ {
const uint size = m_width * m_height; const uint size = m_width * m_height * m_depth;
for (uint i = 0; i < size; ++i) for (uint i = 0; i < size; ++i)
{ {
m_data[i] = c; m_data[i] = c;

@ -29,14 +29,15 @@ namespace nv
const Image & operator=(const Image & img); const Image & operator=(const Image & img);
void allocate(uint w, uint h); void allocate(uint w, uint h, uint d = 1);
bool load(const char * name); bool load(const char * name);
void wrap(void * data, uint w, uint h); void wrap(void * data, uint w, uint h, uint d = 1);
void unwrap(); void unwrap();
uint width() const; uint width() const;
uint height() const; uint height() const;
uint depth() const;
const Color32 * scanline(uint h) const; const Color32 * scanline(uint h) const;
Color32 * scanline(uint h); Color32 * scanline(uint h);
@ -61,6 +62,7 @@ namespace nv
private: private:
uint m_width; uint m_width;
uint m_height; uint m_height;
uint m_depth;
Format m_format; Format m_format;
Color32 * m_data; Color32 * m_data;
}; };

@ -275,9 +275,9 @@ bool nv::ImageIO::saveFloat(const char * fileName, Stream & s, const FloatImage
{ {
if (componentCount == 0) if (componentCount == 0)
{ {
componentCount = fimage->componentNum() - baseComponent; componentCount = fimage->componentCount() - baseComponent;
} }
if (baseComponent + componentCount < fimage->componentNum()) if (baseComponent + componentCount < fimage->componentCount())
{ {
return false; return false;
} }
@ -430,7 +430,7 @@ Image * nv::ImageIO::loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s)
Image * image = new Image(); Image * image = new Image();
image->allocate(w, h); image->allocate(w, h, 1); // freeimage can only load 2d images:
// Copy the image over to our internal format, FreeImage has the scanlines bottom to top though. // Copy the image over to our internal format, FreeImage has the scanlines bottom to top though.
for (int y=0; y < h; y++) for (int y=0; y < h; y++)
@ -1575,7 +1575,7 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage
{ {
nvCheck(fileName != NULL); nvCheck(fileName != NULL);
nvCheck(fimage != NULL); nvCheck(fimage != NULL);
nvCheck(base_component + num_components <= fimage->componentNum()); nvCheck(base_component + num_components <= fimage->componentCount());
const int iW = fimage->width(); const int iW = fimage->width();
const int iH = fimage->height(); const int iH = fimage->height();
@ -1740,7 +1740,7 @@ bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage,
{ {
nvCheck(fileName != NULL); nvCheck(fileName != NULL);
nvCheck(fimage != NULL); nvCheck(fimage != NULL);
nvCheck(base_component + num_components <= fimage->componentNum()); nvCheck(base_component + num_components <= fimage->componentCount());
nvCheck(num_components > 0 && num_components <= 4); nvCheck(num_components > 0 && num_components <= 4);
const int w = fimage->width(); const int w = fimage->width();

@ -36,172 +36,172 @@ using namespace nv;
// Create normal map using the given kernels. // Create normal map using the given kernels.
static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, const Kernel2 * kdu, const Kernel2 * kdv) static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, const Kernel2 * kdu, const Kernel2 * kdv)
{ {
nvDebugCheck(kdu != NULL); nvDebugCheck(kdu != NULL);
nvDebugCheck(kdv != NULL); nvDebugCheck(kdv != NULL);
nvDebugCheck(img != NULL); nvDebugCheck(img != NULL);
const uint w = img->width(); const uint w = img->width();
const uint h = img->height(); const uint h = img->height();
AutoPtr<FloatImage> fimage(new FloatImage()); AutoPtr<FloatImage> fimage(new FloatImage());
fimage->allocate(4, w, h); fimage->allocate(4, w, h);
// Compute height and store in alpha channel: // Compute height and store in alpha channel:
float * alphaChannel = fimage->channel(3); float * alphaChannel = fimage->channel(3);
for(uint i = 0; i < w*h; i++) for(uint i = 0; i < w * h; i++)
{ {
Vector4 color = toVector4(img->pixel(i)); Vector4 color = toVector4(img->pixel(i));
alphaChannel[i] = dot(color, heightWeights); alphaChannel[i] = dot(color, heightWeights);
} }
float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor. float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor.
for(uint y = 0; y < h; y++) for(uint y = 0; y < h; y++)
{ {
for(uint x = 0; x < w; x++) for(uint x = 0; x < w; x++)
{ {
const float du = fimage->applyKernel(kdu, x, y, 3, wm); const float du = fimage->applyKernelXY(kdu, x, y, 0, 3, wm);
const float dv = fimage->applyKernel(kdv, x, y, 3, wm); const float dv = fimage->applyKernelXY(kdv, x, y, 0, 3, wm);
Vector3 n = normalize(Vector3(du, dv, heightScale)); Vector3 n = normalize(Vector3(du, dv, heightScale));
fimage->pixel(x, y, 0) = 0.5f * n.x + 0.5f; fimage->pixel(x, y, 0, 0) = 0.5f * n.x + 0.5f;
fimage->pixel(x, y, 1) = 0.5f * n.y + 0.5f; fimage->pixel(x, y, 0, 1) = 0.5f * n.y + 0.5f;
fimage->pixel(x, y, 2) = 0.5f * n.z + 0.5f; fimage->pixel(x, y, 0, 2) = 0.5f * n.z + 0.5f;
} }
} }
return fimage.release(); return fimage.release();
} }
// Create normal map using the given kernels. // Create normal map using the given kernels.
static FloatImage * createNormalMap(const FloatImage * img, FloatImage::WrapMode wm, const Kernel2 * kdu, const Kernel2 * kdv) static FloatImage * createNormalMap(const FloatImage * img, FloatImage::WrapMode wm, const Kernel2 * kdu, const Kernel2 * kdv)
{ {
nvDebugCheck(kdu != NULL); nvDebugCheck(kdu != NULL);
nvDebugCheck(kdv != NULL); nvDebugCheck(kdv != NULL);
nvDebugCheck(img != NULL); nvDebugCheck(img != NULL);
#pragma NV_MESSAGE("FIXME: Height scale parameter should go away. It should be a sensible value that produces good results when the heightmap is in the [0, 1] range.") #pragma NV_MESSAGE("FIXME: Height scale parameter should go away. It should be a sensible value that produces good results when the heightmap is in the [0, 1] range.")
const float heightScale = 1.0f / 16.0f; const float heightScale = 1.0f / 16.0f;
const uint w = img->width(); const uint w = img->width();
const uint h = img->height(); const uint h = img->height();
AutoPtr<FloatImage> img_out(new FloatImage()); AutoPtr<FloatImage> img_out(new FloatImage());
img_out->allocate(4, w, h); img_out->allocate(4, w, h);
for (uint y = 0; y < h; y++) for (uint y = 0; y < h; y++)
{ {
for (uint x = 0; x < w; x++) for (uint x = 0; x < w; x++)
{ {
const float du = img->applyKernel(kdu, x, y, 3, wm); const float du = img->applyKernelXY(kdu, x, y, 0, 3, wm);
const float dv = img->applyKernel(kdv, x, y, 3, wm); const float dv = img->applyKernelXY(kdv, x, y, 0, 3, wm);
Vector3 n = normalize(Vector3(du, dv, heightScale)); Vector3 n = normalize(Vector3(du, dv, heightScale));
img_out->pixel(x, y, 0) = n.x; img_out->pixel(x, y, 0, 0) = n.x;
img_out->pixel(x, y, 1) = n.y; img_out->pixel(x, y, 0, 1) = n.y;
img_out->pixel(x, y, 2) = n.z; img_out->pixel(x, y, 0, 2) = n.z;
}
} }
}
// Copy alpha channel.
for (uint y = 0; y < h; y++) // Copy alpha channel.
{ for (uint y = 0; y < h; y++)
for (uint x = 0; x < w; x++) {
{ for (uint x = 0; x < w; x++)
img_out->pixel(x, y, 3) = img->pixel(x, y, 3); {
} img_out->pixel(x, y, 0, 3) = img->pixel(x, y, 0, 3);
} }
}
return img_out.release();
return img_out.release();
} }
/// Create normal map using the given filter. /// Create normal map using the given filter.
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/) FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/)
{ {
nvDebugCheck(img != NULL); nvDebugCheck(img != NULL);
// Init the kernels. // Init the kernels.
Kernel2 * kdu = NULL; Kernel2 * kdu = NULL;
Kernel2 * kdv = NULL; Kernel2 * kdv = NULL;
switch(filter) switch(filter)
{ {
case NormalMapFilter_Sobel3x3: case NormalMapFilter_Sobel3x3:
kdu = new Kernel2(3); kdu = new Kernel2(3);
break; break;
case NormalMapFilter_Sobel5x5: case NormalMapFilter_Sobel5x5:
kdu = new Kernel2(5); kdu = new Kernel2(5);
break; break;
case NormalMapFilter_Sobel7x7: case NormalMapFilter_Sobel7x7:
kdu = new Kernel2(7); kdu = new Kernel2(7);
break; break;
case NormalMapFilter_Sobel9x9: case NormalMapFilter_Sobel9x9:
kdu = new Kernel2(9); kdu = new Kernel2(9);
break; break;
default: default:
nvDebugCheck(false); nvDebugCheck(false);
}; };
kdu->initSobel(); kdu->initSobel();
kdu->normalize(); kdu->normalize();
kdv = new Kernel2(*kdu); kdv = new Kernel2(*kdu);
kdv->transpose(); kdv->transpose();
return ::createNormalMap(img, wm, heightWeights, kdu, kdv); return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
} }
/// Create normal map combining multiple sobel filters. /// Create normal map combining multiple sobel filters.
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights) FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights)
{ {
nvDebugCheck(img != NULL); nvDebugCheck(img != NULL);
Kernel2 * kdu = NULL; Kernel2 * kdu = NULL;
Kernel2 * kdv = NULL; Kernel2 * kdv = NULL;
kdu = new Kernel2(9); kdu = new Kernel2(9);
kdu->initBlendedSobel(filterWeights); kdu->initBlendedSobel(filterWeights);
kdu->normalize(); kdu->normalize();
kdv = new Kernel2(*kdu); kdv = new Kernel2(*kdu);
kdv->transpose(); kdv->transpose();
return ::createNormalMap(img, wm, heightWeights, kdu, kdv); return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
} }
FloatImage * nv::createNormalMap(const FloatImage * img, FloatImage::WrapMode wm, Vector4::Arg filterWeights) FloatImage * nv::createNormalMap(const FloatImage * img, FloatImage::WrapMode wm, Vector4::Arg filterWeights)
{ {
nvDebugCheck(img != NULL); nvDebugCheck(img != NULL);
Kernel2 * kdu = NULL; Kernel2 * kdu = NULL;
Kernel2 * kdv = NULL; Kernel2 * kdv = NULL;
kdu = new Kernel2(9); kdu = new Kernel2(9);
kdu->initBlendedSobel(filterWeights); kdu->initBlendedSobel(filterWeights);
kdu->normalize(); kdu->normalize();
kdv = new Kernel2(*kdu); kdv = new Kernel2(*kdu);
kdv->transpose(); kdv->transpose();
return ::createNormalMap(img, wm, kdu, kdv); return ::createNormalMap(img, wm, kdu, kdv);
} }
/// Normalize the given image in place. /// Normalize the given image in place.
void nv::normalizeNormalMap(FloatImage * img) void nv::normalizeNormalMap(FloatImage * img)
{ {
nvDebugCheck(img != NULL); nvDebugCheck(img != NULL);
#pragma NV_MESSAGE("TODO: Pack and expand normals explicitly?") #pragma NV_MESSAGE("TODO: Pack and expand normals explicitly?")
img->expandNormals(0); img->expandNormals(0);
img->normalize(0); img->normalize(0);
img->packNormals(0); img->packNormals(0);
} }

@ -33,7 +33,7 @@ namespace nv
struct CompressorInterface struct CompressorInterface
{ {
virtual ~CompressorInterface() {} virtual ~CompressorInterface() {}
virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * rgba, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) = 0; virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * rgba, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) = 0;
}; };
} // nv namespace } // nv namespace

@ -301,214 +301,132 @@ void NormalCompressorDXT5n::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alp
} }
#if defined(HAVE_S3QUANT)
void S3CompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{
float error = 0.0f;
BlockDXT1 dxtBlock3;
BlockDXT1 dxtBlock4;
ColorBlock block;
for (uint y = 0; y < h; y += 4) {
for (uint x = 0; x < w; x += 4) {
block.init(inputFormat, w, h, data, x, y);
// Init rgb block.
RGBBlock rgbBlock;
rgbBlock.n = 16;
for (uint i = 0; i < 16; i++) {
rgbBlock.colorChannel[i][0] = clamp(float(block.color(i).r) / 255.0f, 0.0f, 1.0f);
rgbBlock.colorChannel[i][1] = clamp(float(block.color(i).g) / 255.0f, 0.0f, 1.0f);
rgbBlock.colorChannel[i][2] = clamp(float(block.color(i).b) / 255.0f, 0.0f, 1.0f);
}
rgbBlock.weight[0] = 1.0f;
rgbBlock.weight[1] = 1.0f;
rgbBlock.weight[2] = 1.0f;
rgbBlock.inLevel = 4;
CodeRGBBlock(&rgbBlock);
// Copy results to DXT block.
dxtBlock4.col0.r = rgbBlock.endPoint[0][0];
dxtBlock4.col0.g = rgbBlock.endPoint[0][1];
dxtBlock4.col0.b = rgbBlock.endPoint[0][2];
dxtBlock4.col1.r = rgbBlock.endPoint[1][0];
dxtBlock4.col1.g = rgbBlock.endPoint[1][1];
dxtBlock4.col1.b = rgbBlock.endPoint[1][2];
dxtBlock4.setIndices(rgbBlock.index);
if (dxtBlock4.col0.u < dxtBlock4.col1.u) {
swap(dxtBlock4.col0.u, dxtBlock4.col1.u);
dxtBlock4.indices ^= 0x55555555;
}
uint error4 = blockError(block, dxtBlock4);
rgbBlock.inLevel = 3;
CodeRGBBlock(&rgbBlock);
// Copy results to DXT block.
dxtBlock3.col0.r = rgbBlock.endPoint[0][0];
dxtBlock3.col0.g = rgbBlock.endPoint[0][1];
dxtBlock3.col0.b = rgbBlock.endPoint[0][2];
dxtBlock3.col1.r = rgbBlock.endPoint[1][0];
dxtBlock3.col1.g = rgbBlock.endPoint[1][1];
dxtBlock3.col1.b = rgbBlock.endPoint[1][2];
dxtBlock3.setIndices(rgbBlock.index);
if (dxtBlock3.col0.u > dxtBlock3.col1.u) {
swap(dxtBlock3.col0.u, dxtBlock3.col1.u);
dxtBlock3.indices ^= (~dxtBlock3.indices >> 1) & 0x55555555;
}
uint error3 = blockError(block, dxtBlock3);
if (error3 < error4) {
error += error3;
if (outputOptions.outputHandler != NULL) {
outputOptions.outputHandler->writeData(&dxtBlock3, sizeof(dxtBlock3));
}
}
else {
error += error4;
if (outputOptions.outputHandler != NULL) {
outputOptions.outputHandler->writeData(&dxtBlock4, sizeof(dxtBlock4));
}
}
}
}
}
#endif // defined(HAVE_S3QUANT)
#if defined(HAVE_ATITC) #if defined(HAVE_ATITC)
void AtiCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void AtiCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
// Init source texture nvDebugCheck(d == 1);
ATI_TC_Texture srcTexture;
srcTexture.dwSize = sizeof(srcTexture); // Init source texture
srcTexture.dwWidth = w; ATI_TC_Texture srcTexture;
srcTexture.dwHeight = h; srcTexture.dwSize = sizeof(srcTexture);
if (inputFormat == nvtt::InputFormat_BGRA_8UB) srcTexture.dwWidth = w;
{ srcTexture.dwHeight = h;
srcTexture.dwPitch = w * 4; if (inputFormat == nvtt::InputFormat_BGRA_8UB)
srcTexture.format = ATI_TC_FORMAT_ARGB_8888; {
} srcTexture.dwPitch = w * 4;
else srcTexture.format = ATI_TC_FORMAT_ARGB_8888;
{ }
srcTexture.dwPitch = w * 16; else
srcTexture.format = ATI_TC_FORMAT_ARGB_32F; {
} // @@ Floating point input is not swizzled.
srcTexture.dwDataSize = ATI_TC_CalculateBufferSize(&srcTexture); srcTexture.dwPitch = w * 16;
srcTexture.pData = (ATI_TC_BYTE*) data; srcTexture.format = ATI_TC_FORMAT_ARGB_32F;
}
// Init dest texture srcTexture.dwDataSize = ATI_TC_CalculateBufferSize(&srcTexture);
ATI_TC_Texture destTexture; srcTexture.pData = (ATI_TC_BYTE*) data;
destTexture.dwSize = sizeof(destTexture);
destTexture.dwWidth = w; // Init dest texture
destTexture.dwHeight = h; ATI_TC_Texture destTexture;
destTexture.dwPitch = 0; destTexture.dwSize = sizeof(destTexture);
destTexture.format = ATI_TC_FORMAT_DXT1; destTexture.dwWidth = w;
destTexture.dwDataSize = ATI_TC_CalculateBufferSize(&destTexture); destTexture.dwHeight = h;
destTexture.pData = (ATI_TC_BYTE*) mem::malloc(destTexture.dwDataSize); destTexture.dwPitch = 0;
destTexture.format = ATI_TC_FORMAT_DXT1;
ATI_TC_CompressOptions options; destTexture.dwDataSize = ATI_TC_CalculateBufferSize(&destTexture);
options.dwSize = sizeof(options); destTexture.pData = (ATI_TC_BYTE*) mem::malloc(destTexture.dwDataSize);
options.bUseChannelWeighting = false;
options.bUseAdaptiveWeighting = false; ATI_TC_CompressOptions options;
options.bDXT1UseAlpha = false; options.dwSize = sizeof(options);
options.nCompressionSpeed = ATI_TC_Speed_Normal; options.bUseChannelWeighting = false;
options.bDisableMultiThreading = false; options.bUseAdaptiveWeighting = false;
//options.bDisableMultiThreading = true; options.bDXT1UseAlpha = false;
options.nCompressionSpeed = ATI_TC_Speed_Normal;
// Compress options.bDisableMultiThreading = false;
ATI_TC_ConvertTexture(&srcTexture, &destTexture, &options, NULL, NULL, NULL); //options.bDisableMultiThreading = true;
if (outputOptions.outputHandler != NULL) { // Compress
outputOptions.outputHandler->writeData(destTexture.pData, destTexture.dwDataSize); ATI_TC_ConvertTexture(&srcTexture, &destTexture, &options, NULL, NULL, NULL);
}
if (outputOptions.outputHandler != NULL) {
mem::free(destTexture.pData); outputOptions.outputHandler->writeData(destTexture.pData, destTexture.dwDataSize);
}
mem::free(destTexture.pData);
} }
void AtiCompressorDXT5::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void AtiCompressorDXT5::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
// Init source texture nvDebugCheck(d == 1);
ATI_TC_Texture srcTexture;
srcTexture.dwSize = sizeof(srcTexture); // Init source texture
srcTexture.dwWidth = w; ATI_TC_Texture srcTexture;
srcTexture.dwHeight = h; srcTexture.dwSize = sizeof(srcTexture);
if (inputFormat == nvtt::InputFormat_BGRA_8UB) srcTexture.dwWidth = w;
{ srcTexture.dwHeight = h;
srcTexture.dwPitch = w * 4; if (inputFormat == nvtt::InputFormat_BGRA_8UB)
srcTexture.format = ATI_TC_FORMAT_ARGB_8888; {
} srcTexture.dwPitch = w * 4;
else srcTexture.format = ATI_TC_FORMAT_ARGB_8888;
{ }
srcTexture.dwPitch = w * 16; else
srcTexture.format = ATI_TC_FORMAT_ARGB_32F; {
} srcTexture.dwPitch = w * 16;
srcTexture.dwDataSize = ATI_TC_CalculateBufferSize(&srcTexture); srcTexture.format = ATI_TC_FORMAT_ARGB_32F;
srcTexture.pData = (ATI_TC_BYTE*) data; }
srcTexture.dwDataSize = ATI_TC_CalculateBufferSize(&srcTexture);
// Init dest texture srcTexture.pData = (ATI_TC_BYTE*) data;
ATI_TC_Texture destTexture;
destTexture.dwSize = sizeof(destTexture); // Init dest texture
destTexture.dwWidth = w; ATI_TC_Texture destTexture;
destTexture.dwHeight = h; destTexture.dwSize = sizeof(destTexture);
destTexture.dwPitch = 0; destTexture.dwWidth = w;
destTexture.format = ATI_TC_FORMAT_DXT5; destTexture.dwHeight = h;
destTexture.dwDataSize = ATI_TC_CalculateBufferSize(&destTexture); destTexture.dwPitch = 0;
destTexture.pData = (ATI_TC_BYTE*) mem::malloc(destTexture.dwDataSize); destTexture.format = ATI_TC_FORMAT_DXT5;
destTexture.dwDataSize = ATI_TC_CalculateBufferSize(&destTexture);
// Compress destTexture.pData = (ATI_TC_BYTE*) mem::malloc(destTexture.dwDataSize);
ATI_TC_ConvertTexture(&srcTexture, &destTexture, NULL, NULL, NULL, NULL);
// Compress
if (outputOptions.outputHandler != NULL) { ATI_TC_ConvertTexture(&srcTexture, &destTexture, NULL, NULL, NULL, NULL);
outputOptions.outputHandler->writeData(destTexture.pData, destTexture.dwDataSize);
} if (outputOptions.outputHandler != NULL) {
outputOptions.outputHandler->writeData(destTexture.pData, destTexture.dwDataSize);
mem::free(destTexture.pData); }
mem::free(destTexture.pData);
} }
#endif // defined(HAVE_ATITC) #endif // defined(HAVE_ATITC)
#if defined(HAVE_SQUISH) #if defined(HAVE_SQUISH)
void SquishCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void SquishCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
#pragma message(NV_FILE_LINE "TODO: Convert input to fixed point ABGR format instead of ARGB") nvDebugCheck(d == 1);
/* nvDebugCheck(false);
Image img(*image);
int count = img.width() * img.height();
for (int i = 0; i < count; i++)
{
Color32 c = img.pixel(i);
img.pixel(i) = Color32(c.b, c.g, c.r, c.a);
}
int size = squish::GetStorageRequirements(img.width(), img.height(), squish::kDxt1);
void * blocks = mem::malloc(size);
squish::CompressImage((const squish::u8 *)img.pixels(), img.width(), img.height(), blocks, squish::kDxt1 | squish::kColourClusterFit); #pragma message(NV_FILE_LINE "TODO: Convert input to fixed point ABGR format instead of ARGB")
/*
if (outputOptions.outputHandler != NULL) { Image img(*image);
outputOptions.outputHandler->writeData(blocks, size); int count = img.width() * img.height();
} for (int i = 0; i < count; i++)
{
mem::free(blocks); Color32 c = img.pixel(i);
*/ img.pixel(i) = Color32(c.b, c.g, c.r, c.a);
}
int size = squish::GetStorageRequirements(img.width(), img.height(), squish::kDxt1);
void * blocks = mem::malloc(size);
squish::CompressImage((const squish::u8 *)img.pixels(), img.width(), img.height(), blocks, squish::kDxt1 | squish::kColourClusterFit);
if (outputOptions.outputHandler != NULL) {
outputOptions.outputHandler->writeData(blocks, size);
}
mem::free(blocks);
*/
} }
#endif // defined(HAVE_SQUISH) #endif // defined(HAVE_SQUISH)
@ -516,62 +434,64 @@ void SquishCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo
#if defined(HAVE_D3DX) #if defined(HAVE_D3DX)
void D3DXCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void D3DXCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
IDirect3D9 * d3d = Direct3DCreate9(D3D_SDK_VERSION); nvDebugCheck(d == 1);
D3DPRESENT_PARAMETERS presentParams; IDirect3D9 * d3d = Direct3DCreate9(D3D_SDK_VERSION);
ZeroMemory(&presentParams, sizeof(presentParams));
presentParams.Windowed = TRUE;
presentParams.SwapEffect = D3DSWAPEFFECT_COPY;
presentParams.BackBufferWidth = 8;
presentParams.BackBufferHeight = 8;
presentParams.BackBufferFormat = D3DFMT_UNKNOWN;
HRESULT err; D3DPRESENT_PARAMETERS presentParams;
ZeroMemory(&presentParams, sizeof(presentParams));
presentParams.Windowed = TRUE;
presentParams.SwapEffect = D3DSWAPEFFECT_COPY;
presentParams.BackBufferWidth = 8;
presentParams.BackBufferHeight = 8;
presentParams.BackBufferFormat = D3DFMT_UNKNOWN;
IDirect3DDevice9 * device = NULL; HRESULT err;
err = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GetDesktopWindow(), D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &device);
IDirect3DTexture9 * texture = NULL; IDirect3DDevice9 * device = NULL;
err = D3DXCreateTexture(device, w, h, 1, 0, D3DFMT_DXT1, D3DPOOL_SYSTEMMEM, &texture); err = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GetDesktopWindow(), D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &device);
IDirect3DSurface9 * surface = NULL;
err = texture->GetSurfaceLevel(0, &surface);
RECT rect; IDirect3DTexture9 * texture = NULL;
rect.left = 0; err = D3DXCreateTexture(device, w, h, 1, 0, D3DFMT_DXT1, D3DPOOL_SYSTEMMEM, &texture);
rect.top = 0;
rect.bottom = h;
rect.right = w;
if (inputFormat == nvtt::InputFormat_BGRA_8UB) IDirect3DSurface9 * surface = NULL;
{ err = texture->GetSurfaceLevel(0, &surface);
err = D3DXLoadSurfaceFromMemory(surface, NULL, NULL, data, D3DFMT_A8R8G8B8, w * 4, NULL, &rect, D3DX_DEFAULT, 0);
}
else
{
err = D3DXLoadSurfaceFromMemory(surface, NULL, NULL, data, D3DFMT_A32B32G32R32F, w * 16, NULL, &rect, D3DX_DEFAULT, 0);
}
if (err != D3DERR_INVALIDCALL && err != D3DXERR_INVALIDDATA) RECT rect;
{ rect.left = 0;
D3DLOCKED_RECT rect; rect.top = 0;
ZeroMemory(&rect, sizeof(rect)); rect.bottom = h;
rect.right = w;
err = surface->LockRect(&rect, NULL, D3DLOCK_READONLY); if (inputFormat == nvtt::InputFormat_BGRA_8UB)
{
err = D3DXLoadSurfaceFromMemory(surface, NULL, NULL, data, D3DFMT_A8R8G8B8, w * 4, NULL, &rect, D3DX_DEFAULT, 0);
}
else
{
err = D3DXLoadSurfaceFromMemory(surface, NULL, NULL, data, D3DFMT_A32B32G32R32F, w * 16, NULL, &rect, D3DX_DEFAULT, 0);
}
if (outputOptions.outputHandler != NULL) { if (err != D3DERR_INVALIDCALL && err != D3DXERR_INVALIDDATA)
int size = rect.Pitch * ((h + 3) / 4); {
outputOptions.outputHandler->writeData(rect.pBits, size); D3DLOCKED_RECT rect;
} ZeroMemory(&rect, sizeof(rect));
err = surface->LockRect(&rect, NULL, D3DLOCK_READONLY);
err = surface->UnlockRect(); if (outputOptions.outputHandler != NULL) {
int size = rect.Pitch * ((h + 3) / 4);
outputOptions.outputHandler->writeData(rect.pBits, size);
} }
surface->Release(); err = surface->UnlockRect();
device->Release(); }
d3d->Release();
surface->Release();
device->Release();
d3d->Release();
} }
#endif // defined(HAVE_D3DX) #endif // defined(HAVE_D3DX)
@ -581,8 +501,8 @@ void D3DXCompressorDXT1::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode
void StbCompressorDXT1::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) void StbCompressorDXT1::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{ {
rgba.swizzle(2, 1, 0, 3); // Swap R and B rgba.swizzle(2, 1, 0, 3); // Swap R and B
stb_compress_dxt_block((unsigned char *)output, (unsigned char *)rgba.colors(), 0, 0); stb_compress_dxt_block((unsigned char *)output, (unsigned char *)rgba.colors(), 0, 0);
} }

@ -107,26 +107,26 @@ namespace nv
#if defined(HAVE_ATITC) #if defined(HAVE_ATITC)
struct AtiCompressorDXT1 : public CompressorInterface struct AtiCompressorDXT1 : public CompressorInterface
{ {
virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
}; };
struct AtiCompressorDXT5 : public CompressorInterface struct AtiCompressorDXT5 : public CompressorInterface
{ {
virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
}; };
#endif #endif
#if defined(HAVE_SQUISH) #if defined(HAVE_SQUISH)
struct SquishCompressorDXT1 : public CompressorInterface struct SquishCompressorDXT1 : public CompressorInterface
{ {
virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
}; };
#endif #endif
#if defined(HAVE_D3DX) #if defined(HAVE_D3DX)
struct D3DXCompressorDXT1 : public CompressorInterface struct D3DXCompressorDXT1 : public CompressorInterface
{ {
virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, uint d, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
}; };
#endif #endif

@ -143,8 +143,10 @@ void CompressorTask(void * data, int i)
} }
} }
void FixedBlockCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void FixedBlockCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
nvDebugCheck(d == 1);
CompressorContext context; CompressorContext context;
context.alphaMode = alphaMode; context.alphaMode = alphaMode;
context.w = w; context.w = w;
@ -177,8 +179,10 @@ void FixedBlockCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, c
void ColorSetCompressor::compress(AlphaMode alphaMode, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) void ColorSetCompressor::compress(AlphaMode alphaMode, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions)
{ {
nvDebugCheck(d == 1);
const uint bs = blockSize(); const uint bs = blockSize();
const uint bw = (w + 3) / 4; const uint bw = (w + 3) / 4;
const uint bh = (h + 3) / 4; const uint bh = (h + 3) / 4;

@ -35,7 +35,7 @@ namespace nv
struct FixedBlockCompressor : public CompressorInterface struct FixedBlockCompressor : public CompressorInterface
{ {
virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * rgba, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * rgba, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0;
virtual uint blockSize() const = 0; virtual uint blockSize() const = 0;
@ -43,7 +43,7 @@ namespace nv
struct ColorSetCompressor : public CompressorInterface struct ColorSetCompressor : public CompressorInterface
{ {
virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * rgba, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * rgba, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
virtual void compressBlock(ColorSet & set, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; virtual void compressBlock(ColorSet & set, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0;
virtual uint blockSize() const = 0; virtual uint blockSize() const = 0;

@ -26,14 +26,14 @@
#include "CompressionOptions.h" #include "CompressionOptions.h"
#include "OutputOptions.h" #include "OutputOptions.h"
#include <nvimage/Image.h> #include "nvimage/Image.h"
#include <nvimage/FloatImage.h> #include "nvimage/FloatImage.h"
#include <nvimage/PixelFormat.h> #include "nvimage/PixelFormat.h"
#include <nvmath/Color.h> #include "nvmath/Color.h"
#include <nvmath/Half.h> #include "nvmath/Half.h"
#include <nvcore/Debug.h> #include "nvcore/Debug.h"
using namespace nv; using namespace nv;
using namespace nvtt; using namespace nvtt;
@ -125,7 +125,7 @@ namespace
void PixelFormatConverter::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void PixelFormatConverter::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
nvDebugCheck (compressionOptions.format == nvtt::Format_RGBA); nvDebugCheck (compressionOptions.format == nvtt::Format_RGBA);
@ -189,77 +189,68 @@ void PixelFormatConverter::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint
} }
const uint pitch = computeBytePitch(w, bitCount, compressionOptions.pitchAlignment); const uint pitch = computeBytePitch(w, bitCount, compressionOptions.pitchAlignment);
const uint wh = w * h; const uint whd = w * h * d;
// Allocate output scanline. // Allocate output scanline.
uint8 * const dst = malloc<uint8>(pitch); uint8 * const dst = malloc<uint8>(pitch);
for (uint y = 0; y < h; y++) for (uint z = 0; z < d; z++)
{ {
const uint * src = (const uint *)data + y * w; for (uint y = 0; y < h; y++)
const float * fsrc = (const float *)data + y * w;
BitStream stream(dst);
for (uint x = 0; x < w; x++)
{ {
float r = fsrc[x + 0 * wh]; const float * src = (const float *)data + y * w;
float g = fsrc[x + 1 * wh];
float b = fsrc[x + 2 * wh];
float a = fsrc[x + 3 * wh];
if (compressionOptions.pixelType == nvtt::PixelType_Float)
{
if (rsize == 32) stream.putFloat(r);
else if (rsize == 16) stream.putHalf(r);
if (gsize == 32) stream.putFloat(g); BitStream stream(dst);
else if (gsize == 16) stream.putHalf(g);
if (bsize == 32) stream.putFloat(b); for (uint x = 0; x < w; x++)
else if (bsize == 16) stream.putHalf(b);
if (asize == 32) stream.putFloat(a);
else if (asize == 16) stream.putHalf(a);
}
else
{ {
Color32 c; float r = src[x + 0 * whd];
if (compressionOptions.pixelType == nvtt::PixelType_UnsignedNorm) { float g = src[x + 1 * whd];
c.r = uint8(clamp(r * 255, 0.0f, 255.0f)); float b = src[x + 2 * whd];
c.g = uint8(clamp(g * 255, 0.0f, 255.0f)); float a = src[x + 3 * whd];
c.b = uint8(clamp(b * 255, 0.0f, 255.0f));
c.a = uint8(clamp(a * 255, 0.0f, 255.0f));
}
// @@ Add support for nvtt::PixelType_SignedInt, nvtt::PixelType_SignedNorm, nvtt::PixelType_UnsignedInt
uint p = 0; if (compressionOptions.pixelType == nvtt::PixelType_Float)
p |= PixelFormat::convert(c.r, 8, rsize) << rshift; {
p |= PixelFormat::convert(c.g, 8, gsize) << gshift; if (rsize == 32) stream.putFloat(r);
p |= PixelFormat::convert(c.b, 8, bsize) << bshift; else if (rsize == 16) stream.putHalf(r);
p |= PixelFormat::convert(c.a, 8, asize) << ashift;
stream.putBits(p, bitCount); if (gsize == 32) stream.putFloat(g);
else if (gsize == 16) stream.putHalf(g);
// Output one byte at a time. if (bsize == 32) stream.putFloat(b);
/*for (uint i = 0; i < byteCount; i++) else if (bsize == 16) stream.putHalf(b);
if (asize == 32) stream.putFloat(a);
else if (asize == 16) stream.putHalf(a);
}
else
{ {
*(dst + x * byteCount + i) = (p >> (i * 8)) & 0xFF; Color32 c;
}*/ if (compressionOptions.pixelType == nvtt::PixelType_UnsignedNorm) {
c.r = uint8(clamp(r * 255, 0.0f, 255.0f));
c.g = uint8(clamp(g * 255, 0.0f, 255.0f));
c.b = uint8(clamp(b * 255, 0.0f, 255.0f));
c.a = uint8(clamp(a * 255, 0.0f, 255.0f));
}
// @@ Add support for nvtt::PixelType_SignedInt, nvtt::PixelType_SignedNorm, nvtt::PixelType_UnsignedInt
uint p = 0;
p |= PixelFormat::convert(c.r, 8, rsize) << rshift;
p |= PixelFormat::convert(c.g, 8, gsize) << gshift;
p |= PixelFormat::convert(c.b, 8, bsize) << bshift;
p |= PixelFormat::convert(c.a, 8, asize) << ashift;
stream.putBits(p, bitCount);
}
} }
}
// Zero padding. // Zero padding.
stream.align(compressionOptions.pitchAlignment); stream.align(compressionOptions.pitchAlignment);
nvDebugCheck(stream.ptr == dst + pitch); nvDebugCheck(stream.ptr == dst + pitch);
/*for (uint x = w * byteCount; x < pitch; x++) // Scanlines are always byte-aligned.
{ outputOptions.writeData(dst, pitch);
*(dst + x) = 0; }
}*/
// @@ This code does not truly support less than byte-aligned textures.
outputOptions.writeData(dst, pitch);
} }
free(dst); free(dst);

@ -31,7 +31,7 @@ namespace nv
{ {
struct PixelFormatConverter : public CompressorInterface struct PixelFormatConverter : public CompressorInterface
{ {
virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
}; };
} // nv namespace } // nv namespace

@ -56,17 +56,17 @@ static Color32 toRgbe8(float r, float g, float b)
} }
void CompressorRGBE::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void CompressorRGBE::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
nvDebugCheck (compressionOptions.format == nvtt::Format_RGBE); nvDebugCheck (compressionOptions.format == nvtt::Format_RGBE);
uint srcPitch = w; uint srcPitch = w;
uint srcPlane = w * h; uint srcPlane = w * h * d;
// Allocate output scanline. // Allocate output scanline.
Color32 * dst = new Color32[w]; Color32 * dst = new Color32[w];
for (uint y = 0; y < h; y++) for (uint y = 0; y < h*d; y++)
{ {
const float * src = (const float *)data + y * srcPitch; const float * src = (const float *)data + y * srcPitch;
@ -75,14 +75,14 @@ void CompressorRGBE::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint h, con
float r = src[x + 0 * srcPlane]; float r = src[x + 0 * srcPlane];
float g = src[x + 1 * srcPlane]; float g = src[x + 1 * srcPlane];
float b = src[x + 2 * srcPlane]; float b = src[x + 2 * srcPlane];
dst[x] = toRgbe8(r, g, b); dst[x] = toRgbe8(r, g, b);
} }
if (outputOptions.outputHandler != NULL) if (outputOptions.outputHandler != NULL)
{ {
outputOptions.outputHandler->writeData(dst, w * 4); outputOptions.outputHandler->writeData(dst, w * 4);
} }
} }
delete [] dst; delete [] dst;

@ -29,9 +29,9 @@
namespace nv namespace nv
{ {
struct CompressorRGBE : public CompressorInterface struct CompressorRGBE : public CompressorInterface
{ {
virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
}; };
} // nv namespace } // nv namespace

@ -122,7 +122,12 @@ int Compressor::estimateSize(const InputOptions & inputOptions, const Compressio
int d = inputOptions.m.depth; int d = inputOptions.m.depth;
getTargetExtent(w, h, d, inputOptions.m.maxExtent, inputOptions.m.roundMode, inputOptions.m.textureType); getTargetExtent(w, h, d, inputOptions.m.maxExtent, inputOptions.m.roundMode, inputOptions.m.textureType);
int mipmapCount = countMipmaps(w, h, d); int mipmapCount = 1;
if (inputOptions.m.generateMipmaps) {
mipmapCount = countMipmaps(w, h, d);
if (inputOptions.m.maxLevel > 0) mipmapCount = min(mipmapCount, inputOptions.m.maxLevel);
}
return inputOptions.m.faceCount * estimateSize(w, h, d, mipmapCount, compressionOptions); return inputOptions.m.faceCount * estimateSize(w, h, d, mipmapCount, compressionOptions);
} }
@ -130,7 +135,7 @@ int Compressor::estimateSize(const InputOptions & inputOptions, const Compressio
// TexImage API. // TexImage API.
bool Compressor::outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const bool Compressor::outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const
{ {
return m.outputHeader(TextureType_2D, tex.width(), tex.height(), tex.depth(), mipmapCount, tex.isNormalMap(), compressionOptions.m, outputOptions.m); return m.outputHeader(tex.type(), tex.width(), tex.height(), tex.depth(), mipmapCount, tex.isNormalMap(), compressionOptions.m, outputOptions.m);
} }
bool Compressor::compress(const TexImage & tex, int face, int mipmap, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const bool Compressor::compress(const TexImage & tex, int face, int mipmap, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const
@ -228,7 +233,7 @@ bool Compressor::Private::compress(const InputOptions::Private & inputOptions, c
// Output images. // Output images.
for (int f = 0; f < faceCount; f++) for (int f = 0; f < faceCount; f++)
{ {
img.setImage2D(inputOptions.inputFormat, inputOptions.width, inputOptions.height, inputOptions.images[f]); img.setImage(inputOptions.inputFormat, inputOptions.width, inputOptions.height, inputOptions.depth, inputOptions.images[f]);
// To normal map. // To normal map.
if (inputOptions.convertToNormalMap) { if (inputOptions.convertToNormalMap) {
@ -242,7 +247,7 @@ bool Compressor::Private::compress(const InputOptions::Private & inputOptions, c
} }
// Resize input. // Resize input.
img.resize(w, h, ResizeFilter_Box); img.resize(w, h, d, ResizeFilter_Box);
nvtt::TexImage tmp = img; nvtt::TexImage tmp = img;
if (!img.isNormalMap()) { if (!img.isNormalMap()) {
@ -269,7 +274,12 @@ bool Compressor::Private::compress(const InputOptions::Private & inputOptions, c
} }
if (useSourceImages) { if (useSourceImages) {
img.setImage2D(inputOptions.inputFormat, w, h, inputOptions.images[idx]); img.setImage(inputOptions.inputFormat, w, h, d, inputOptions.images[idx]);
// For already generated mipmaps, we need to convert to linear.
if (!img.isNormalMap()) {
img.toLinear(inputOptions.inputGamma);
}
} }
else { else {
if (inputOptions.mipmapFilter == MipmapFilter_Kaiser) { if (inputOptions.mipmapFilter == MipmapFilter_Kaiser) {
@ -282,6 +292,7 @@ bool Compressor::Private::compress(const InputOptions::Private & inputOptions, c
} }
nvDebugCheck(img.width() == w); nvDebugCheck(img.width() == w);
nvDebugCheck(img.height() == h); nvDebugCheck(img.height() == h);
nvDebugCheck(img.depth() == d);
if (img.isNormalMap()) { if (img.isNormalMap()) {
if (inputOptions.normalizeMipmaps) { if (inputOptions.normalizeMipmaps) {
@ -313,7 +324,7 @@ bool Compressor::Private::compress(const TexImage & tex, int face, int mipmap, c
bool Compressor::Private::compress(AlphaMode alphaMode, int w, int h, int d, int face, int mipmap, const float * rgba, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const bool Compressor::Private::compress(AlphaMode alphaMode, int w, int h, int d, int face, int mipmap, const float * rgba, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const
{ {
int size = computeImageSize(w, h, d, compressionOptions.bitcount, compressionOptions.pitchAlignment, compressionOptions.format); int size = computeImageSize(w, h, d, compressionOptions.getBitCount(), compressionOptions.pitchAlignment, compressionOptions.format);
outputOptions.beginImage(size, w, h, d, face, mipmap); outputOptions.beginImage(size, w, h, d, face, mipmap);
// Decide what compressor to use. // Decide what compressor to use.
@ -335,7 +346,7 @@ bool Compressor::Private::compress(AlphaMode alphaMode, int w, int h, int d, int
} }
else else
{ {
compressor->compress(alphaMode, w, h, rgba, dispatcher, compressionOptions, outputOptions); compressor->compress(alphaMode, w, h, d, rgba, dispatcher, compressionOptions, outputOptions);
} }
return true; return true;
@ -393,10 +404,10 @@ bool Compressor::Private::outputHeader(nvtt::TextureType textureType, int w, int
else if (textureType == TextureType_Cube) { else if (textureType == TextureType_Cube) {
header.setTextureCube(); header.setTextureCube();
} }
/*else if (textureType == TextureType_3D) { else if (textureType == TextureType_3D) {
header.setTexture3D(); header.setTexture3D();
header.setDepth(d); header.setDepth(d);
}*/ }
header.setWidth(w); header.setWidth(w);
header.setHeight(h); header.setHeight(h);
@ -408,10 +419,7 @@ bool Compressor::Private::outputHeader(nvtt::TextureType textureType, int w, int
{ {
if (compressionOptions.format == Format_RGBA) if (compressionOptions.format == Format_RGBA)
{ {
int bitcount = compressionOptions.bitcount; const uint bitcount = compressionOptions.getBitCount();
if (bitcount == 0) {
bitcount = compressionOptions.rsize + compressionOptions.gsize + compressionOptions.bsize + compressionOptions.asize;
}
if (bitcount == 16) if (bitcount == 16)
{ {

@ -176,9 +176,6 @@ void InputOptions::resetTextureLayout()
// Copies the data to our internal structures. // Copies the data to our internal structures.
bool InputOptions::setMipmapData(const void * data, int width, int height, int depth /*= 1*/, int face /*= 0*/, int mipLevel /*= 0*/) bool InputOptions::setMipmapData(const void * data, int width, int height, int depth /*= 1*/, int face /*= 0*/, int mipLevel /*= 0*/)
{ {
if (depth != 1) {
return false;
}
if (uint(face) >= m.faceCount) { if (uint(face) >= m.faceCount) {
return false; return false;
} }

@ -115,6 +115,7 @@ uint nv::computeImageSize(uint w, uint h, uint d, uint bitCount, uint pitchAlign
return d * h * computeBytePitch(w, bitCount, pitchAlignmentInBytes); return d * h * computeBytePitch(w, bitCount, pitchAlignmentInBytes);
} }
else { else {
nvDebugCheck(d == 1);
// @@ Handle 3D textures. DXT and VTC have different behaviors. // @@ Handle 3D textures. DXT and VTC have different behaviors.
return ((w + 3) / 4) * ((h + 3) / 4) * blockSize(format); return ((w + 3) / 4) * ((h + 3) / 4) * blockSize(format);
} }
@ -253,7 +254,7 @@ int TexImage::height() const
int TexImage::depth() const int TexImage::depth() const
{ {
if (m->image != NULL) return 1; if (m->image != NULL) return m->image->depth();
return 0; return 0;
} }
@ -272,6 +273,11 @@ bool TexImage::isNormalMap() const
return m->isNormalMap; return m->isNormalMap;
} }
TextureType TexImage::type() const
{
return m->type;
}
int TexImage::countMipmaps() const int TexImage::countMipmaps() const
{ {
if (m->image == NULL) return 0; if (m->image == NULL) return 0;
@ -338,7 +344,7 @@ void TexImage::histogram(int channel, float rangeMin, float rangeMax, int binCou
float scale = float(binCount) / rangeMax; float scale = float(binCount) / rangeMax;
float bias = - scale * rangeMin; float bias = - scale * rangeMin;
const uint count = m->image->width() * m->image->height(); const uint count = m->image->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float f = c[i] * scale + bias; float f = c[i] * scale + bias;
int idx = ifloor(f); int idx = ifloor(f);
@ -355,7 +361,7 @@ void TexImage::range(int channel, float * rangeMin, float * rangeMax)
FloatImage * img = m->image; FloatImage * img = m->image;
float * c = img->channel(channel); float * c = img->channel(channel);
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint p = 0; p < count; p++) { for (uint p = 0; p < count; p++) {
float f = c[p]; float f = c[p];
if (f < range.x) range.x = f; if (f < range.x) range.x = f;
@ -378,7 +384,7 @@ bool TexImage::load(const char * fileName, bool * hasAlpha/*= NULL*/)
detach(); detach();
if (hasAlpha != NULL) { if (hasAlpha != NULL) {
*hasAlpha = (img->componentNum() == 4); *hasAlpha = (img->componentCount() == 4);
} }
// @@ Have loadFloat allocate the image with the desired number of channels. // @@ Have loadFloat allocate the image with the desired number of channels.
@ -400,16 +406,17 @@ bool TexImage::save(const char * fileName) const
return false; return false;
} }
bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, const void * data) bool TexImage::setImage(nvtt::InputFormat format, int w, int h, int d, const void * data)
{ {
detach(); detach();
if (m->image == NULL) { if (m->image == NULL) {
m->image = new FloatImage(); m->image = new FloatImage();
} }
m->image->allocate(4, w, h); m->image->allocate(4, w, h, d);
m->type = (d == 1) ? TextureType_2D : TextureType_3D;
const int count = w * h; const int count = m->image->pixelCount();
float * rdst = m->image->channel(0); float * rdst = m->image->channel(0);
float * gdst = m->image->channel(1); float * gdst = m->image->channel(1);
@ -471,16 +478,17 @@ bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, const void * d
return true; return true;
} }
bool TexImage::setImage2D(InputFormat format, int w, int h, const void * r, const void * g, const void * b, const void * a) bool TexImage::setImage(InputFormat format, int w, int h, int d, const void * r, const void * g, const void * b, const void * a)
{ {
detach(); detach();
if (m->image == NULL) { if (m->image == NULL) {
m->image = new FloatImage(); m->image = new FloatImage();
} }
m->image->allocate(4, w, h); m->image->allocate(4, w, h, d);
m->type = (d == 1) ? TextureType_2D : TextureType_3D;
const int count = w * h; const int count = m->image->pixelCount();
float * rdst = m->image->channel(0); float * rdst = m->image->channel(0);
float * gdst = m->image->channel(1); float * gdst = m->image->channel(1);
@ -542,6 +550,7 @@ bool TexImage::setImage2D(InputFormat format, int w, int h, const void * r, cons
return true; return true;
} }
// @@ Add support for compressed 3D textures.
bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, const void * data) bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, const void * data)
{ {
if (format != nvtt::Format_BC1 && format != nvtt::Format_BC2 && format != nvtt::Format_BC3 && format != nvtt::Format_BC4 && format != nvtt::Format_BC5) if (format != nvtt::Format_BC1 && format != nvtt::Format_BC2 && format != nvtt::Format_BC3 && format != nvtt::Format_BC4 && format != nvtt::Format_BC5)
@ -554,7 +563,8 @@ bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, const vo
if (m->image == NULL) { if (m->image == NULL) {
m->image = new FloatImage(); m->image = new FloatImage();
} }
m->image->allocate(4, w, h); m->image->allocate(4, w, h, 1);
m->type = TextureType_2D;
const int bw = (w + 3) / 4; const int bw = (w + 3) / 4;
const int bh = (h + 3) / 4; const int bh = (h + 3) / 4;
@ -570,50 +580,50 @@ bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, const vo
{ {
ColorBlock colors; ColorBlock colors;
if (format == nvtt::Format_BC1) if (format == nvtt::Format_BC1)
{ {
const BlockDXT1 * block = (const BlockDXT1 *)ptr; const BlockDXT1 * block = (const BlockDXT1 *)ptr;
if (decoder == Decoder_D3D10) { if (decoder == Decoder_D3D10) {
block->decodeBlock(&colors, false); block->decodeBlock(&colors, false);
} }
else if (decoder == Decoder_D3D9) { else if (decoder == Decoder_D3D9) {
block->decodeBlock(&colors, false); block->decodeBlock(&colors, false);
} }
else if (decoder == Decoder_NV5x) { else if (decoder == Decoder_NV5x) {
block->decodeBlockNV5x(&colors); block->decodeBlockNV5x(&colors);
} }
} }
else if (format == nvtt::Format_BC2) else if (format == nvtt::Format_BC2)
{ {
const BlockDXT3 * block = (const BlockDXT3 *)ptr; const BlockDXT3 * block = (const BlockDXT3 *)ptr;
if (decoder == Decoder_D3D10) { if (decoder == Decoder_D3D10) {
block->decodeBlock(&colors, false); block->decodeBlock(&colors, false);
} }
else if (decoder == Decoder_D3D9) { else if (decoder == Decoder_D3D9) {
block->decodeBlock(&colors, false); block->decodeBlock(&colors, false);
} }
else if (decoder == Decoder_NV5x) { else if (decoder == Decoder_NV5x) {
block->decodeBlockNV5x(&colors); block->decodeBlockNV5x(&colors);
} }
} }
else if (format == nvtt::Format_BC3) else if (format == nvtt::Format_BC3)
{ {
const BlockDXT5 * block = (const BlockDXT5 *)ptr; const BlockDXT5 * block = (const BlockDXT5 *)ptr;
if (decoder == Decoder_D3D10) { if (decoder == Decoder_D3D10) {
block->decodeBlock(&colors, false); block->decodeBlock(&colors, false);
} }
else if (decoder == Decoder_D3D9) { else if (decoder == Decoder_D3D9) {
block->decodeBlock(&colors, false); block->decodeBlock(&colors, false);
} }
else if (decoder == Decoder_NV5x) { else if (decoder == Decoder_NV5x) {
block->decodeBlockNV5x(&colors); block->decodeBlockNV5x(&colors);
} }
} }
else if (format == nvtt::Format_BC4) else if (format == nvtt::Format_BC4)
{ {
const BlockATI1 * block = (const BlockATI1 *)ptr; const BlockATI1 * block = (const BlockATI1 *)ptr;
block->decodeBlock(&colors, decoder == Decoder_D3D9); block->decodeBlock(&colors, decoder == Decoder_D3D9);
} }
@ -623,25 +633,25 @@ bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, const vo
block->decodeBlock(&colors, decoder == Decoder_D3D9); block->decodeBlock(&colors, decoder == Decoder_D3D9);
} }
for (int yy = 0; yy < 4; yy++) for (int yy = 0; yy < 4; yy++)
{ {
for (int xx = 0; xx < 4; xx++) for (int xx = 0; xx < 4; xx++)
{ {
Color32 c = colors.color(xx, yy); Color32 c = colors.color(xx, yy);
if (x * 4 + xx < w && y * 4 + yy < h) if (x * 4 + xx < w && y * 4 + yy < h)
{ {
m->image->pixel(x*4 + xx, y*4 + yy, 0) = float(c.r) * 1.0f/255.0f; m->image->pixel(0, x*4 + xx, y*4 + yy, 0) = float(c.r) * 1.0f/255.0f;
m->image->pixel(x*4 + xx, y*4 + yy, 1) = float(c.g) * 1.0f/255.0f; m->image->pixel(1, x*4 + xx, y*4 + yy, 0) = float(c.g) * 1.0f/255.0f;
m->image->pixel(x*4 + xx, y*4 + yy, 2) = float(c.b) * 1.0f/255.0f; m->image->pixel(2, x*4 + xx, y*4 + yy, 0) = float(c.b) * 1.0f/255.0f;
m->image->pixel(x*4 + xx, y*4 + yy, 3) = float(c.a) * 1.0f/255.0f; m->image->pixel(3, x*4 + xx, y*4 + yy, 0) = float(c.a) * 1.0f/255.0f;
} }
} }
} }
ptr += bs; ptr += bs;
}
} }
}
} }
catch(...) { catch(...) {
return false; return false;
@ -673,19 +683,19 @@ static void getDefaultFilterWidthAndParams(int filter, float * filterWidth, floa
} }
} }
void TexImage::resize(int w, int h, ResizeFilter filter) void TexImage::resize(int w, int h, int d, ResizeFilter filter)
{ {
float filterWidth; float filterWidth;
float params[2]; float params[2];
getDefaultFilterWidthAndParams(filter, &filterWidth, params); getDefaultFilterWidthAndParams(filter, &filterWidth, params);
resize(w, h, filter, filterWidth, params); resize(w, h, d, filter, filterWidth, params);
} }
void TexImage::resize(int w, int h, ResizeFilter filter, float filterWidth, const float * params) void TexImage::resize(int w, int h, int d, ResizeFilter filter, float filterWidth, const float * params)
{ {
FloatImage * img = m->image; FloatImage * img = m->image;
if (img == NULL || (w == img->width() && h == img->height())) { if (img == NULL || (w == img->width() && h == img->height() && d == img->depth())) {
return; return;
} }
@ -698,25 +708,25 @@ void TexImage::resize(int w, int h, ResizeFilter filter, float filterWidth, cons
if (filter == ResizeFilter_Box) if (filter == ResizeFilter_Box)
{ {
BoxFilter filter(filterWidth); BoxFilter filter(filterWidth);
img = img->resize(filter, w, h, wrapMode, 3); img = img->resize(filter, w, h, d, wrapMode, 3);
} }
else if (filter == ResizeFilter_Triangle) else if (filter == ResizeFilter_Triangle)
{ {
TriangleFilter filter(filterWidth); TriangleFilter filter(filterWidth);
img = img->resize(filter, w, h, wrapMode, 3); img = img->resize(filter, w, h, d, wrapMode, 3);
} }
else if (filter == ResizeFilter_Kaiser) else if (filter == ResizeFilter_Kaiser)
{ {
KaiserFilter filter(filterWidth); KaiserFilter filter(filterWidth);
if (params != NULL) filter.setParameters(params[0], params[1]); if (params != NULL) filter.setParameters(params[0], params[1]);
img = img->resize(filter, w, h, wrapMode, 3); img = img->resize(filter, w, h, d, wrapMode, 3);
} }
else //if (filter == ResizeFilter_Mitchell) else //if (filter == ResizeFilter_Mitchell)
{ {
nvDebugCheck(filter == ResizeFilter_Mitchell); nvDebugCheck(filter == ResizeFilter_Mitchell);
MitchellFilter filter; MitchellFilter filter;
if (params != NULL) filter.setParameters(params[0], params[1]); if (params != NULL) filter.setParameters(params[0], params[1]);
img = img->resize(filter, w, h, wrapMode, 3); img = img->resize(filter, w, h, d, wrapMode, 3);
} }
} }
else else
@ -724,25 +734,25 @@ void TexImage::resize(int w, int h, ResizeFilter filter, float filterWidth, cons
if (filter == ResizeFilter_Box) if (filter == ResizeFilter_Box)
{ {
BoxFilter filter(filterWidth); BoxFilter filter(filterWidth);
img = img->resize(filter, w, h, wrapMode); img = img->resize(filter, w, h, d, wrapMode);
} }
else if (filter == ResizeFilter_Triangle) else if (filter == ResizeFilter_Triangle)
{ {
TriangleFilter filter(filterWidth); TriangleFilter filter(filterWidth);
img = img->resize(filter, w, h, wrapMode); img = img->resize(filter, w, h, d, wrapMode);
} }
else if (filter == ResizeFilter_Kaiser) else if (filter == ResizeFilter_Kaiser)
{ {
KaiserFilter filter(filterWidth); KaiserFilter filter(filterWidth);
if (params != NULL) filter.setParameters(params[0], params[1]); if (params != NULL) filter.setParameters(params[0], params[1]);
img = img->resize(filter, w, h, wrapMode); img = img->resize(filter, w, h, d, wrapMode);
} }
else //if (filter == ResizeFilter_Mitchell) else //if (filter == ResizeFilter_Mitchell)
{ {
nvDebugCheck(filter == ResizeFilter_Mitchell); nvDebugCheck(filter == ResizeFilter_Mitchell);
MitchellFilter filter; MitchellFilter filter;
if (params != NULL) filter.setParameters(params[0], params[1]); if (params != NULL) filter.setParameters(params[0], params[1]);
img = img->resize(filter, w, h, wrapMode); img = img->resize(filter, w, h, d, wrapMode);
} }
} }
@ -765,11 +775,11 @@ void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter, f
int w = m->image->width(); int w = m->image->width();
int h = m->image->height(); int h = m->image->height();
int d = 1; int d = m->image->depth();
getTargetExtent(w, h, d, maxExtent, roundMode, nvtt::TextureType_2D); getTargetExtent(w, h, d, maxExtent, roundMode, m->type);
resize(w, h, filter, filterWidth, params); resize(w, h, d, filter, filterWidth, params);
} }
bool TexImage::buildNextMipmap(MipmapFilter filter) bool TexImage::buildNextMipmap(MipmapFilter filter)
@ -784,7 +794,7 @@ bool TexImage::buildNextMipmap(MipmapFilter filter)
bool TexImage::buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params) bool TexImage::buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params)
{ {
FloatImage * img = m->image; FloatImage * img = m->image;
if (img == NULL || (img->width() == 1 && img->height() == 1)) { if (img == NULL || (img->width() == 1 && img->height() == 1 && img->depth() == 1)) {
return false; return false;
} }
@ -816,7 +826,7 @@ bool TexImage::buildNextMipmap(MipmapFilter filter, float filterWidth, const flo
{ {
if (filter == MipmapFilter_Box) if (filter == MipmapFilter_Box)
{ {
if (filterWidth == 0.5f) { if (filterWidth == 0.5f && img->depth() == 1) {
img = img->fastDownSample(); img = img->fastDownSample();
} }
else { else {
@ -939,8 +949,8 @@ void TexImage::blend(float red, float green, float blue, float alpha, float t)
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const int count = img->width() * img->height(); const uint count = img->pixelCount();
for (int i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
r[i] = lerp(r[i], red, t); r[i] = lerp(r[i], red, t);
g[i] = lerp(g[i], green, t); g[i] = lerp(g[i], green, t);
@ -961,8 +971,8 @@ void TexImage::premultiplyAlpha()
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const int count = img->width() * img->height(); const uint count = img->pixelCount();
for (int i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
r[i] *= a[i]; r[i] *= a[i];
g[i] *= a[i]; g[i] *= a[i];
@ -989,8 +999,8 @@ void TexImage::toGreyScale(float redScale, float greenScale, float blueScale, fl
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const int count = img->width() * img->height(); const uint count = img->pixelCount();
for (int i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
float grey = r[i] * redScale + g[i] * greenScale + b[i] * blueScale + a[i] * alphaScale; float grey = r[i] * redScale + g[i] * greenScale + b[i] * blueScale + a[i] * alphaScale;
a[i] = b[i] = g[i] = r[i] = grey; a[i] = b[i] = g[i] = r[i] = grey;
@ -1005,33 +1015,37 @@ void TexImage::setBorder(float r, float g, float b, float a)
detach(); detach();
FloatImage * img = m->image; FloatImage * img = m->image;
const int w = img->width(); const uint w = img->width();
const int h = img->height(); const uint h = img->height();
const uint d = img->depth();
for (int i = 0; i < w; i++)
{
img->pixel(i, 0, 0) = r;
img->pixel(i, 0, 1) = g;
img->pixel(i, 0, 2) = b;
img->pixel(i, 0, 3) = a;
img->pixel(i, h-1, 0) = r;
img->pixel(i, h-1, 1) = g;
img->pixel(i, h-1, 2) = b;
img->pixel(i, h-1, 3) = a;
}
for (int i = 0; i < h; i++) for (int z = 0; z < d; z++)
{ {
img->pixel(0, i, 0) = r; for (int i = 0; i < w; i++)
img->pixel(0, i, 1) = g; {
img->pixel(0, i, 2) = b; img->pixel(0, i, 0, z) = r;
img->pixel(0, i, 3) = a; img->pixel(1, i, 0, z) = g;
img->pixel(2, i, 0, z) = b;
img->pixel(3, i, 0, z) = a;
img->pixel(0, i, h-1, z) = r;
img->pixel(1, i, h-1, z) = g;
img->pixel(2, i, h-1, z) = b;
img->pixel(3, i, h-1, z) = a;
}
img->pixel(w-1, i, 0) = r; for (int i = 0; i < h; i++)
img->pixel(w-1, i, 1) = g; {
img->pixel(w-1, i, 2) = b; img->pixel(0, 0, i, z) = r;
img->pixel(w-1, i, 3) = a; img->pixel(1, 0, i, z) = g;
img->pixel(2, 0, i, z) = b;
img->pixel(3, 0, i, z) = a;
img->pixel(0, w-1, i, z) = r;
img->pixel(1, w-1, i, z) = g;
img->pixel(2, w-1, i, z) = b;
img->pixel(3, w-1, i, z) = a;
}
} }
} }
@ -1048,8 +1062,8 @@ void TexImage::fill(float red, float green, float blue, float alpha)
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const int count = img->width() * img->height(); const uint count = img->pixelCount();
for (int i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
r[i] = red; r[i] = red;
g[i] = green; g[i] = green;
@ -1112,7 +1126,7 @@ void TexImage::toRGBM(float range/*= 1*/, float threshold/*= 0.25*/)
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float R = nv::clamp(r[i] * irange, 0.0f, 1.0f); float R = nv::clamp(r[i] * irange, 0.0f, 1.0f);
float G = nv::clamp(g[i] * irange, 0.0f, 1.0f); float G = nv::clamp(g[i] * irange, 0.0f, 1.0f);
@ -1139,7 +1153,7 @@ void TexImage::fromRGBM(float range/*= 1*/)
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float M = a[i] * range; float M = a[i] * range;
@ -1164,7 +1178,7 @@ void TexImage::toYCoCg()
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float R = r[i]; float R = r[i];
float G = g[i]; float G = g[i];
@ -1191,7 +1205,7 @@ void TexImage::toYCoCg()
// and minimize bilinear interpolation artifacts. // and minimize bilinear interpolation artifacts.
void TexImage::blockScaleCoCg(int bits/*= 5*/, float threshold/*= 0.0*/) void TexImage::blockScaleCoCg(int bits/*= 5*/, float threshold/*= 0.0*/)
{ {
if (m->image == NULL) return; if (m->image == NULL || m->image->depth() != 1) return;
detach(); detach();
@ -1214,8 +1228,8 @@ void TexImage::blockScaleCoCg(int bits/*= 5*/, float threshold/*= 0.0*/)
const uint x = bi*4 + i; const uint x = bi*4 + i;
if (x >= w) continue; if (x >= w) continue;
float Co = img->pixel(x, y, 0); float Co = img->pixel(0, x, y, 0);
float Cg = img->pixel(x, y, 1); float Cg = img->pixel(1, x, y, 0);
m = max(m, fabsf(Co)); m = max(m, fabsf(Co));
m = max(m, fabsf(Cg)); m = max(m, fabsf(Cg));
@ -1231,8 +1245,8 @@ void TexImage::blockScaleCoCg(int bits/*= 5*/, float threshold/*= 0.0*/)
uint x = min(bi*4 + i, w); uint x = min(bi*4 + i, w);
uint y = min(bj*4 + j, h); uint y = min(bj*4 + j, h);
float & Co = img->pixel(x, y, 0); float & Co = img->pixel(0, x, y, 0);
float & Cg = img->pixel(x, y, 1); float & Cg = img->pixel(1, x, y, 0);
Co /= scale; Co /= scale;
nvDebugCheck(fabsf(Co) <= 1.0f); nvDebugCheck(fabsf(Co) <= 1.0f);
@ -1240,7 +1254,7 @@ void TexImage::blockScaleCoCg(int bits/*= 5*/, float threshold/*= 0.0*/)
Cg /= scale; Cg /= scale;
nvDebugCheck(fabsf(Cg) <= 1.0f); nvDebugCheck(fabsf(Cg) <= 1.0f);
img->pixel(x, y, 2) = scale; img->pixel(2, x, y, 0) = scale;
} }
} }
} }
@ -1259,7 +1273,7 @@ void TexImage::fromYCoCg()
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float Co = r[i]; float Co = r[i];
float Cg = g[i]; float Cg = g[i];
@ -1294,7 +1308,7 @@ void TexImage::toLUVW(float range/*= 1.0f*/)
float * b = img->channel(2); float * b = img->channel(2);
float * a = img->channel(3); float * a = img->channel(3);
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float R = nv::clamp(r[i] * irange, 0.0f, 1.0f); float R = nv::clamp(r[i] * irange, 0.0f, 1.0f);
float G = nv::clamp(g[i] * irange, 0.0f, 1.0f); float G = nv::clamp(g[i] * irange, 0.0f, 1.0f);
@ -1324,7 +1338,7 @@ void TexImage::abs(int channel)
FloatImage * img = m->image; FloatImage * img = m->image;
float * c = img->channel(channel); float * c = img->channel(channel);
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
c[i] = fabsf(c[i]); c[i] = fabsf(c[i]);
} }
@ -1454,6 +1468,7 @@ void TexImage::fromJPEGLS()
*/ */
// If dither is true, this uses Floyd-Steinberg dithering method.
void TexImage::binarize(int channel, float threshold, bool dither) void TexImage::binarize(int channel, float threshold, bool dither)
{ {
if (m->image == NULL) return; if (m->image == NULL) return;
@ -1461,45 +1476,51 @@ void TexImage::binarize(int channel, float threshold, bool dither)
detach(); detach();
FloatImage * img = m->image; FloatImage * img = m->image;
const uint w = img->width();
const uint h = img->height();
if (!dither) { if (!dither) {
float * c = img->channel(channel); float * c = img->channel(channel);
const uint count = w * h; const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
c[i] = float(c[i] > threshold); c[i] = float(c[i] > threshold);
} }
} }
else { else {
const uint w = img->width();
const uint h = img->height();
const uint d = img->depth();
float * row0 = new float[(w+2)]; float * row0 = new float[(w+2)];
float * row1 = new float[(w+2)]; float * row1 = new float[(w+2)];
memset(row0, 0, sizeof(float)*(w+2));
memset(row1, 0, sizeof(float)*(w+2));
for (uint y = 0; y < h; y++) { // @@ Extend Floyd-Steinberg dithering to 3D properly.
for (uint x = 0; x < w; x++) { for (uint z = 0; z < d; z++) {
memset(row0, 0, sizeof(float)*(w+2));
memset(row1, 0, sizeof(float)*(w+2));
for (uint y = 0; y < h; y++) {
for (uint x = 0; x < w; x++) {
float & f = img->pixel(x, y, channel); float & f = img->pixel(channel, x, y, 0);
// Add error and quantize. // Add error and quantize.
float qf = float(f + row0[1+x] > threshold); float qf = float(f + row0[1+x] > threshold);
// Compute new error: // Compute new error:
float diff = f - qf; float diff = f - qf;
// Store color. // Store color.
f = qf; f = qf;
// Propagate new error. // Propagate new error.
row0[1+x+1] += (7.0f / 16.0f) * diff; row0[1+x+1] += (7.0f / 16.0f) * diff;
row1[1+x-1] += (3.0f / 16.0f) * diff; row1[1+x-1] += (3.0f / 16.0f) * diff;
row1[1+x+0] += (5.0f / 16.0f) * diff; row1[1+x+0] += (5.0f / 16.0f) * diff;
row1[1+x+1] += (1.0f / 16.0f) * diff; row1[1+x+1] += (1.0f / 16.0f) * diff;
} }
swap(row0, row1); swap(row0, row1);
memset(row1, 0, sizeof(float)*(w+2)); memset(row1, 0, sizeof(float)*(w+2));
}
} }
delete [] row0; delete [] row0;
@ -1510,6 +1531,7 @@ void TexImage::binarize(int channel, float threshold, bool dither)
// Uniform quantizer. // Uniform quantizer.
// Assumes input is in [0, 1] range. Output is in the [0, 1] range, but rounded to the middle of each bin. // Assumes input is in [0, 1] range. Output is in the [0, 1] range, but rounded to the middle of each bin.
// If exactEndPoints is true, [0, 1] are represented exactly, and the correponding bins are half the size, so quantization is not truly uniform. // If exactEndPoints is true, [0, 1] are represented exactly, and the correponding bins are half the size, so quantization is not truly uniform.
// When dither is true, this uses Floyd-Steinberg dithering.
void TexImage::quantize(int channel, int bits, bool exactEndPoints, bool dither) void TexImage::quantize(int channel, int bits, bool exactEndPoints, bool dither)
{ {
if (m->image == NULL) return; if (m->image == NULL) return;
@ -1517,11 +1539,8 @@ void TexImage::quantize(int channel, int bits, bool exactEndPoints, bool dither)
detach(); detach();
FloatImage * img = m->image; FloatImage * img = m->image;
const uint w = img->width();
const uint h = img->height();
float scale, offset; float scale, offset;
if (exactEndPoints) { if (exactEndPoints) {
scale = float((1 << bits) - 1); scale = float((1 << bits) - 1);
offset = 0.0f; offset = 0.0f;
@ -1533,40 +1552,47 @@ void TexImage::quantize(int channel, int bits, bool exactEndPoints, bool dither)
if (!dither) { if (!dither) {
float * c = img->channel(channel); float * c = img->channel(channel);
const uint count = w * h; const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
c[i] = floorf(c[i] * scale + offset) / scale; c[i] = floorf(c[i] * scale + offset) / scale;
} }
} }
else { else {
const uint w = img->width();
const uint h = img->height();
const uint d = img->depth();
float * row0 = new float[(w+2)]; float * row0 = new float[(w+2)];
float * row1 = new float[(w+2)]; float * row1 = new float[(w+2)];
memset(row0, 0, sizeof(float)*(w+2));
memset(row1, 0, sizeof(float)*(w+2));
for (uint y = 0; y < h; y++) { for (uint z = 0; z < d; z++) {
for (uint x = 0; x < w; x++) { memset(row0, 0, sizeof(float)*(w+2));
memset(row1, 0, sizeof(float)*(w+2));
float & f = img->pixel(x, y, channel); for (uint y = 0; y < h; y++) {
for (uint x = 0; x < w; x++) {
// Add error and quantize. float & f = img->pixel(channel, x, y, 0);
float qf = floorf((f + row0[1+x]) * scale + offset) / scale;
// Compute new error: // Add error and quantize.
float diff = f - qf; float qf = floorf((f + row0[1+x]) * scale + offset) / scale;
// Store color. // Compute new error:
f = qf; float diff = f - qf;
// Propagate new error. // Store color.
row0[1+x+1] += (7.0f / 16.0f) * diff; f = qf;
row1[1+x-1] += (3.0f / 16.0f) * diff;
row1[1+x+0] += (5.0f / 16.0f) * diff;
row1[1+x+1] += (1.0f / 16.0f) * diff;
}
swap(row0, row1); // Propagate new error.
memset(row1, 0, sizeof(float)*(w+2)); row0[1+x+1] += (7.0f / 16.0f) * diff;
row1[1+x-1] += (3.0f / 16.0f) * diff;
row1[1+x+0] += (5.0f / 16.0f) * diff;
row1[1+x+1] += (1.0f / 16.0f) * diff;
}
swap(row0, row1);
memset(row1, 0, sizeof(float)*(w+2));
}
} }
delete [] row0; delete [] row0;
@ -1612,13 +1638,14 @@ void TexImage::transformNormals(NormalTransform xform)
detach(); detach();
m->image->expandNormals(0); FloatImage * img = m->image;
img->expandNormals(0);
const uint count = m->image->width() * m->image->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float & x = m->image->pixel(i, 0); float & x = img->pixel(0, i);
float & y = m->image->pixel(i, 1); float & y = img->pixel(1, i);
float & z = m->image->pixel(i, 2); float & z = img->pixel(2, i);
Vector3 n(x, y, z); Vector3 n(x, y, z);
n = normalizeSafe(n, Vector3(0.0f), 0.0f); n = normalizeSafe(n, Vector3(0.0f), 0.0f);
@ -1675,7 +1702,7 @@ void TexImage::transformNormals(NormalTransform xform)
z = n.z; z = n.z;
} }
m->image->packNormals(0); img->packNormals(0);
} }
void TexImage::reconstructNormals(NormalTransform xform) void TexImage::reconstructNormals(NormalTransform xform)
@ -1684,13 +1711,14 @@ void TexImage::reconstructNormals(NormalTransform xform)
detach(); detach();
m->image->expandNormals(0); FloatImage * img = m->image;
img->expandNormals(0);
const uint count = m->image->width() * m->image->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) { for (uint i = 0; i < count; i++) {
float & x = m->image->pixel(i, 0); float & x = img->pixel(0, i);
float & y = m->image->pixel(i, 1); float & y = img->pixel(1, i);
float & z = m->image->pixel(i, 2); float & z = img->pixel(2, i);
Vector3 n(x, y, z); Vector3 n(x, y, z);
if (xform == NormalTransform_Orthographic) { if (xform == NormalTransform_Orthographic) {
@ -1723,16 +1751,68 @@ void TexImage::reconstructNormals(NormalTransform xform)
z = n.z; z = n.z;
} }
img->packNormals(0);
}
void TexImage::toCleanNormalMap()
{
if (m->image == NULL) return;
detach();
m->image->expandNormals(0);
const uint count = m->image->pixelCount();
for (uint i = 0; i < count; i++) {
float x = m->image->pixel(0, i);
float y = m->image->pixel(1, i);
m->image->pixel(2, i) = x*x + y*y;
}
m->image->packNormals(0);
}
// [-1,1] -> [ 0,1]
void TexImage::packNormals() {
if (m->image == NULL) return;
detach();
m->image->packNormals(0); m->image->packNormals(0);
} }
void TexImage::flipVertically() // [ 0,1] -> [-1,1]
void TexImage::expandNormals() {
if (m->image == NULL) return;
detach();
m->image->expandNormals(0);
}
void TexImage::flipX()
{
if (m->image == NULL) return;
detach();
m->image->flipX();
}
void TexImage::flipY()
{
if (m->image == NULL) return;
detach();
m->image->flipY();
}
void TexImage::flipZ()
{ {
if (m->image == NULL) return; if (m->image == NULL) return;
detach(); detach();
m->image->flip(); m->image->flipZ();
} }
bool TexImage::copyChannel(const TexImage & srcImage, int srcChannel) bool TexImage::copyChannel(const TexImage & srcImage, int srcChannel)
@ -1747,17 +1827,14 @@ bool TexImage::copyChannel(const TexImage & srcImage, int srcChannel, int dstCha
FloatImage * dst = m->image; FloatImage * dst = m->image;
const FloatImage * src = srcImage.m->image; const FloatImage * src = srcImage.m->image;
if (dst == NULL || src == NULL || dst->width() != src->width() || dst->height() != src->height()) { if (!sameLayout(dst, src)) {
return false; return false;
} }
nvDebugCheck(dst->componentNum() == 4 && src->componentNum() == 4); nvDebugCheck(dst->componentCount() == 4 && src->componentCount() == 4);
detach(); detach();
const uint w = src->width(); memcpy(dst->channel(dstChannel), src->channel(srcChannel), dst->pixelCount()*sizeof(float));
const uint h = src->height();
memcpy(dst->channel(dstChannel), src->channel(srcChannel), w*h*sizeof(float));
return true; return true;
} }
@ -1769,10 +1846,10 @@ bool TexImage::addChannel(const TexImage & srcImage, int srcChannel, int dstChan
FloatImage * dst = m->image; FloatImage * dst = m->image;
const FloatImage * src = srcImage.m->image; const FloatImage * src = srcImage.m->image;
if (dst == NULL || src == NULL || dst->width() != src->width() || dst->height() != src->height()) { if (!sameLayout(dst, src)) {
return false; return false;
} }
nvDebugCheck(dst->componentNum() == 4 && src->componentNum() == 4); nvDebugCheck(dst->componentCount() == 4 && src->componentCount() == 4);
detach(); detach();
@ -1781,7 +1858,9 @@ bool TexImage::addChannel(const TexImage & srcImage, int srcChannel, int dstChan
float * d = dst->channel(dstChannel); float * d = dst->channel(dstChannel);
const float * s = src->channel(srcChannel); const float * s = src->channel(srcChannel);
for (uint i = 0; i < w*h; i++) {
const uint count = src->pixelCount();
for (uint i = 0; i < count; i++) {
d[i] += s[i] * scale; d[i] += s[i] * scale;
} }
@ -1819,27 +1898,28 @@ TexImage nvtt::diff(const TexImage & reference, const TexImage & image, float sc
const FloatImage * ref = reference.m->image; const FloatImage * ref = reference.m->image;
const FloatImage * img = image.m->image; const FloatImage * img = image.m->image;
if (img == NULL || ref == NULL || img->width() != ref->width() || img->height() != ref->height()) { if (!sameLayout(img, ref)) {
return TexImage(); return TexImage();
} }
nvDebugCheck(img->componentNum() == 4);
nvDebugCheck(ref->componentNum() == 4); nvDebugCheck(img->componentCount() == 4);
nvDebugCheck(ref->componentCount() == 4);
nvtt::TexImage diffImage; nvtt::TexImage diffImage;
FloatImage * diff = diffImage.m->image = new FloatImage; FloatImage * diff = diffImage.m->image = new FloatImage;
diff->allocate(4, img->width(), img->height()); diff->allocate(4, img->width(), img->height(), img->depth());
const uint count = img->width() * img->height(); const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) for (uint i = 0; i < count; i++)
{ {
float r0 = img->pixel(i, 0); float r0 = img->pixel(0, i);
float g0 = img->pixel(i, 1); float g0 = img->pixel(1, i);
float b0 = img->pixel(i, 2); float b0 = img->pixel(2, i);
//float a0 = img->pixel(i, 3); //float a0 = img->pixel(3, i);
float r1 = ref->pixel(i, 0); float r1 = ref->pixel(0, i);
float g1 = ref->pixel(i, 1); float g1 = ref->pixel(1, i);
float b1 = ref->pixel(i, 2); float b1 = ref->pixel(2, i);
float a1 = ref->pixel(i, 3); float a1 = ref->pixel(3, i);
float dr = r0 - r1; float dr = r0 - r1;
float dg = g0 - g1; float dg = g0 - g1;
@ -1853,10 +1933,10 @@ TexImage nvtt::diff(const TexImage & reference, const TexImage & image, float sc
db *= a1; db *= a1;
} }
diff->pixel(i, 0) = dr * scale; diff->pixel(0, i) = dr * scale;
diff->pixel(i, 1) = dg * scale; diff->pixel(1, i) = dg * scale;
diff->pixel(i, 2) = db * scale; diff->pixel(2, i) = db * scale;
diff->pixel(i, 3) = a1; diff->pixel(3, i) = a1;
} }
return diffImage; return diffImage;

@ -125,8 +125,9 @@ CudaCompressor::CudaCompressor(CudaContext & ctx) : m_ctx(ctx)
} }
void CudaCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) void CudaCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{ {
nvDebugCheck(d == 1);
nvDebugCheck(cuda::isHardwarePresent()); nvDebugCheck(cuda::isHardwarePresent());
#if defined HAVE_CUDA #if defined HAVE_CUDA

@ -54,7 +54,7 @@ namespace nv
{ {
CudaCompressor(CudaContext & ctx); CudaCompressor(CudaContext & ctx);
virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions);
virtual void setup(cudaArray * image, const nvtt::CompressionOptions::Private & compressionOptions) = 0; virtual void setup(cudaArray * image, const nvtt::CompressionOptions::Private & compressionOptions) = 0;
virtual void compressBlocks(uint first, uint count, uint w, uint h, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; virtual void compressBlocks(uint first, uint count, uint w, uint h, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0;

@ -23,7 +23,7 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include "nvcore/Debug.h" #include "nvcore/Debug.h"
//#include "nvcore/Library.h" #include "nvcore/Library.h"
#include "CudaUtils.h" #include "CudaUtils.h"
#if defined HAVE_CUDA #if defined HAVE_CUDA

@ -190,7 +190,7 @@ namespace nvtt
{ {
TextureType_2D, TextureType_2D,
TextureType_Cube, TextureType_Cube,
// TextureType_3D, TextureType_3D,
}; };
/// Input formats. /// Input formats.
@ -415,6 +415,7 @@ namespace nvtt
NVTT_API int width() const; NVTT_API int width() const;
NVTT_API int height() const; NVTT_API int height() const;
NVTT_API int depth() const; NVTT_API int depth() const;
NVTT_API TextureType type() const;
NVTT_API WrapMode wrapMode() const; NVTT_API WrapMode wrapMode() const;
NVTT_API AlphaMode alphaMode() const; NVTT_API AlphaMode alphaMode() const;
NVTT_API bool isNormalMap() const; NVTT_API bool isNormalMap() const;
@ -428,13 +429,13 @@ namespace nvtt
// Texture data. // Texture data.
NVTT_API bool load(const char * fileName, bool * hasAlpha = 0); NVTT_API bool load(const char * fileName, bool * hasAlpha = 0);
NVTT_API bool save(const char * fileName) const; NVTT_API bool save(const char * fileName) const;
NVTT_API bool setImage2D(InputFormat format, int w, int h, const void * data); NVTT_API bool setImage(InputFormat format, int w, int h, int d, const void * data);
NVTT_API bool setImage2D(InputFormat format, int w, int h, const void * r, const void * g, const void * b, const void * a); NVTT_API bool setImage(InputFormat format, int w, int h, int d, const void * r, const void * g, const void * b, const void * a);
NVTT_API bool setImage2D(Format format, Decoder decoder, int w, int h, const void * data); NVTT_API bool setImage2D(Format format, Decoder decoder, int w, int h, const void * data);
// Resizing methods. // Resizing methods.
NVTT_API void resize(int w, int h, ResizeFilter filter); NVTT_API void resize(int w, int h, int d, ResizeFilter filter);
NVTT_API void resize(int w, int h, ResizeFilter filter, float filterWidth, const float * params = 0); NVTT_API void resize(int w, int h, int d, ResizeFilter filter, float filterWidth, const float * params = 0);
NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter); NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter);
NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter, float filterWidth, const float * params = 0); NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter, float filterWidth, const float * params = 0);
NVTT_API bool buildNextMipmap(MipmapFilter filter); NVTT_API bool buildNextMipmap(MipmapFilter filter);
@ -471,14 +472,19 @@ namespace nvtt
NVTT_API void binarize(int channel, float threshold, bool dither); NVTT_API void binarize(int channel, float threshold, bool dither);
NVTT_API void quantize(int channel, int bits, bool exactEndPoints, bool dither); NVTT_API void quantize(int channel, int bits, bool exactEndPoints, bool dither);
// Normal map transforms. // Normal map transforms. @@ All these methods assume packed normals.
NVTT_API void toNormalMap(float sm, float medium, float big, float large); NVTT_API void toNormalMap(float sm, float medium, float big, float large);
NVTT_API void normalizeNormalMap(); NVTT_API void normalizeNormalMap();
NVTT_API void transformNormals(NormalTransform xform); NVTT_API void transformNormals(NormalTransform xform);
NVTT_API void reconstructNormals(NormalTransform xform); NVTT_API void reconstructNormals(NormalTransform xform);
NVTT_API void toCleanNormalMap();
NVTT_API void packNormals(); // [-1,1] -> [ 0,1]
NVTT_API void expandNormals(); // [ 0,1] -> [-1,1]
// Geometric transforms. // Geometric transforms.
NVTT_API void flipVertically(); NVTT_API void flipX();
NVTT_API void flipY();
NVTT_API void flipZ();
// Copy image data. // Copy image data.
NVTT_API bool copyChannel(const TexImage & srcImage, int srcChannel); NVTT_API bool copyChannel(const TexImage & srcImage, int srcChannel);
@ -501,6 +507,54 @@ namespace nvtt
}; };
/// A texture mipmap.
struct CubeImage
{
NVTT_API CubeImage();
NVTT_API CubeImage(const CubeImage & tex);
NVTT_API ~CubeImage();
NVTT_API void operator=(const CubeImage & tex);
// Queries.
NVTT_API bool isNull() const;
NVTT_API int size() const;
NVTT_API int countMipmaps() const;
NVTT_API float average(int channel, int alpha_channel = -1, float gamma = 2.2f) const;
// Texture data.
NVTT_API bool load(const char * fileName);
NVTT_API bool save(const char * fileName) const;
NVTT_API bool setImage2D(InputFormat format, int face, int w, int h, const void * data);
NVTT_API bool setImage2D(InputFormat format, int face, int w, int h, const void * r, const void * g, const void * b, const void * a);
NVTT_API bool setImage2D(Format format, Decoder decoder, int face, int w, int h, const void * data);
TexImage & face(int face);
//
// @@ Add resizing methods.
/*
NVTT_API void resize(int w, int h, ResizeFilter filter);
NVTT_API void resize(int w, int h, ResizeFilter filter, float filterWidth, const float * params = 0);
NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter);
NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter, float filterWidth, const float * params = 0);
NVTT_API bool buildNextMipmap(MipmapFilter filter);
NVTT_API bool buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params = 0);
*/
// Color transforms.
NVTT_API void toLinear(float gamma);
NVTT_API void toGamma(float gamma);
private:
void detach();
struct Private;
Private * m;
};
// Return string for the given error code. // Return string for the given error code.
NVTT_API const char * errorString(Error e); NVTT_API const char * errorString(Error e);

@ -60,7 +60,7 @@ int main(int argc, char *argv[])
// Output compressed image. // Output compressed image.
context.outputHeader(image, image.countMipmaps(), compressionOptions, outputOptions); context.outputHeader(image, image.countMipmaps(), compressionOptions, outputOptions);
image.flipVertically(); image.flipY();
image.setAlphaMode(nvtt::AlphaMode_Transparency); image.setAlphaMode(nvtt::AlphaMode_Transparency);
// Output first mipmap. // Output first mipmap.

@ -95,7 +95,7 @@ int main(int argc, char *argv[])
// Output header and first mipmap. // Output header and first mipmap.
context.outputHeader(colorMap, colorMap.countMipmaps(), colorCompressionOptions, colorOutputOptions); context.outputHeader(colorMap, colorMap.countMipmaps(), colorCompressionOptions, colorOutputOptions);
colorMap.flipVertically(); colorMap.flipY();
colorMap.setAlphaMode(nvtt::AlphaMode_Transparency); colorMap.setAlphaMode(nvtt::AlphaMode_Transparency);
context.compress(colorMap, 0, 0, colorCompressionOptions, colorOutputOptions); context.compress(colorMap, 0, 0, colorCompressionOptions, colorOutputOptions);
@ -103,7 +103,7 @@ int main(int argc, char *argv[])
if (inputFileNameNormal != NULL) { if (inputFileNameNormal != NULL) {
context.outputHeader(normalMap, normalMap.countMipmaps(), normalCompressionOptions, normalOutputOptions); context.outputHeader(normalMap, normalMap.countMipmaps(), normalCompressionOptions, normalOutputOptions);
normalMap.flipVertically(); normalMap.flipY();
normalMap.setAlphaMode(nvtt::AlphaMode_Transparency); normalMap.setAlphaMode(nvtt::AlphaMode_Transparency);
normalMap.normalizeNormalMap(); normalMap.normalizeNormalMap();
normalMap.copyChannel(colorMap, 3); // Copy alpha channel from color to normal map. normalMap.copyChannel(colorMap, 3); // Copy alpha channel from color to normal map.
@ -118,7 +118,7 @@ int main(int argc, char *argv[])
const float coverage = colorMap.alphaTestCoverage(alphaRef); const float coverage = colorMap.alphaTestCoverage(alphaRef);
// Build and output mipmaps. // Build and output mipmaps.
int m = 1; int m = 1;
while (colorMap.buildNextMipmap(nvtt::MipmapFilter_Kaiser)) while (colorMap.buildNextMipmap(nvtt::MipmapFilter_Kaiser))
{ {
colorMap.scaleAlphaToCoverage(coverage, alphaRef); colorMap.scaleAlphaToCoverage(coverage, alphaRef);
@ -136,7 +136,7 @@ int main(int argc, char *argv[])
context.compress(normalMap, 0, m, normalCompressionOptions, normalOutputOptions); context.compress(normalMap, 0, m, normalCompressionOptions, normalOutputOptions);
} }
m++; m++;
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;

@ -839,7 +839,7 @@ int main(int argc, char *argv[])
outputFileName.format("%s/%s", outPath, set.fileNames[i]); outputFileName.format("%s/%s", outPath, set.fileNames[i]);
outputFileName.stripExtension(); outputFileName.stripExtension();
if (set.type == ImageType_HDR) outputFileName.append(".dds"); if (set.type == ImageType_HDR) outputFileName.append(".dds");
else outputFileName.append(".png"); else outputFileName.append(".tga");
if (!img.save(outputFileName.str())) if (!img.save(outputFileName.str()))
{ {
printf("Error saving file '%s'.\n", outputFileName.str()); printf("Error saving file '%s'.\n", outputFileName.str());
@ -851,7 +851,7 @@ int main(int argc, char *argv[])
outputFileName.format("%s/%s", outputFilePath.str(), set.fileNames[i]); outputFileName.format("%s/%s", outputFilePath.str(), set.fileNames[i]);
outputFileName.stripExtension(); outputFileName.stripExtension();
if (set.type == ImageType_HDR) outputFileName.append(".dds"); if (set.type == ImageType_HDR) outputFileName.append(".dds");
else outputFileName.append(".png"); else outputFileName.append(".tga");
if (!img_out.save(outputFileName.str())) if (!img_out.save(outputFileName.str()))
{ {
printf("Error saving file '%s'.\n", outputFileName.str()); printf("Error saving file '%s'.\n", outputFileName.str());
@ -886,7 +886,7 @@ int main(int argc, char *argv[])
outputFileName.format("%s/%s", outputFilePath.str(), set.fileNames[i]); outputFileName.format("%s/%s", outputFilePath.str(), set.fileNames[i]);
outputFileName.stripExtension(); outputFileName.stripExtension();
outputFileName.append("_diff.png"); outputFileName.append("_diff.tga");
diff.save(outputFileName.str()); diff.save(outputFileName.str());

Loading…
Cancel
Save