merge internal branch:

- some support for floating point images.
- Charles Bloom extrapolation filter.
- misc fixes.
This commit is contained in:
castano 2007-12-03 09:14:19 +00:00
parent 2e41727f81
commit 4373aa758b
16 changed files with 3175 additions and 2959 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,223 +1,223 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_IMAGE_BLOCKDXT_H #ifndef NV_IMAGE_BLOCKDXT_H
#define NV_IMAGE_BLOCKDXT_H #define NV_IMAGE_BLOCKDXT_H
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include <nvimage/nvimage.h> #include <nvimage/nvimage.h>
namespace nv namespace nv
{ {
struct ColorBlock; struct ColorBlock;
class Stream; class Stream;
/// DXT1 block. /// DXT1 block.
struct BlockDXT1 struct BlockDXT1
{ {
Color16 col0; Color16 col0;
Color16 col1; Color16 col1;
union { union {
uint8 row[4]; uint8 row[4];
uint indices; uint indices;
}; };
bool isFourColorMode() const; bool isFourColorMode() const;
uint evaluatePalette(Color32 color_array[4]) const; uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePaletteFast(Color32 color_array[4]) const; uint evaluatePaletteFast(Color32 color_array[4]) const;
void evaluatePalette3(Color32 color_array[4]) const; void evaluatePalette3(Color32 color_array[4]) const;
void evaluatePalette4(Color32 color_array[4]) const; void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void setIndices(int * idx); void setIndices(int * idx);
void flip4(); void flip4();
void flip2(); void flip2();
}; };
/// Return true if the block uses four color mode, false otherwise. /// Return true if the block uses four color mode, false otherwise.
inline bool BlockDXT1::isFourColorMode() const inline bool BlockDXT1::isFourColorMode() const
{ {
return col0.u > col1.u; return col0.u > col1.u;
} }
/// DXT3 alpha block with explicit alpha. /// DXT3 alpha block with explicit alpha.
struct AlphaBlockDXT3 struct AlphaBlockDXT3
{ {
union { union {
struct { struct {
uint alpha0 : 4; uint alpha0 : 4;
uint alpha1 : 4; uint alpha1 : 4;
uint alpha2 : 4; uint alpha2 : 4;
uint alpha3 : 4; uint alpha3 : 4;
uint alpha4 : 4; uint alpha4 : 4;
uint alpha5 : 4; uint alpha5 : 4;
uint alpha6 : 4; uint alpha6 : 4;
uint alpha7 : 4; uint alpha7 : 4;
uint alpha8 : 4; uint alpha8 : 4;
uint alpha9 : 4; uint alpha9 : 4;
uint alphaA : 4; uint alphaA : 4;
uint alphaB : 4; uint alphaB : 4;
uint alphaC : 4; uint alphaC : 4;
uint alphaD : 4; uint alphaD : 4;
uint alphaE : 4; uint alphaE : 4;
uint alphaF : 4; uint alphaF : 4;
}; };
uint16 row[4]; uint16 row[4];
}; };
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void flip4(); void flip4();
void flip2(); void flip2();
}; };
/// DXT3 block. /// DXT3 block.
struct BlockDXT3 struct BlockDXT3
{ {
AlphaBlockDXT3 alpha; AlphaBlockDXT3 alpha;
BlockDXT1 color; BlockDXT1 color;
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void flip4(); void flip4();
void flip2(); void flip2();
}; };
/// DXT5 alpha block. /// DXT5 alpha block.
struct AlphaBlockDXT5 struct AlphaBlockDXT5
{ {
union { union {
struct { struct {
uint64 alpha0 : 8; // 8 uint64 alpha0 : 8; // 8
uint64 alpha1 : 8; // 16 uint64 alpha1 : 8; // 16
uint64 bits0 : 3; // 3 - 19 uint64 bits0 : 3; // 3 - 19
uint64 bits1 : 3; // 6 - 22 uint64 bits1 : 3; // 6 - 22
uint64 bits2 : 3; // 9 - 25 uint64 bits2 : 3; // 9 - 25
uint64 bits3 : 3; // 12 - 28 uint64 bits3 : 3; // 12 - 28
uint64 bits4 : 3; // 15 - 31 uint64 bits4 : 3; // 15 - 31
uint64 bits5 : 3; // 18 - 34 uint64 bits5 : 3; // 18 - 34
uint64 bits6 : 3; // 21 - 37 uint64 bits6 : 3; // 21 - 37
uint64 bits7 : 3; // 24 - 40 uint64 bits7 : 3; // 24 - 40
uint64 bits8 : 3; // 27 - 43 uint64 bits8 : 3; // 27 - 43
uint64 bits9 : 3; // 30 - 46 uint64 bits9 : 3; // 30 - 46
uint64 bitsA : 3; // 33 - 49 uint64 bitsA : 3; // 33 - 49
uint64 bitsB : 3; // 36 - 52 uint64 bitsB : 3; // 36 - 52
uint64 bitsC : 3; // 39 - 55 uint64 bitsC : 3; // 39 - 55
uint64 bitsD : 3; // 42 - 58 uint64 bitsD : 3; // 42 - 58
uint64 bitsE : 3; // 45 - 61 uint64 bitsE : 3; // 45 - 61
uint64 bitsF : 3; // 48 - 64 uint64 bitsF : 3; // 48 - 64
}; };
uint64 u; uint64 u;
}; };
void evaluatePalette(uint8 alpha[8]) const; void evaluatePalette(uint8 alpha[8]) const;
void evaluatePalette8(uint8 alpha[8]) const; void evaluatePalette8(uint8 alpha[8]) const;
void evaluatePalette6(uint8 alpha[8]) const; void evaluatePalette6(uint8 alpha[8]) const;
void indices(uint8 index_array[16]) const; void indices(uint8 index_array[16]) const;
uint index(uint index) const; uint index(uint index) const;
void setIndex(uint index, uint value); void setIndex(uint index, uint value);
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void flip4(); void flip4();
void flip2(); void flip2();
}; };
/// DXT5 block. /// DXT5 block.
struct BlockDXT5 struct BlockDXT5
{ {
AlphaBlockDXT5 alpha; AlphaBlockDXT5 alpha;
BlockDXT1 color; BlockDXT1 color;
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void flip4(); void flip4();
void flip2(); void flip2();
}; };
/// ATI1 block. /// ATI1 block.
struct BlockATI1 struct BlockATI1
{ {
AlphaBlockDXT5 alpha; AlphaBlockDXT5 alpha;
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void flip4(); void flip4();
void flip2(); void flip2();
}; };
/// ATI2 block. /// ATI2 block.
struct BlockATI2 struct BlockATI2
{ {
AlphaBlockDXT5 x; AlphaBlockDXT5 x;
AlphaBlockDXT5 y; AlphaBlockDXT5 y;
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void flip4(); void flip4();
void flip2(); void flip2();
}; };
/// CTX1 block. /// CTX1 block.
struct BlockCTX1 struct BlockCTX1
{ {
uint8 col0[2]; uint8 col0[2];
uint8 col1[2]; uint8 col1[2];
union { union {
uint8 row[4]; uint8 row[4];
uint indices; uint indices;
}; };
void evaluatePalette(Color32 color_array[4]) const; void evaluatePalette(Color32 color_array[4]) const;
void setIndices(int * idx); void setIndices(int * idx);
void decodeBlock(ColorBlock * block) const; void decodeBlock(ColorBlock * block) const;
void flip4(); void flip4();
void flip2(); void flip2();
}; };
// Serialization functions. // Serialization functions.
NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT1 & block); NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT1 & block);
NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT3 & block); NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT3 & block);
NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT3 & block); NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT3 & block);
NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT5 & block); NVIMAGE_API Stream & operator<<(Stream & stream, AlphaBlockDXT5 & block);
NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT5 & block); NVIMAGE_API Stream & operator<<(Stream & stream, BlockDXT5 & block);
NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI1 & block); NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI1 & block);
NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI2 & block); NVIMAGE_API Stream & operator<<(Stream & stream, BlockATI2 & block);
NVIMAGE_API Stream & operator<<(Stream & stream, BlockCTX1 & block); NVIMAGE_API Stream & operator<<(Stream & stream, BlockCTX1 & block);
} // nv namespace } // nv namespace
#endif // NV_IMAGE_BLOCKDXT_H #endif // NV_IMAGE_BLOCKDXT_H

View File

@ -44,6 +44,11 @@ IF(TIFF_FOUND)
INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
ENDIF(TIFF_FOUND) ENDIF(TIFF_FOUND)
IF(OPENEXR_FOUND)
SET(LIBS ${LIBS} ${OPENEXR_LIBRARIES})
INCLUDE_DIRECTORIES(${OPENEXR_INCLUDE_PATHS})
ENDIF(OPENEXR_FOUND)
# targets # targets
ADD_DEFINITIONS(-DNVIMAGE_EXPORTS) ADD_DEFINITIONS(-DNVIMAGE_EXPORTS)

View File

