merge internal branch:
- some support for floating point images. - Charles Bloom extrapolation filter. - misc fixes.
This commit is contained in:
parent
2e41727f81
commit
4373aa758b
File diff suppressed because it is too large
Load Diff
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user