@ -1,122 +1,122 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <nvcore/Ptr.h> #include <nvcore/Ptr.h>
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include <nvimage/NormalMap.h> #include <nvimage/NormalMap.h>
#include <nvimage/Filter.h> #include <nvimage/Filter.h>
#include <nvimage/FloatImage.h> #include <nvimage/FloatImage.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
using namespace nv; using namespace nv;
static float processPixel(const FloatImage * img, uint x, uint y) static float processPixel(const FloatImage * img, uint x, uint y)
{ {
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();
float d = img->pixel(x, y, 0); float d = img->pixel(x, y, 0);
float fx0 = (float) x / w; float fx0 = (float) x / w;
float fy0 = (float) y / h; float fy0 = (float) y / h;
float best_ratio = INF; float best_ratio = INF;
uint best_x = w; uint best_x = w;
uint best_y = h; uint best_y = h;
for (uint yy = 0; yy < h; yy++) for (uint yy = 0; yy < h; yy++)
{ {
for (uint xx = 0; xx < w; xx++) for (uint xx = 0; xx < w; xx++)
{ {
float ch = d - img->pixel(xx, yy, 0); float ch = d - img->pixel(xx, yy, 0);
if (ch > 0) if (ch > 0)
{ {
float dx = float(xx - x); float dx = float(xx - x);
float dy = float(yy - y); float dy = float(yy - y);
float ratio = (dx * dx + dy * dy) / ch; float ratio = (dx * dx + dy * dy) / ch;
if (ratio < best_ratio) if (ratio < best_ratio)
{ {
best_x = xx; best_x = xx;
best_y = yy; best_y = yy;
} }
} }
} }
} }
if (best_x != w) if (best_x != w)
{ {
nvDebugCheck(best_y !=h); nvDebugCheck(best_y !=h);
float dx = float(best_x - x) / w; float dx = float(best_x - x) / w;
float dy = float(best_y - y) / h; float dy = float(best_y - y) / h;
float cw = sqrtf(dx*dx + dy*dy); float cw = sqrtf(dx*dx + dy*dy);
float ch = d - img->pixel(xx, yy, 0); float ch = d - img->pixel(xx, yy, 0);
return min(1, sqrtf(cw / ch)); return min(1, sqrtf(cw / ch));
} }
return 1; return 1;
} }
// Create cone map using the given kernels. // Create cone map using the given kernels.
FloatImage * createConeMap(const Image * img, Vector4::Arg heightWeights) FloatImage * createConeMap(const Image * img, Vector4::Arg heightWeights)
{ {
nvCheck(img != NULL); nvCheck(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(2, w, h); //fimage->allocate(2, w, h);
fimage->allocate(4, w, h); fimage->allocate(4, w, h);
// Compute height and store in red channel: // Compute height and store in red channel:
float * heightChannel = fimage->channel(0); float * heightChannel = fimage->channel(0);
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));
heightChannel[i] = dot(color, heightWeights); heightChannel[i] = dot(color, heightWeights);
} }
// Compute cones: // Compute cones:
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++)
{ {
processPixel(fimage, x, y); processPixel(fimage, x, y);
} }
} }
return fimage.release(); return fimage.release();
} }

View File

@ -1,24 +1,24 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_IMAGE_CONEMAP_H #ifndef NV_IMAGE_CONEMAP_H
@ -29,7 +29,7 @@
namespace nv namespace nv
{ {
class Image; class Image;
class FloatImage; class FloatImage;
FloatImage * createConeMap(const Image * img, Vector4::Arg heightWeights); FloatImage * createConeMap(const Image * img, Vector4::Arg heightWeights);

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +1,152 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_IMAGE_DIRECTDRAWSURFACE_H #ifndef NV_IMAGE_DIRECTDRAWSURFACE_H
#define NV_IMAGE_DIRECTDRAWSURFACE_H #define NV_IMAGE_DIRECTDRAWSURFACE_H
#include <nvimage/nvimage.h> #include <nvimage/nvimage.h>
namespace nv namespace nv
{ {
class Image; class Image;
class Stream; class Stream;
struct ColorBlock; struct ColorBlock;
struct DDSPixelFormat struct DDSPixelFormat
{ {
uint size; uint size;
uint flags; uint flags;
uint fourcc; uint fourcc;
uint bitcount; uint bitcount;
uint rmask; uint rmask;
uint gmask; uint gmask;
uint bmask; uint bmask;
uint amask; uint amask;
}; };
struct DDSCaps struct DDSCaps
{ {
uint caps1; uint caps1;
uint caps2; uint caps2;
uint caps3; uint caps3;
uint caps4; uint caps4;
}; };
/// DDS file header for DX10. /// DDS file header for DX10.
struct DDSHeader10 struct DDSHeader10
{ {
uint dxgiFormat; uint dxgiFormat;
uint resourceDimension; uint resourceDimension;
uint miscFlag; uint miscFlag;
uint arraySize; uint arraySize;
uint reserved; uint reserved;
}; };
/// DDS file header. /// DDS file header.
struct DDSHeader struct DDSHeader
{ {
uint fourcc; uint fourcc;
uint size; uint size;
uint flags; uint flags;
uint height; uint height;
uint width; uint width;
uint pitch; uint pitch;
uint depth; uint depth;
uint mipmapcount; uint mipmapcount;
uint reserved[11]; uint reserved[11];
DDSPixelFormat pf; DDSPixelFormat pf;
DDSCaps caps; DDSCaps caps;
uint notused; uint notused;
DDSHeader10 header10; DDSHeader10 header10;
// Helper methods. // Helper methods.
DDSHeader(); DDSHeader();
void setWidth(uint w); void setWidth(uint w);
void setHeight(uint h); void setHeight(uint h);
void setDepth(uint d); void setDepth(uint d);
void setMipmapCount(uint count); void setMipmapCount(uint count);
void setTexture2D(); void setTexture2D();
void setTexture3D(); void setTexture3D();
void setTextureCube(); void setTextureCube();
void setLinearSize(uint size); void setLinearSize(uint size);
void setPitch(uint pitch); void setPitch(uint pitch);
void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3); void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask); void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
void setDX10Format(uint format); void setDX10Format(uint format);
void setNormalFlag(bool b); void setNormalFlag(bool b);
void swapBytes(); void swapBytes();
bool hasDX10Header() const; bool hasDX10Header() const;
}; };
NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header); NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header);
/// DirectDraw Surface. (DDS) /// DirectDraw Surface. (DDS)
class NVIMAGE_CLASS DirectDrawSurface class NVIMAGE_CLASS DirectDrawSurface
{ {
public: public:
DirectDrawSurface(const char * file); DirectDrawSurface(const char * file);
~DirectDrawSurface(); ~DirectDrawSurface();
bool isValid() const; bool isValid() const;
bool isSupported() const; bool isSupported() const;
uint mipmapCount() const; uint mipmapCount() const;
uint width() const; uint width() const;
uint height() const; uint height() const;
uint depth() const; uint depth() const;
bool isTexture2D() const; bool isTexture2D() const;
bool isTexture3D() const; bool isTexture3D() const;
bool isTextureCube() const; bool isTextureCube() const;
void mipmap(Image * img, uint f, uint m); void mipmap(Image * img, uint f, uint m);
// void mipmap(FloatImage * img, uint f, uint m); // void mipmap(FloatImage * img, uint f, uint m);
void printInfo() const; void printInfo() const;
private: private:
uint blockSize() const; uint blockSize() const;
uint faceSize() const; uint faceSize() const;
uint mipmapSize(uint m) const; uint mipmapSize(uint m) const;
uint offset(uint f, uint m); uint offset(uint f, uint m);
void readLinearImage(Image * img); void readLinearImage(Image * img);
void readBlockImage(Image * img); void readBlockImage(Image * img);
void readBlock(ColorBlock * rgba); void readBlock(ColorBlock * rgba);
private: private:
Stream * const stream; Stream * const stream;
DDSHeader header; DDSHeader header;
DDSHeader10 header10; DDSHeader10 header10;
}; };
} // nv namespace } // nv namespace
#endif // NV_IMAGE_DIRECTDRAWSURFACE_H #endif // NV_IMAGE_DIRECTDRAWSURFACE_H

View File

@ -15,15 +15,29 @@ using namespace nv;
namespace namespace
{ {
static int round(float f) static int iround(float f)
{ {
return int(f); return int(f);
} }
static int ifloor(float f)
{
return int(floor(f));
}
static float frac(float f) static float frac(float f)
{ {
return f - floor(f); return f - floor(f);
} }
static int mirror(int x, int w)
{
x = fabs(x);
while (x >= w) {
x = 2 * w - x - 2;
}
return x;
}
} }
@ -161,7 +175,7 @@ void FloatImage::normalize(uint base_component)
for(uint i = 0; i < size; i++) { for(uint i = 0; i < size; i++) {
Vector3 normal(xChannel[i], yChannel[i], zChannel[i]); Vector3 normal(xChannel[i], yChannel[i], zChannel[i]);
normal = normalizeSafe(normal, Vector3(zero)); normal = normalizeSafe(normal, Vector3(zero), 0.0f);
xChannel[i] = normal.x(); xChannel[i] = normal.x();
yChannel[i] = normal.y(); yChannel[i] = normal.y();
@ -226,72 +240,42 @@ void FloatImage::exponentiate(uint base_component, uint num, float power)
} }
} }
#if 0 float FloatImage::sampleNearest(const float x, const float y, const int c, const WrapMode wm) const
float FloatImage::nearest(float x, float y, int c, WrapMode wm) const
{ {
if( wm == WrapMode_Clamp ) return nearest_clamp(x, y, c); if( wm == WrapMode_Clamp ) return sampleNearestClamp(x, y, c);
/*if( wm == WrapMode_Repeat )*/ return nearest_repeat(x, y, c); else if( wm == WrapMode_Repeat ) return sampleNearestRepeat(x, y, c);
//if( wm == WrapMode_Mirror ) return nearest_mirror(x, y, c); else /*if( wm == WrapMode_Mirror )*/ return sampleNearestMirror(x, y, c);
} }
float FloatImage::nearest_clamp(int x, int y, const int c) const float FloatImage::sampleLinear(const float x, const float y, const int c, const WrapMode wm) const
{ {
const int w = m_width; if( wm == WrapMode_Clamp ) return sampleLinearClamp(x, y, c);
const int h = m_height; else if( wm == WrapMode_Repeat ) return sampleLinearRepeat(x, y, c);
int ix = ::clamp(x, 0, w-1); else /*if( wm == WrapMode_Mirror )*/ return sampleLinearMirror(x, y, c);
int iy = ::clamp(y, 0, h-1); }
float FloatImage::sampleNearestClamp(const float x, const float y, const int c) const
{
int ix = ::clamp(iround(x * m_width), 0, m_width-1);
int iy = ::clamp(iround(y * m_height), 0, m_height-1);
return pixel(ix, iy, c); return pixel(ix, iy, c);
} }
float FloatImage::nearest_repeat(int x, int y, const int c) const float FloatImage::sampleNearestRepeat(const float x, const float y, const int c) const
{ {
const int w = m_width; int ix = iround(frac(x) * m_width);
const int h = m_height; int iy = iround(frac(y) * m_height);
int ix = x % w;
int iy = y % h;
return pixel(ix, iy, c);
}
#endif
float FloatImage::nearest(float x, float y, int c, WrapMode wm) const
{
if( wm == WrapMode_Clamp ) return nearest_clamp(x, y, c);
/*if( wm == WrapMode_Repeat )*/ return nearest_repeat(x, y, c);
//if( wm == WrapMode_Mirror ) return nearest_mirror(x, y, c);
}
float FloatImage::linear(float x, float y, int c, WrapMode wm) const
{
if( wm == WrapMode_Clamp ) return linear_clamp(x, y, c);
/*if( wm == WrapMode_Repeat )*/ return linear_repeat(x, y, c);
//if( wm == WrapMode_Mirror ) return linear_mirror(x, y, c);
}
float FloatImage::nearest_clamp(float x, float y, const int c) const
{
const int w = m_width;
const int h = m_height;
int ix = ::clamp(round(x * w), 0, w-1);
int iy = ::clamp(round(y * h), 0, h-1);
return pixel(ix, iy, c); return pixel(ix, iy, c);
} }
float FloatImage::nearest_repeat(float x, float y, const int c) const float FloatImage::sampleNearestMirror(const float x, const float y, const int c) const
{ {
const int w = m_width; int ix = mirror(iround(x * m_width), m_width);
const int h = m_height; int iy = mirror(iround(y * m_height), m_height);
int ix = round(frac(x) * w);
int iy = round(frac(y) * h);
return pixel(ix, iy, c); return pixel(ix, iy, c);
} }
float FloatImage::nearest_mirror(float x, float y, const int c) const float FloatImage::sampleLinearClamp(float x, float y, const int c) const
{
// @@ TBD
return 0.0f;
}
float FloatImage::linear_clamp(float x, float y, const int c) const
{ {
const int w = m_width; const int w = m_width;
const int h = m_height; const int h = m_height;
@ -302,10 +286,10 @@ float FloatImage::linear_clamp(float x, float y, const int c) const
const float fracX = frac(x); const float fracX = frac(x);
const float fracY = frac(y); const float fracY = frac(y);
const int ix0 = ::clamp(round(x), 0, w-1); const int ix0 = ::clamp(ifloor(x), 0, w-1);
const int iy0 = ::clamp(round(y), 0, h-1); const int iy0 = ::clamp(ifloor(y), 0, h-1);
const int ix1 = ::clamp(round(x)+1, 0, w-1); const int ix1 = ::clamp(ifloor(x)+1, 0, w-1);
const int iy1 = ::clamp(round(y)+1, 0, h-1); const int iy1 = ::clamp(ifloor(y)+1, 0, h-1);
float f1 = pixel(ix0, iy0, c); float f1 = pixel(ix0, iy0, c);
float f2 = pixel(ix1, iy0, c); float f2 = pixel(ix1, iy0, c);
@ -318,7 +302,7 @@ float FloatImage::linear_clamp(float x, float y, const int c) const
return lerp(i1, i2, fracY); return lerp(i1, i2, fracY);
} }
float FloatImage::linear_repeat(float x, float y, int c) const float FloatImage::sampleLinearRepeat(float x, float y, int c) const
{ {
const int w = m_width; const int w = m_width;
const int h = m_height; const int h = m_height;
@ -326,10 +310,10 @@ float FloatImage::linear_repeat(float x, float y, int c) const
const float fracX = frac(x * w); const float fracX = frac(x * w);
const float fracY = frac(y * h); const float fracY = frac(y * h);
int ix0 = round(frac(x) * w); int ix0 = ifloor(frac(x) * w);
int iy0 = round(frac(y) * h); int iy0 = ifloor(frac(y) * h);
int ix1 = round(frac(x + 1.0f/w) * w); int ix1 = ifloor(frac(x + 1.0f/w) * w);
int iy1 = round(frac(y + 1.0f/h) * h); int iy1 = ifloor(frac(y + 1.0f/h) * h);
float f1 = pixel(ix0, iy0, c); float f1 = pixel(ix0, iy0, c);
float f2 = pixel(ix1, iy0, c); float f2 = pixel(ix1, iy0, c);
@ -342,10 +326,31 @@ float FloatImage::linear_repeat(float x, float y, int c) const
return lerp(i1, i2, fracY); return lerp(i1, i2, fracY);
} }
float FloatImage::linear_mirror(float x, float y, int c) const float FloatImage::sampleLinearMirror(float x, float y, int c) const
{ {
// @@ TBD const int w = m_width;
return 0.0f; const int h = m_height;
x *= w;
y *= h;
const float fracX = frac(x);
const float fracY = frac(y);
int ix0 = mirror(x, w);
int iy0 = mirror(y, h);
int ix1 = mirror(x + 1, w);
int iy1 = mirror(y + 1, h);
float f1 = pixel(ix0, iy0, c);
float f2 = pixel(ix1, iy0, c);
float f3 = pixel(ix0, iy1, c);
float f4 = pixel(ix1, iy1, c);
float i1 = lerp(f1, f2, fracX);
float i2 = lerp(f3, f4, fracX);
return lerp(i1, i2, fracY);
} }

View File

@ -97,18 +97,16 @@ public:
void setPixel(float f, uint idx); void setPixel(float f, uint idx);
float pixel(uint idx) const; float pixel(uint idx) const;
float nearest(int x, int y, int c, WrapMode wm) const; float sampleNearest(float x, float y, int c, WrapMode wm) const;
float sampleLinear(float x, float y, int c, WrapMode wm) const;
float nearest(float x, float y, int c, WrapMode wm) const; float sampleNearestClamp(float x, float y, int c) const;
float linear(float x, float y, int c, WrapMode wm) const; float sampleNearestRepeat(float x, float y, int c) const;
float sampleNearestMirror(float x, float y, int c) const;
float nearest_clamp(float x, float y, int c) const; float sampleLinearClamp(float x, float y, int c) const;
float nearest_repeat(float x, float y, int c) const; float sampleLinearRepeat(float x, float y, int c) const;
float nearest_mirror(float x, float y, int c) const; float sampleLinearMirror(float x, float y, int c) const;
float linear_clamp(float x, float y, int c) const;
float linear_repeat(float x, float y, int c) const;
float linear_mirror(float x, float y, int c) const;
//@} //@}
public: public:

View File

@ -1,6 +1,7 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- castanyo@yahoo.es
#include <nvcore/Containers.h> #include <nvcore/Containers.h>
#include <nvcore/Ptr.h>
#include <nvmath/nvmath.h> #include <nvmath/nvmath.h>
@ -11,7 +12,7 @@ using namespace nv;
// This is a variation of Sapiro's inpainting method. // This is a variation of Sapiro's inpainting method.
void nv::fillExtrapolateOnce(FloatImage * img, BitMap * bmap) void nv::fillExtrapolate(int passCount, FloatImage * img, BitMap * bmap)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
nvCheck(bmap != NULL); nvCheck(bmap != NULL);
@ -23,83 +24,73 @@ void nv::fillExtrapolateOnce(FloatImage * img, BitMap * bmap)
nvCheck(bmap->width() == uint(w)); nvCheck(bmap->width() == uint(w));
nvCheck(bmap->height() == uint(h)); nvCheck(bmap->height() == uint(h));
BitMap * newbmap = new BitMap(w, h); AutoPtr<BitMap> newbmap(new BitMap(w, h));
for(int c = 0; c < count; c++) { for(int p = 0; p < passCount; p++)
{
float * channel = img->channel(c); for(int c = 0; c < count; c++)
{
for(int y = 0; y < h; y++) { float * channel = img->channel(c);
for(int x = 0; x < w; x++) {
for(int y = 0; y < h; y++) {
if (bmap->bitAt(x, y)) { for(int x = 0; x < w; x++) {
// Not a hole.
newbmap->setBitAt(x, y);
continue;
}
const bool west = bmap->bitAt(img->indexClamp(x-1, y));
const bool east = bmap->bitAt(img->indexClamp(x+1, y));
const bool north = bmap->bitAt(img->indexClamp(x, y-1));
const bool south = bmap->bitAt(img->indexClamp(x, y+1));
const bool northwest = bmap->bitAt(img->indexClamp(x-1, y-1));
const bool northeast = bmap->bitAt(img->indexClamp(x+1, y-1));
const bool southwest = bmap->bitAt(img->indexClamp(x-1, y+1));
const bool southeast = bmap->bitAt(img->indexClamp(x+1, y+1));
int num = west + east + north + south + northwest + northeast + southwest + southeast;
if (num != 0) {
float average = 0.0f;
if (num == 3 && west && northwest && southwest) {
average = channel[img->indexClamp(x-1, y)];
}
else if (num == 3 && east && northeast && southeast) {
average = channel[img->indexClamp(x+1, y)];
}
else if (num == 3 && north && northwest && northeast) {
average = channel[img->indexClamp(x, y-1)];
}
else if (num == 3 && south && southwest && southeast) {
average = channel[img->indexClamp(x, y+1)];
}
else {
float total = 0.0f;
if (west) { average += 1 * channel[img->indexClamp(x-1, y)]; total += 1; }
if (east) { average += 1 * channel[img->indexClamp(x+1, y)]; total += 1; }
if (north) { average += 1 * channel[img->indexClamp(x, y-1)]; total += 1; }
if (south) { average += 1 * channel[img->indexClamp(x, y+1)]; total += 1; }
if (northwest) { average += channel[img->indexClamp(x-1, y-1)]; ++total; } if (bmap->bitAt(x, y)) {
if (northeast) { average += channel[img->indexClamp(x+1, y-1)]; ++total; } // Not a hole.
if (southwest) { average += channel[img->indexClamp(x-1, y+1)]; ++total; } newbmap->setBitAt(x, y);
if (southeast) { average += channel[img->indexClamp(x+1, y+1)]; ++total; } continue;
average /= total;
} }
const bool west = bmap->bitAt(img->indexClamp(x-1, y));
const bool east = bmap->bitAt(img->indexClamp(x+1, y));
const bool north = bmap->bitAt(img->indexClamp(x, y-1));
const bool south = bmap->bitAt(img->indexClamp(x, y+1));
const bool northwest = bmap->bitAt(img->indexClamp(x-1, y-1));
const bool northeast = bmap->bitAt(img->indexClamp(x+1, y-1));
const bool southwest = bmap->bitAt(img->indexClamp(x-1, y+1));
const bool southeast = bmap->bitAt(img->indexClamp(x+1, y+1));
int num = west + east + north + south + northwest + northeast + southwest + southeast;
if (num != 0) {
channel[img->indexClamp(x, y)] = average; float average = 0.0f;
newbmap->setBitAt(x, y); if (num == 3 && west && northwest && southwest) {
average = channel[img->indexClamp(x-1, y)];
}
else if (num == 3 && east && northeast && southeast) {
average = channel[img->indexClamp(x+1, y)];
}
else if (num == 3 && north && northwest && northeast) {
average = channel[img->indexClamp(x, y-1)];
}
else if (num == 3 && south && southwest && southeast) {
average = channel[img->indexClamp(x, y+1)];
}
else {
float total = 0.0f;
if (west) { average += 1 * channel[img->indexClamp(x-1, y)]; total += 1; }
if (east) { average += 1 * channel[img->indexClamp(x+1, y)]; total += 1; }
if (north) { average += 1 * channel[img->indexClamp(x, y-1)]; total += 1; }
if (south) { average += 1 * channel[img->indexClamp(x, y+1)]; total += 1; }
if (northwest) { average += channel[img->indexClamp(x-1, y-1)]; ++total; }
if (northeast) { average += channel[img->indexClamp(x+1, y-1)]; ++total; }
if (southwest) { average += channel[img->indexClamp(x-1, y+1)]; ++total; }
if (southeast) { average += channel[img->indexClamp(x+1, y+1)]; ++total; }
average /= total;
}
channel[img->indexClamp(x, y)] = average;
newbmap->setBitAt(x, y);
}
} }
} }
} }
}
// Update the bit mask. // Update the bit mask.
swap(*newbmap, *bmap); swap(*newbmap, *bmap);
}
void nv::fillExtrapolateNTimes(FloatImage * img, BitMap * bmap, int n)
{
nvCheck(img != NULL);
nvCheck(bmap != NULL);
nvCheck(n > 0);
for(int i = 0; i < n; i++)
{
fillExtrapolateOnce(img, bmap);
} }
} }
@ -134,7 +125,7 @@ namespace {
} // namespace } // namespace
// Voronoi filling using EDT-4 // Voronoi filling using EDT-4
void nv::fillVoronoi(FloatImage * img, const BitMap & bmap) void nv::fillVoronoi(FloatImage * img, const BitMap * bmap)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
@ -142,8 +133,8 @@ void nv::fillVoronoi(FloatImage * img, const BitMap & bmap)
const int h = img->height(); const int h = img->height();
const int count = img->componentNum(); const int count = img->componentNum();
nvCheck(bmap.width() == uint(w)); nvCheck(bmap->width() == uint(w));
nvCheck(bmap.height() == uint(h)); nvCheck(bmap->height() == uint(h));
Array<Neighbor> edm; Array<Neighbor> edm;
edm.resize(w * h); edm.resize(w * h);
@ -154,7 +145,7 @@ void nv::fillVoronoi(FloatImage * img, const BitMap & bmap)
// Init edm. // Init edm.
for( y = 0; y < h; y++ ) { for( y = 0; y < h; y++ ) {
for( x = 0; x < w; x++ ) { for( x = 0; x < w; x++ ) {
if( bmap.bitAt(x, y) ) { if( bmap->bitAt(x, y) ) {
edm[y * w + x].x = x; edm[y * w + x].x = x;
edm[y * w + x].y = y; edm[y * w + x].y = y;
edm[y * w + x].d = 0; edm[y * w + x].d = 0;
@ -229,7 +220,7 @@ void nv::fillVoronoi(FloatImage * img, const BitMap & bmap)
} }
void nv::fillBlur(FloatImage * img, const BitMap & bmap) void nv::fillBlur(FloatImage * img, const BitMap * bmap)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
@ -306,7 +297,7 @@ static bool downsample(const FloatImage * src, const BitMap * srcMask, const Flo
} }
// This is the filter used in the Lumigraph paper. The Unreal engine uses something similar. // This is the filter used in the Lumigraph paper. The Unreal engine uses something similar.
void nv::fillPullPush(FloatImage * img, const BitMap & bmap) void nv::fillPullPush(FloatImage * img, const BitMap * bmap)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
@ -320,7 +311,7 @@ void nv::fillPullPush(FloatImage * img, const BitMap & bmap)
Array<const BitMap *> mipmapMasks(num); Array<const BitMap *> mipmapMasks(num);
mipmaps.append(img); mipmaps.append(img);
mipmapMasks.append(&bmap); mipmapMasks.append(bmap);
const FloatImage * current; const FloatImage * current;
const BitMap * currentMask; const BitMap * currentMask;
@ -336,16 +327,22 @@ void nv::fillPullPush(FloatImage * img, const BitMap & bmap)
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++) {
uint sx = x; int sx = x;
uint sy = y; int sy = y;
//float sx = x;
//float sy = y;
const uint levelCount = mipmaps.count(); const uint levelCount = mipmaps.count();
for(uint l = 0; l < levelCount; l++) { for (uint l = 0; l < levelCount; l++)
{
//const float fx = sx / mipmaps[l]->width();
//const float fy = sy / mipmaps[l]->height();
if (mipmapMasks[l]->bitAt(sx, sy)) if (mipmapMasks[l]->bitAt(sx, sy))
{ {
// Sample mipmaps[l](sx, sy) and copy to img(x, y) // Sample mipmaps[l](sx, sy) and copy to img(x, y)
for(uint c = 0; c < count; c++) { for(uint c = 0; c < count; c++) {
//img->setPixel(mipmaps[l]->linear_clamp(fx, fy, c), x, y, c);
img->setPixel(mipmaps[l]->pixel(sx, sy, c), x, y, c); img->setPixel(mipmaps[l]->pixel(sx, sy, c), x, y, c);
} }
break; break;
@ -357,20 +354,20 @@ void nv::fillPullPush(FloatImage * img, const BitMap & bmap)
} }
} }
// Don't delete the original image and mask.
mipmaps[0] = NULL;
mipmapMasks[0] = NULL;
// Delete the mipmaps.
deleteAll(mipmaps); deleteAll(mipmaps);
deleteAll(mipmapMasks); deleteAll(mipmapMasks);
} }
/* /*
void nv::fillSeamFix(FloatImage * img, const BitMap & bmap)
{
}
*/
#if 0 // Code below is under the BPL license.
This Code is from Charles Bloom:
/**
DoPixelSeamFix DoPixelSeamFix
10-20-02 10-20-02
@ -386,7 +383,7 @@ Note that I'm working on normals, but I treat them just as 3 scalars and normali
at the end. To be more correct, I would work on the surface of a sphere, but that at the end. To be more correct, I would work on the surface of a sphere, but that
just seems like way too much work. just seems like way too much work.
**/ */
struct LocalPixels struct LocalPixels
{ {
@ -395,11 +392,11 @@ struct LocalPixels
// index [y][x] // index [y][x]
bool fill[5][5]; bool fill[5][5];
float data[5][5]; float data[5][5];
mutable float result; mutable float result;
mutable float weight; mutable float weight;
bool Quad3SubH(float * pQ, int row) const
bool Quad3SubH(gVec4 * pQ,int row) const
{ {
const bool * pFill = fill[row]; const bool * pFill = fill[row];
const float * pDat = data[row]; const float * pDat = data[row];
@ -426,7 +423,7 @@ struct LocalPixels
} }
// improve result with a horizontal quad in row 1 and/or // improve result with a horizontal quad in row 1 and/or
bool Quad3SubV(gVec4 * pQ,int col) const bool Quad3SubV(float * pQ, int col) const
{ {
if ( fill[1][col] && fill[2][col] && fill[3][col] ) if ( fill[1][col] && fill[2][col] && fill[3][col] )
{ {
@ -449,14 +446,14 @@ struct LocalPixels
return false; return false;
} }
bool Quad3H(gVec4 * pQ) const bool Quad3H(float * pQ) const
{ {
if ( ! Quad3SubH(pQ,1) ) if (!Quad3SubH(pQ,1))
{ {
return Quad3SubH(pQ,3); return Quad3SubH(pQ,3);
} }
gVec4 q(0,0,0,0); // initializer not needed, just make it shut up float q = 0.0f; // initializer not needed, just make it shut up
if ( Quad3SubH(&q,3) ) if (Quad3SubH(&q, 3))
{ {
// got q and pQ // got q and pQ
*pQ = (*pQ+q)*0.5f; *pQ = (*pQ+q)*0.5f;
@ -464,17 +461,17 @@ struct LocalPixels
return true; return true;
} }
bool Quad3V(gVec4 * pQ) const bool Quad3V(float * pQ) const
{ {
if ( ! Quad3SubV(pQ,1) ) if (!Quad3SubV(pQ, 1))
{ {
return Quad3SubV(pQ,3); return Quad3SubV(pQ, 3);
} }
gVec4 q(0,0,0,0); // initializer not needed, just make it shut up float q = 0.0f; // initializer not needed, just make it shut up
if ( Quad3SubV(&q,3) ) if (Quad3SubV(&q, 3))
{ {
// got q and pQ // got q and pQ
*pQ = (*pQ+q)*0.5f; *pQ = (*pQ + q) * 0.5f;
} }
return true; return true;
} }
@ -482,7 +479,7 @@ struct LocalPixels
// a common want is [1] - ([0]+[2])*0.5f ; // a common want is [1] - ([0]+[2])*0.5f ;
// so use -0.5f*Quad // so use -0.5f*Quad
bool TryQuads() const bool tryQuads() const
{ {
bool res = false; bool res = false;
@ -490,7 +487,7 @@ struct LocalPixels
if ( fill[2][1] && fill[2][3] ) if ( fill[2][1] && fill[2][3] )
{ {
// got horizontal straddle // got horizontal straddle
gVec4 q; float q;
if ( Quad3H(&q) ) if ( Quad3H(&q) )
{ {
result += (data[2][1] + data[2][3] - q) * 0.5f; result += (data[2][1] + data[2][3] - q) * 0.5f;
@ -501,7 +498,7 @@ struct LocalPixels
if ( fill[1][2] && fill[3][2] ) if ( fill[1][2] && fill[3][2] )
{ {
// got vertical straddle // got vertical straddle
gVec4 q; float q;
if ( Quad3V(&q) ) if ( Quad3V(&q) )
{ {
result += (data[1][2] + data[3][2] - q) * 0.5f; result += (data[1][2] + data[3][2] - q) * 0.5f;
@ -514,7 +511,7 @@ struct LocalPixels
if ( fill[2][0] && fill[2][1] ) if ( fill[2][0] && fill[2][1] )
{ {
// got left-side pair // got left-side pair
gVec4 q; float q;
if ( Quad3H(&q) ) if ( Quad3H(&q) )
{ {
result += data[2][1]*2.f - data[2][0] + q; result += data[2][1]*2.f - data[2][0] + q;
@ -525,7 +522,7 @@ struct LocalPixels
if ( fill[2][3] && fill[2][4] ) if ( fill[2][3] && fill[2][4] )
{ {
// got right-side pair // got right-side pair
gVec4 q; float q;
if ( Quad3H(&q) ) if ( Quad3H(&q) )
{ {
result += data[2][3]*2.f - data[2][4] + q; result += data[2][3]*2.f - data[2][4] + q;
@ -536,7 +533,7 @@ struct LocalPixels
if ( fill[0][2] && fill[1][2] ) if ( fill[0][2] && fill[1][2] )
{ {
// got left-side pair // got left-side pair
gVec4 q; float q;
if ( Quad3V(&q) ) if ( Quad3V(&q) )
{ {
result += data[1][2]*2.f - data[0][2] + q; result += data[1][2]*2.f - data[0][2] + q;
@ -547,7 +544,7 @@ struct LocalPixels
if ( fill[3][2] && fill[4][2] ) if ( fill[3][2] && fill[4][2] )
{ {
// got right-side pair // got right-side pair
gVec4 q; float q;
if ( Quad3V(&q) ) if ( Quad3V(&q) )
{ {
result += data[3][2]*2.f - data[4][2] + q; result += data[3][2]*2.f - data[4][2] + q;
@ -558,7 +555,7 @@ struct LocalPixels
return res; return res;
} }
bool TryPlanar() const bool tryPlanar() const
{ {
// four cases : // four cases :
const int indices[] = const int indices[] =
@ -569,37 +566,37 @@ struct LocalPixels
2,3, 3,2, 3,3 2,3, 3,2, 3,3
}; };
bool res = false; bool res = false;
for(int i=0;i<4;i++) for (int i = 0; i < 4; i++)
{ {
const int * I = indices + i*6; const int * I = indices + i*6;
if ( ! fill[ I[0] ][ I[1] ] ) if (!fill[ I[0] ][ I[1] ])
continue; continue;
if ( ! fill[ I[2] ][ I[3] ] ) if (!fill[ I[2] ][ I[3] ])
continue; continue;
if ( ! fill[ I[4] ][ I[5] ] ) if (!fill[ I[4] ][ I[5] ])
continue; continue;
result += data[ I[0] ][ I[1] ] + data[ I[2] ][ I[3] ] - data[ I[4] ][ I[5] ]; result += data[ I[0] ][ I[1] ] + data[ I[2] ][ I[3] ] - data[ I[4] ][ I[5] ];
weight += 1.f; weight += 1.0f;
res = true; res = true;
} }
return res; return res;
} }
bool TryTwos() const bool tryTwos() const
{ {
bool res = false; bool res = false;
if ( fill[2][1] && fill[2][3] ) if (fill[2][1] && fill[2][3])
{ {
result += (data[2][1] + data[2][3]) * 0.5f; result += (data[2][1] + data[2][3]) * 0.5f;
weight += 1.f; weight += 1.0f;
res = true; res = true;
} }
if ( fill[1][2] && fill[3][2] ) if (fill[1][2] && fill[3][2])
{ {
result += (data[1][2] + data[3][2]) * 0.5f; result += (data[1][2] + data[3][2]) * 0.5f;
weight += 1.f; weight += 1.0f;
res = true; res = true;
} }
@ -611,141 +608,146 @@ struct LocalPixels
1,2, 0,2, 1,2, 0,2,
3,2, 4,2, 3,2, 4,2,
}; };
for(int i=0;i<4;i++) for (int i = 0; i < 4; i++)
{ {
const int * I = indices + i*4; const int * I = indices + i*4;
if ( ! fill[ I[0] ][ I[1] ] ) if (!fill[ I[0] ][ I[1] ])
continue; continue;
if ( ! fill[ I[2] ][ I[3] ] ) if (!fill[ I[2] ][ I[3] ])
continue; continue;
result += data[ I[0] ][ I[1] ]*2.f - data[ I[2] ][ I[3] ]; result += data[ I[0] ][ I[1] ]*2.0f - data[ I[2] ][ I[3] ];
weight += 1.f; weight += 1.0f;
res = true; res = true;
} }
return res; return res;
} }
bool doLocalPixelFill() const
bool DoLocalPixelFill() const
{ {
result = gVec4::zero; result = 0.0f;
weight = 0.f; weight = 0.0f;
if ( TryQuads() ) if (tryQuads()) {
return true; return true;
}
if ( TryPlanar() )
if (tryPlanar()) {
return true; return true;
}
return TryTwos();
return tryTwos();
} }
}; // LocalPixels ----------------------------------------------- }; // struct LocalPixels
void gNormalMap::DoPixelSeamFix()
// This is a cubic extrapolation filter from Charles Bloom (DoPixelSeamFix).
void nv::fillCubicExtrapolate(int passCount, FloatImage * img, BitMap * bmap, int coverageIndex /*= -1*/)
{ {
gLog::Printf("gNormalMap::DoPixelSeamFix.."); nvCheck(passCount > 0);
nvCheck(img != NULL);
nvCheck(bmap != NULL);
const int desiredTicks = 30; const int w = img->width();
const int heightPerTick = NUM_SEAMFIX_PASSES * m_height / desiredTicks; const int h = img->height();
int tick = 0; const int count = img->componentNum();
for(int pass=0;pass<NUM_SEAMFIX_PASSES;pass++) nvCheck(bmap->width() == uint(w));
nvCheck(bmap->height() == uint(h));
AutoPtr<BitMap> newbmap( new BitMap(w, h) );
float * coverageChannel = NULL;
if (coverageIndex != -1)
{ {
for(int yb=0;yb<m_height;yb++) coverageChannel = img->channel(coverageIndex);
{ }
gVec4 * pRow = m_normals + m_width * yb;
const EState * pStateRow = m_states + m_width * yb;
for(int xb=0;xb<m_width;xb++)
{
if ( pStateRow[xb] != eNull && pStateRow[xb] != eEdge )
{
ASSERT( ! IsNull(pRow[xb]) );
continue; // it's got a pixel
}
// can be non-null, if it wasn't actually inside any tri,
// but got the anti-aliased edge effect of a tri
// replace edge pixels with seam-fix here
//ASSERT( IsNull(pRow[xb]) );
// make the local neighborhood: int firstChannel = -1;
int numFill = 0;
LocalPixels lp; for (int p = 0; p < passCount; p++)
for(int ny=0;ny<5;ny++) {
{ for (int c = 0; c < count; c++)
int y = (yb + ny - 2); {
if ( y < 0 || y >= m_height ) if (c == coverageIndex) continue;
{ if (firstChannel == -1) firstChannel = c;
// out of range
for(int i=0;i<5;i++) float * channel = img->channel(c);
{
lp.fill[ny][i] = false; for (int yb = 0; yb < h; yb++) {
} for (int xb = 0; xb < w; xb++) {
if (bmap->bitAt(xb, yb)) {
// Not a hole.
newbmap->setBitAt(xb, yb);
continue; continue;
} }
gVec4 * pRow = m_normals + m_width * y;
const EState * pStateRow = m_states + m_width * y; int numFill = 0;
for(int nx=0;nx<5;nx++)
LocalPixels lp;
for (int ny = 0; ny < 5; ny++)
{ {
int x = (xb + nx - 2); int y = (yb + ny - 2);
if ( x < 0 || x >= m_width ) if ( y < 0 || y >= h )
{ {
lp.fill[ny][nx] = false; // out of range
for(int i = 0; i < 5; i++)
{
lp.fill[ny][i] = false;
}
continue;
} }
else if ( pStateRow[x] == eNull || pStateRow[x] == eEdge )
for (int nx = 0; nx < 5; nx++)
{ {
lp.fill[ny][nx] = false; int x = (xb + nx - 2);
if (x < 0 || x >= w)
{
lp.fill[ny][nx] = false;
}
else
{
int idx = img->index(x, y);
if (!bmap->bitAt(idx))
{
lp.fill[ny][nx] = false;
}
else
{
lp.fill[ny][nx] = true;
lp.data[ny][nx] = channel[idx];
numFill++;
}
}
} }
else }
// need at least 3 to do anything decent
if (numFill < 2)
continue;
nvDebugCheck(lp.fill[2][2] == false);
if (lp.doLocalPixelFill())
{
const int idx = img->index(xb, yb);
channel[idx] = lp.result / lp.weight;
if (c == firstChannel)
{ {
lp.fill[ny][nx] = true; //coverageChannel[idx] /= lp.weight; // @@ Not sure what this was for, coverageChannel[idx] is always zero.
lp.data[ny][nx] = pRow[x]; newbmap->setBitAt(xb, yb);
numFill++;
} }
} }
} }
// need at least 3 to do anything decent
if ( numFill < 2 )
continue;
ASSERT(lp.fill[2][2] == false);
if ( lp.DoLocalPixelFill() )
{
if ( lp.result.MutableVec3().NormalizeSafe() )
{
pRow[xb] = lp.result;
pRow[xb][3] /= lp.weight;
}
}
}
if ( ++tick == heightPerTick )
{
tick = 0;
gLog::Printf(".");
} }
} }
// now run back over and stamp anything that's not null as being ok // Update the bit mask.
swap(*newbmap, *bmap);
for(int y=0;y<m_height;y++)
{
const gVec4 * pRow = m_normals + m_width * y;
EState * pStateRow = m_states + m_width * y;
for(int x=0;x<m_width;x++)
{
if ( ( pStateRow[x] == eNull || pStateRow[x] == eEdge ) && ! IsNull(pRow[x]) )
{
pStateRow[x] = eSeamFixed;
}
}
}
} }
gLog::Printf("done\n");
} }
#endif // 0

View File

@ -84,12 +84,12 @@ namespace nv
}; };
NVIMAGE_API void fillVoronoi(FloatImage * img, const BitMap & bmap); NVIMAGE_API void fillVoronoi(FloatImage * img, const BitMap * bmap);
NVIMAGE_API void fillBlur(FloatImage * img, const BitMap & bmap); NVIMAGE_API void fillBlur(FloatImage * img, const BitMap * bmap);
NVIMAGE_API void fillPullPush(FloatImage * img, const BitMap & bmap); NVIMAGE_API void fillPullPush(FloatImage * img, const BitMap * bmap);
NVIMAGE_API void fillExtrapolateOnce(FloatImage * img, BitMap * bmap); NVIMAGE_API void fillExtrapolate(int passCount, FloatImage * img, BitMap * bmap);
NVIMAGE_API void fillExtrapolateNTimes(FloatImage * img, BitMap * bmap, int n); NVIMAGE_API void fillCubicExtrapolate(int passCount, FloatImage * img, BitMap * bmap, int coverageIndex = -1);
} // nv namespace } // nv namespace

View File

@ -1,133 +1,133 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- castanyo@yahoo.es
#include <nvcore/Debug.h> #include <nvcore/Debug.h>
#include <nvcore/Ptr.h> #include <nvcore/Ptr.h>
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
#include <nvimage/ImageIO.h> #include <nvimage/ImageIO.h>
using namespace nv; using namespace nv;
Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL) Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL)
{ {
} }
Image::~Image() Image::~Image()
{ {
free(); free();
} }
void Image::allocate(uint w, uint h) void Image::allocate(uint w, uint h)
{ {
m_width = w; m_width = w;
m_height = h; m_height = h;
m_data = (Color32 *)realloc(m_data, w * h * sizeof(Color32)); m_data = (Color32 *)realloc(m_data, w * h * sizeof(Color32));
} }
bool Image::load(const char * name) bool Image::load(const char * name)
{ {
free(); free();
AutoPtr<Image> img(ImageIO::load(name)); AutoPtr<Image> img(ImageIO::load(name));
if (img == NULL) { if (img == NULL) {
return false; return false;
} }
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_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)
{ {
free(); free();
m_data = (Color32 *)data; m_data = (Color32 *)data;
m_width = w; m_width = w;
m_height = h; m_height = h;
} }
void Image::unwrap() void Image::unwrap()
{ {
m_data = NULL; m_data = NULL;
m_width = 0; m_width = 0;
m_height = 0; m_height = 0;
} }
void Image::free() void Image::free()
{ {
::free(m_data); ::free(m_data);
m_data = NULL; m_data = NULL;
} }
uint Image::width() const uint Image::width() const
{ {
return m_width; return m_width;
} }
uint Image::height() const uint Image::height() const
{ {
return m_height; return m_height;
} }
const Color32 * Image::scanline(uint h) const const Color32 * Image::scanline(uint h) const
{ {
nvDebugCheck(h < m_height); nvDebugCheck(h < m_height);
return m_data + h * m_width; return m_data + h * m_width;
} }
Color32 * Image::scanline(uint h) Color32 * Image::scanline(uint h)
{ {
nvDebugCheck(h < m_height); nvDebugCheck(h < m_height);
return m_data + h * m_width; return m_data + h * m_width;
} }
const Color32 * Image::pixels() const const Color32 * Image::pixels() const
{ {
return m_data; return m_data;
} }
Color32 * Image::pixels() Color32 * Image::pixels()
{ {
return m_data; return m_data;
} }
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);
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);
return m_data[idx]; return m_data[idx];
} }
Image::Format Image::format() const Image::Format Image::format() const
{ {
return m_format; return m_format;
} }
void Image::setFormat(Image::Format f) void Image::setFormat(Image::Format f)
{ {
m_format = f; m_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;
for (uint i = 0; i < size; ++i) for (uint i = 0; i < size; ++i)
{ {
m_data[i] = c; m_data[i] = c;
} }
} }

View File

@ -4,6 +4,8 @@
#include <nvcore/Containers.h> #include <nvcore/Containers.h>
#include <nvcore/StrLib.h> #include <nvcore/StrLib.h>
#include <nvcore/StdStream.h> #include <nvcore/StdStream.h>
#include <nvcore/Tokenizer.h>
#include <nvcore/TextWriter.h>
#include <nvmath/Color.h> #include <nvmath/Color.h>
@ -29,11 +31,13 @@ extern "C" {
# include <tiffio.h> # include <tiffio.h>
#endif #endif
#if defined(HAVE_EXR) #if defined(HAVE_OPENEXR)
# include <ImfRgbaFile.h> # include <ImfIO.h>
# include <ImfInputFile.h> // ??? # include <ImathBox.h>
# include <ImfChannelList.h>
# include <ImfInputFile.h>
# include <ImfOutputFile.h>
# include <ImfArray.h> # include <ImfArray.h>
using namespace Imf;
#endif #endif
using namespace nv; using namespace nv;
@ -55,23 +59,28 @@ namespace {
} // namespace } // namespace
Image * nv::ImageIO::load(const char * name) Image * nv::ImageIO::load(const char * fileName)
{ {
StdInputStream stream(name); nvDebugCheck(fileName != NULL);
StdInputStream stream(fileName);
if (stream.isError()) { if (stream.isError()) {
return false; return NULL;
} }
return load(name, stream); return ImageIO::load(fileName, stream);
} }
Image * nv::ImageIO::load(const char * name, Stream & s) Image * nv::ImageIO::load(const char * fileName, Stream & s)
{ {
const char * extension = Path::extension(name); nvDebugCheck(fileName != NULL);
nvDebugCheck(s.isLoading());
const char * extension = Path::extension(fileName);
if (strCaseCmp(extension, ".tga") == 0) { if (strCaseCmp(extension, ".tga") == 0) {
return loadTGA(s); return ImageIO::loadTGA(s);
} }
#if defined(HAVE_JPEG) #if defined(HAVE_JPEG)
if (strCaseCmp(extension, ".jpg") == 0 || strCaseCmp(extension, ".jpeg") == 0) { if (strCaseCmp(extension, ".jpg") == 0 || strCaseCmp(extension, ".jpeg") == 0) {
@ -90,36 +99,113 @@ Image * nv::ImageIO::load(const char * name, Stream & s)
return NULL; return NULL;
} }
NVIMAGE_API FloatImage * nv::ImageIO::loadFloat(const char * name) bool nv::ImageIO::save(const char * fileName, Stream & s, Image * img)
{ {
StdInputStream stream(name); nvDebugCheck(fileName != NULL);
nvDebugCheck(s.isSaving());
nvDebugCheck(img != NULL);
const char * extension = Path::extension(fileName);
if (strCaseCmp(extension, ".tga") == 0) {
return ImageIO::saveTGA(s, img);
}
return false;
}
bool nv::ImageIO::save(const char * fileName, Image * img)
{
nvDebugCheck(fileName != NULL);
nvDebugCheck(img != NULL);
StdOutputStream stream(fileName);
if (stream.isError())
{
return false;
}
return ImageIO::save(fileName, stream, img);
}
FloatImage * nv::ImageIO::loadFloat(const char * fileName)
{
nvDebugCheck(fileName != NULL);
StdInputStream stream(fileName);
if (stream.isError()) { if (stream.isError()) {
return false; return false;
} }
return loadFloat(name, stream); return loadFloat(fileName, stream);
} }
NVIMAGE_API FloatImage * nv::ImageIO::loadFloat(const char * name, Stream & s) FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s)
{ {
const char * extension = Path::extension(name); nvDebugCheck(fileName != NULL);
const char * extension = Path::extension(fileName);
#if defined(HAVE_TIFF) #if defined(HAVE_TIFF)
if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) { if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) {
return loadFloatTIFF(name, s); return loadFloatTIFF(fileName, s);
} }
#endif #endif
#if defined(HAVE_EXR) #if defined(HAVE_OPENEXR)
if (strCaseCmp(extension, ".exr") == 0) { if (strCaseCmp(extension, ".exr") == 0) {
return loadFloatEXR(name, s); return loadFloatEXR(fileName, s);
} }
#endif #endif
if (strCaseCmp(extension, ".pfm") == 0) {
return loadFloatPFM(fileName, s);
}
return NULL; return NULL;
} }
bool nv::ImageIO::saveFloat(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components)
{
const char * extension = Path::extension(fileName);
#if defined(HAVE_OPENEXR)
if (strCaseCmp(extension, ".exr") == 0)
{
return ImageIO::saveFloatEXR(fileName, fimage, base_component, num_components);
}
#endif
#if defined(HAVE_TIFF)
if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0)
{
return ImageIO::saveFloatTIFF(fileName, fimage, base_component, num_components);
}
#endif
if (strCaseCmp(extension, ".pfm") == 0)
{
// return ImageIO::saveFloatPFM(fileName, fimage, base_component, num_components);
}
if (num_components == 3 || num_components == 4)
{
AutoPtr<Image> image(fimage->createImage(base_component, num_components));
nvCheck(image != NULL);
if (num_components == 4)
{
image->setFormat(Image::Format_ARGB);
}
return ImageIO::save(fileName, image.ptr());
}
return false;
}
/// Load TGA image. /// Load TGA image.
Image * nv::ImageIO::loadTGA(Stream & s) Image * nv::ImageIO::loadTGA(Stream & s)
{ {
@ -912,7 +998,7 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage
{ {
nvCheck(fileName != NULL); nvCheck(fileName != NULL);
nvCheck(fimage != NULL); nvCheck(fimage != NULL);
nvCheck(fimage->componentNum() <= base_component + num_components); nvCheck(base_component + num_components <= fimage->componentNum());
const int iW = fimage->width(); const int iW = fimage->width();
const int iH = fimage->height(); const int iH = fimage->height();
@ -936,7 +1022,12 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage
uint32 rowsperstrip = TIFFDefaultStripSize(image, (uint32)-1); uint32 rowsperstrip = TIFFDefaultStripSize(image, (uint32)-1);
TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
if (num_components == 3)
{
// Set this so that it can be visualized with pfstools.
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
}
TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
@ -963,14 +1054,14 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, const FloatImage * fimage
#endif #endif
#if defined(HAVE_EXR) #if defined(HAVE_OPENEXR)
namespace namespace
{ {
class ExrStream : public Imf::IStream class ExrStream : public Imf::IStream
{ {
public: public:
ExrStream(Stream & s) : m_stream(s) ExrStream(const char * name, Stream & s) : Imf::IStream(name), m_stream(s)
{ {
nvDebugCheck(s.isLoading()); nvDebugCheck(s.isLoading());
} }
@ -987,12 +1078,12 @@ namespace
return m_stream.isAtEnd(); return m_stream.isAtEnd();
} }
virtual Int64 tellg() virtual Imf::Int64 tellg()
{ {
return m_stream.tell(); return m_stream.tell();
} }
virtual void seekg(Int64 pos) virtual void seekg(Imf::Int64 pos)
{ {
m_stream.seek(pos); m_stream.seek(pos);
} }
@ -1010,12 +1101,13 @@ namespace
FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s) FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s)
{ {
nvCheck(s.isLoading());
nvCheck(!s.isError()); nvCheck(!s.isError());
ExrStream stream(s); ExrStream stream(fileName, s);
RgbaInputFile inputFile(stream); Imf::InputFile inputFile(stream);
Box2i box = inputFile.dataWindow(); Imath::Box2i box = inputFile.header().dataWindow();
int width = box.max.x - box.min.y + 1; int width = box.max.x - box.min.y + 1;
int height = box.max.x - box.min.y + 1; int height = box.max.x - box.min.y + 1;
@ -1024,7 +1116,7 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s)
// Count channels. // Count channels.
uint channelCount= 0; uint channelCount= 0;
for (ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it) for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it)
{ {
channelCount++; channelCount++;
} }
@ -1034,11 +1126,11 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s)
fimage->allocate(channelCount, width, height); fimage->allocate(channelCount, width, height);
// Describe image's layout with a framebuffer. // Describe image's layout with a framebuffer.
FrameBuffer frameBuffer; Imf::FrameBuffer frameBuffer;
uint i = 0; uint i = 0;
for (ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it, ++i) for (Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it, ++i)
{ {
frameBuffer.insert(it.name(), Slice(FLOAT, fimage->channel(i), sizeof(float), sizeof(float) * width)); frameBuffer.insert(it.name(), Imf::Slice(Imf::FLOAT, (char *)fimage->channel(i), sizeof(float), sizeof(float) * width));
} }
// Read it. // Read it.
@ -1048,22 +1140,11 @@ FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName, Stream & s)
return fimage.release(); return fimage.release();
} }
FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName)
{
StdInputStream stream(fileName);
if (stream.isError()) {
return false;
}
return loadFloatExr(fileName, stream);
}
bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components) bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components)
{ {
nvCheck(fileName != NULL); nvCheck(fileName != NULL);
nvCheck(fimage != NULL); nvCheck(fimage != NULL);
nvCheck(fimage->componentNum() <= base_component + num_components); nvCheck(base_component + num_components <= fimage->componentNum());
nvCheck(num_components > 0 && num_components <= 4); nvCheck(num_components > 0 && num_components <= 4);
const int w = fimage->width(); const int w = fimage->width();
@ -1071,29 +1152,146 @@ bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage,
const char * channelNames[] = {"R", "G", "B", "A"}; const char * channelNames[] = {"R", "G", "B", "A"};
Header header (width, height); Imf::Header header (w, h);
for (uint c = 0; c < num_components; c++) for (uint c = 0; c < num_components; c++)
{ {
header.channels().insert(channelNames[c], Channel(FLOAT)); header.channels().insert(channelNames[c], Imf::Channel(Imf::FLOAT));
} }
OutputFile file(fileName, header); Imf::OutputFile file(fileName, header);
FrameBuffer frameBuffer; Imf::FrameBuffer frameBuffer;
for (uint c = 0; c < num_components; c++) for (uint c = 0; c < num_components; c++)
{ {
const char * channel = (char *) fimage->channel(base_component + c); char * channel = (char *) fimage->channel(base_component + c);
frameBuffer.insert(channelNames[c], Slice(FLOAT, channel, sizeof(float), sizeof(float) * w)); frameBuffer.insert(channelNames[c], Imf::Slice(Imf::FLOAT, channel, sizeof(float), sizeof(float) * w));
} }
file.setFrameBuffer(frameBuffer); file.setFrameBuffer(frameBuffer);
file.writePixels(height); file.writePixels(h);
return false; return true;
} }
#endif // defined(HAVE_EXR) #endif // defined(HAVE_OPENEXR)
FloatImage * nv::ImageIO::loadFloatPFM(const char * fileName, Stream & s)
{
nvCheck(s.isLoading());
nvCheck(!s.isError());
Tokenizer parser(&s);
parser.nextToken();
bool grayscale;
if (parser.token() == "PF")
{
grayscale = false;
}
else if (parser.token() == "Pf")
{
grayscale = true;
}
else
{
// Invalid file.
return NULL;
}
parser.nextLine();
int width = parser.token().toInt(); parser.nextToken();
int height = parser.token().toInt();
parser.nextLine();
float scaleFactor = parser.token().toFloat();
if (scaleFactor >= 0)
{
s.setByteOrder(Stream::BigEndian);
}
else
{
s.setByteOrder(Stream::LittleEndian);
}
scaleFactor = fabsf(scaleFactor);
// Allocate image.
AutoPtr<FloatImage> fimage(new FloatImage());
if (grayscale)
{
fimage->allocate(1, width, height);
float * channel = fimage->channel(0);
for (int i = 0; i < width * height; i++)
{
s << channel[i];
}
}
else
{
fimage->allocate(3, width, height);
float * rchannel = fimage->channel(0);
float * gchannel = fimage->channel(1);
float * bchannel = fimage->channel(2);
for (int i = 0; i < width * height; i++)
{
s << rchannel[i] << gchannel[i] << bchannel[i];
}
}
return fimage.release();
}
bool nv::ImageIO::saveFloatPFM(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components)
{
nvCheck(fileName != NULL);
nvCheck(fimage != NULL);
nvCheck(fimage->componentNum() <= base_component + num_components);
nvCheck(num_components == 1 || num_components == 3);
StdOutputStream stream(fileName);
TextWriter writer(&stream);
if (num_components == 1) writer.write("Pf\n");
else /*if (num_components == 3)*/ writer.write("PF\n");
int w = fimage->width();
int h = fimage->height();
writer.write("%d %d\n", w, h);
writer.write("%f\n", -1.0f); // little endian with 1.0 scale.
if (num_components == 1)
{
float * channel = const_cast<float *>(fimage->channel(0));
for (int i = 0; i < w * h; i++)
{
stream << channel[i];
}
}
else
{
float * rchannel = const_cast<float *>(fimage->channel(0));
float * gchannel = const_cast<float *>(fimage->channel(1));
float * bchannel = const_cast<float *>(fimage->channel(2));
for (int i = 0; i < w * h; i++)
{
stream << rchannel[i] << gchannel[i] << bchannel[i];
}
}
return true;
}
#if 0 #if 0

View File

@ -15,9 +15,14 @@ namespace nv
{ {
NVIMAGE_API Image * load(const char * fileName); NVIMAGE_API Image * load(const char * fileName);
NVIMAGE_API Image * load(const char * fileName, Stream & s); NVIMAGE_API Image * load(const char * fileName, Stream & s);
NVIMAGE_API FloatImage * loadFloat(const char * fileName); NVIMAGE_API FloatImage * loadFloat(const char * fileName);
NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s); NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s);
NVIMAGE_API bool save(const char * fileName, Stream & s, Image * img);
NVIMAGE_API bool save(const char * fileName, Image * img);
NVIMAGE_API bool saveFloat(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components);
NVIMAGE_API Image * loadTGA(Stream & s); NVIMAGE_API Image * loadTGA(Stream & s);
NVIMAGE_API bool saveTGA(Stream & s, const Image * img); NVIMAGE_API bool saveTGA(Stream & s, const Image * img);
@ -37,12 +42,15 @@ namespace nv
NVIMAGE_API bool saveFloatTIFF(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); NVIMAGE_API bool saveFloatTIFF(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components);
#endif #endif
#if defined(HAVE_EXR) #if defined(HAVE_OPENEXR)
NVIMAGE_API FloatImage * loadFloatEXR(const char * fileName, Stream & s); NVIMAGE_API FloatImage * loadFloatEXR(const char * fileName, Stream & s);
NVIMAGE_API bool saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components); NVIMAGE_API bool saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components);
#endif #endif
NVIMAGE_API FloatImage * loadFloatPFM(const char * fileName, Stream & s);
NVIMAGE_API bool saveFloatPFM(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components);
} // ImageIO namespace } // ImageIO namespace
} // nv namespace } // nv namespace

View File

@ -1,140 +1,140 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <nvcore/Ptr.h> #include <nvcore/Ptr.h>
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include <nvimage/NormalMap.h> #include <nvimage/NormalMap.h>
#include <nvimage/Filter.h> #include <nvimage/Filter.h>
#include <nvimage/FloatImage.h> #include <nvimage/FloatImage.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
using namespace nv; 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)
{ {
nvCheck(kdu != NULL); nvCheck(kdu != NULL);
nvCheck(kdv != NULL); nvCheck(kdv != NULL);
nvCheck(img != NULL); nvCheck(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->applyKernel(kdu, x, y, 3, wm);
const float dv = fimage->applyKernel(kdv, x, y, 3, wm); const float dv = fimage->applyKernel(kdv, x, y, 3, wm);
Vector3 n = normalize(Vector3(du, dv, heightScale)); Vector3 n = normalize(Vector3(du, dv, heightScale));
fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0); fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0);
fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1); fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1);
fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2); fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2);
} }
} }
return fimage.release(); return fimage.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*/)
{ {
nvCheck(img != NULL); nvCheck(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)
{ {
nvCheck(img != NULL); nvCheck(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);
} }
/// Normalize the given image in place. /// Normalize the given image in place.
void nv::normalizeNormalMap(FloatImage * img) void nv::normalizeNormalMap(FloatImage * img)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
img->expandNormals(0); img->expandNormals(0);
img->normalize(0); img->normalize(0);
img->packNormals(0); img->packNormals(0);
} }

View File

@ -1,55 +1,55 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_IMAGE_NORMALMAP_H #ifndef NV_IMAGE_NORMALMAP_H
#define NV_IMAGE_NORMALMAP_H #define NV_IMAGE_NORMALMAP_H
#include <nvmath/Vector.h> #include <nvmath/Vector.h>
#include <nvimage/nvimage.h> #include <nvimage/nvimage.h>
#include <nvimage/FloatImage.h> #include <nvimage/FloatImage.h>
namespace nv namespace nv
{ {
class Image; class Image;
enum NormalMapFilter enum NormalMapFilter
{ {
NormalMapFilter_Sobel3x3, // fine detail NormalMapFilter_Sobel3x3, // fine detail
NormalMapFilter_Sobel5x5, // medium detail NormalMapFilter_Sobel5x5, // medium detail
NormalMapFilter_Sobel7x7, // large detail NormalMapFilter_Sobel7x7, // large detail
NormalMapFilter_Sobel9x9, // very large NormalMapFilter_Sobel9x9, // very large
}; };
FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter = NormalMapFilter_Sobel3x3); FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter = NormalMapFilter_Sobel3x3);
FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights); FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights);
void normalizeNormalMap(FloatImage * img); void normalizeNormalMap(FloatImage * img);
// @@ Add generation of DU/DV maps. // @@ Add generation of DU/DV maps.
} // nv namespace } // nv namespace
#endif // NV_IMAGE_NORMALMAP_H #endif // NV_IMAGE_NORMALMAP_H