Add support for FreeImage in nvimage.
Add support for floating point input images in nvtt.
This commit is contained in:
@ -11,6 +11,7 @@
|
|||||||
#cmakedefine HAVE_JPEG
|
#cmakedefine HAVE_JPEG
|
||||||
#cmakedefine HAVE_TIFF
|
#cmakedefine HAVE_TIFF
|
||||||
#cmakedefine HAVE_OPENEXR
|
#cmakedefine HAVE_OPENEXR
|
||||||
|
#cmakedefine HAVE_FREEIMAGE
|
||||||
|
|
||||||
#cmakedefine HAVE_MAYA
|
#cmakedefine HAVE_MAYA
|
||||||
|
|
||||||
|
@ -51,6 +51,11 @@ IF(OPENEXR_FOUND)
|
|||||||
INCLUDE_DIRECTORIES(${OPENEXR_INCLUDE_PATHS})
|
INCLUDE_DIRECTORIES(${OPENEXR_INCLUDE_PATHS})
|
||||||
ENDIF(OPENEXR_FOUND)
|
ENDIF(OPENEXR_FOUND)
|
||||||
|
|
||||||
|
IF(FREEIMAGE_FOUND)
|
||||||
|
SET(LIBS ${LIBS} ${FREEIMAGE_LIBRARIES})
|
||||||
|
INCLUDE_DIRECTORIES(${FREEIMAGE_INCLUDE_PATHS})
|
||||||
|
ENDIF(FREEIMAGE_FOUND)
|
||||||
|
|
||||||
# targets
|
# targets
|
||||||
ADD_DEFINITIONS(-DNVIMAGE_EXPORTS)
|
ADD_DEFINITIONS(-DNVIMAGE_EXPORTS)
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
#include "ColorSpace.h"
|
// This code is in the public domain -- jim@tilander.org
|
||||||
|
|
||||||
|
#include <nvcore/nvcore.h>
|
||||||
|
|
||||||
#include <nvmath/Color.h>
|
#include <nvmath/Color.h>
|
||||||
#include <nvimage/Image.h>
|
#include <nvimage/Image.h>
|
||||||
#include <nvcore/nvcore.h>
|
|
||||||
|
#include "ColorSpace.h"
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
@ -63,4 +67,4 @@ namespace nv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// This code is in the public domain -- jim@tilander.org
|
||||||
|
|
||||||
#ifndef NV_IMAGE_COLORSPACE_H
|
#ifndef NV_IMAGE_COLORSPACE_H
|
||||||
#define NV_IMAGE_COLORSPACE_H
|
#define NV_IMAGE_COLORSPACE_H
|
||||||
|
@ -40,6 +40,10 @@ extern "C" {
|
|||||||
# include <ImfArray.h>
|
# include <ImfArray.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_FREEIMAGE)
|
||||||
|
# include <FreeImage.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace nv;
|
using namespace nv;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -58,6 +62,9 @@ namespace {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
static Image * loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s);
|
||||||
|
static FloatImage * loadFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s);
|
||||||
|
|
||||||
|
|
||||||
Image * nv::ImageIO::load(const char * fileName)
|
Image * nv::ImageIO::load(const char * fileName)
|
||||||
{
|
{
|
||||||
@ -78,10 +85,16 @@ Image * nv::ImageIO::load(const char * fileName, Stream & s)
|
|||||||
nvDebugCheck(s.isLoading());
|
nvDebugCheck(s.isLoading());
|
||||||
|
|
||||||
const char * extension = Path::extension(fileName);
|
const char * extension = Path::extension(fileName);
|
||||||
|
|
||||||
if (strCaseCmp(extension, ".tga") == 0) {
|
if (strCaseCmp(extension, ".tga") == 0) {
|
||||||
return ImageIO::loadTGA(s);
|
return ImageIO::loadTGA(s);
|
||||||
}
|
}
|
||||||
|
#if defined(HAVE_FREEIMAGE)
|
||||||
|
FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName);
|
||||||
|
if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) {
|
||||||
|
return loadFreeImage(fif, s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#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) {
|
||||||
return loadJPG(s);
|
return loadJPG(s);
|
||||||
@ -92,10 +105,13 @@ Image * nv::ImageIO::load(const char * fileName, Stream & s)
|
|||||||
return loadPNG(s);
|
return loadPNG(s);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (strCaseCmp(extension, ".psd") == 0) {
|
if (strCaseCmp(extension, ".psd") == 0) {
|
||||||
return loadPSD(s);
|
return loadPSD(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @@ use image plugins?
|
// @@ use image plugins?
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +173,12 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s)
|
|||||||
return loadFloatEXR(fileName, s);
|
return loadFloatEXR(fileName, s);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_FREEIMAGE)
|
||||||
|
FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName);
|
||||||
|
if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) {
|
||||||
|
return loadFloatFreeImage(fif, s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* // @@ Disable temporarily
|
/* // @@ Disable temporarily
|
||||||
if (strCaseCmp(extension, ".pfm") == 0) {
|
if (strCaseCmp(extension, ".pfm") == 0) {
|
||||||
@ -600,6 +622,206 @@ Image * nv::ImageIO::loadPSD(Stream & s)
|
|||||||
return img.release();
|
return img.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(HAVE_FREEIMAGE)
|
||||||
|
|
||||||
|
unsigned ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle)
|
||||||
|
{
|
||||||
|
Stream * s = (Stream *) handle;
|
||||||
|
s->serialize(buffer, size * count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SeekProc(fi_handle handle, long offset, int origin)
|
||||||
|
{
|
||||||
|
Stream * s = (Stream *) handle;
|
||||||
|
|
||||||
|
switch(origin) {
|
||||||
|
case SEEK_SET :
|
||||||
|
s->seek(offset);
|
||||||
|
break;
|
||||||
|
case SEEK_CUR :
|
||||||
|
s->seek(s->tell() + offset);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long TellProc(fi_handle handle)
|
||||||
|
{
|
||||||
|
Stream * s = (Stream *) handle;
|
||||||
|
return s->tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image * loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s)
|
||||||
|
{
|
||||||
|
nvCheck(!s.isError());
|
||||||
|
|
||||||
|
FreeImageIO io;
|
||||||
|
io.read_proc = ReadProc;
|
||||||
|
io.write_proc = NULL;
|
||||||
|
io.seek_proc = SeekProc;
|
||||||
|
io.tell_proc = TellProc;
|
||||||
|
|
||||||
|
FIBITMAP * bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)&s, 0);
|
||||||
|
|
||||||
|
if (bitmap == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int w = FreeImage_GetWidth(bitmap);
|
||||||
|
const int h = FreeImage_GetHeight(bitmap);
|
||||||
|
|
||||||
|
if (FreeImage_GetImageType(bitmap) == FIT_BITMAP)
|
||||||
|
{
|
||||||
|
if (FreeImage_GetBPP(bitmap) != 32)
|
||||||
|
{
|
||||||
|
FIBITMAP * tmp = FreeImage_ConvertTo32Bits(bitmap);
|
||||||
|
FreeImage_Unload(bitmap);
|
||||||
|
bitmap = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// @@ Use tone mapping?
|
||||||
|
FIBITMAP * tmp = FreeImage_ConvertToType(bitmap, FIT_BITMAP, true);
|
||||||
|
FreeImage_Unload(bitmap);
|
||||||
|
bitmap = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image * image = new Image();
|
||||||
|
image->allocate(w, h);
|
||||||
|
|
||||||
|
// Copy the image over to our internal format, FreeImage has the scanlines bottom to top though.
|
||||||
|
for (int y=0; y < h; y++)
|
||||||
|
{
|
||||||
|
const void * src = FreeImage_GetScanLine(bitmap, h - y - 1);
|
||||||
|
void * dst = image->scanline(y);
|
||||||
|
|
||||||
|
memcpy(dst, src, 4 * w);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeImage_Unload(bitmap);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatImage * loadFloatFreeImage(FREE_IMAGE_FORMAT fif, Stream & s)
|
||||||
|
{
|
||||||
|
nvCheck(!s.isError());
|
||||||
|
|
||||||
|
FreeImageIO io;
|
||||||
|
io.read_proc = ReadProc;
|
||||||
|
io.write_proc = NULL;
|
||||||
|
io.seek_proc = SeekProc;
|
||||||
|
io.tell_proc = TellProc;
|
||||||
|
|
||||||
|
FIBITMAP * bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)&s, 0);
|
||||||
|
|
||||||
|
if (bitmap == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int w = FreeImage_GetWidth(bitmap);
|
||||||
|
const int h = FreeImage_GetHeight(bitmap);
|
||||||
|
|
||||||
|
FREE_IMAGE_TYPE fit = FreeImage_GetImageType(bitmap);
|
||||||
|
|
||||||
|
FloatImage * floatImage = new FloatImage();
|
||||||
|
|
||||||
|
switch (fit)
|
||||||
|
{
|
||||||
|
case FIT_FLOAT:
|
||||||
|
floatImage->allocate(1, w, h);
|
||||||
|
|
||||||
|
for (int y=0; y < h; y++)
|
||||||
|
{
|
||||||
|
const float * src = (const float *)FreeImage_GetScanLine(bitmap, h - y - 1 );
|
||||||
|
float * dst = floatImage->scanline(y, 0);
|
||||||
|
|
||||||
|
for (int x=0; x < w; x++)
|
||||||
|
{
|
||||||
|
dst[x] = src[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIT_COMPLEX:
|
||||||
|
floatImage->allocate(2, w, h);
|
||||||
|
|
||||||
|
for (int y=0; y < h; y++)
|
||||||
|
{
|
||||||
|
const FICOMPLEX * src = (const FICOMPLEX *)FreeImage_GetScanLine(bitmap, h - y - 1 );
|
||||||
|
|
||||||
|
float * dst_real = floatImage->scanline(y, 0);
|
||||||
|
float * dst_imag = floatImage->scanline(y, 1);
|
||||||
|
|
||||||
|
for (int x=0; x < w; x++)
|
||||||
|
{
|
||||||
|
dst_real[x] = src[x].r;
|
||||||
|
dst_imag[x] = src[x].i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIT_RGBF:
|
||||||
|
floatImage->allocate(3, w, h);
|
||||||
|
|
||||||
|
for (int y=0; y < h; y++)
|
||||||
|
{
|
||||||
|
const FIRGBF * src = (const FIRGBF *)FreeImage_GetScanLine(bitmap, h - y - 1 );
|
||||||
|
|
||||||
|
float * dst_red = floatImage->scanline(y, 0);
|
||||||
|
float * dst_green = floatImage->scanline(y, 1);
|
||||||
|
float * dst_blue = floatImage->scanline(y, 2);
|
||||||
|
|
||||||
|
for (int x=0; x < w; x++)
|
||||||
|
{
|
||||||
|
dst_red[x] = src[x].red;
|
||||||
|
dst_green[x] = src[x].green;
|
||||||
|
dst_blue[x] = src[x].blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIT_RGBAF:
|
||||||
|
floatImage->allocate(4, w, h);
|
||||||
|
|
||||||
|
for (int y=0; y < h; y++)
|
||||||
|
{
|
||||||
|
const FIRGBAF * src = (const FIRGBAF *)FreeImage_GetScanLine(bitmap, h - y - 1 );
|
||||||
|
|
||||||
|
float * dst_red = floatImage->scanline(y, 0);
|
||||||
|
float * dst_green = floatImage->scanline(y, 1);
|
||||||
|
float * dst_blue = floatImage->scanline(y, 2);
|
||||||
|
float * dst_alpha = floatImage->scanline(y, 3);
|
||||||
|
|
||||||
|
for (int x=0; x < w; x++)
|
||||||
|
{
|
||||||
|
dst_red[x] = src[x].red;
|
||||||
|
dst_green[x] = src[x].green;
|
||||||
|
dst_blue[x] = src[x].blue;
|
||||||
|
dst_alpha[x] = src[x].alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
delete floatImage;
|
||||||
|
floatImage = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeImage_Unload(bitmap);
|
||||||
|
|
||||||
|
return floatImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(HAVE_FREEIMAGE)
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_PNG)
|
#if defined(HAVE_PNG)
|
||||||
|
|
||||||
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||||
|
@ -211,7 +211,7 @@ bool InputOptions::setMipmapData(const void * data, int width, int height, int d
|
|||||||
{
|
{
|
||||||
image->allocate(width, height);
|
image->allocate(width, height);
|
||||||
memcpy(image->pixels(), data, width * height * 4);
|
memcpy(image->pixels(), data, width * height * 4);
|
||||||
m.images[idx].data = image;
|
m.images[idx].uint8data = image;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -234,7 +234,7 @@ bool InputOptions::setMipmapData(const void * data, int width, int height, int d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.images[idx].data = image;
|
m.images[idx].floatdata = image;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -467,7 +467,7 @@ const Image * InputOptions::Private::image(uint idx) const
|
|||||||
return image.uint8data.ptr();
|
return image.uint8data.ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
const FloatImage * InputOptions::Private::image(uint idx) const
|
const FloatImage * InputOptions::Private::floatImage(uint idx) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(idx < faceCount * mipmapCount);
|
nvDebugCheck(idx < faceCount * mipmapCount);
|
||||||
|
|
||||||
|
@ -104,6 +104,8 @@ namespace nvtt
|
|||||||
{
|
{
|
||||||
InputImage() {}
|
InputImage() {}
|
||||||
|
|
||||||
|
bool hasValidData() const { return uint8data != NULL || floatdata != NULL; }
|
||||||
|
|
||||||
int mipLevel;
|
int mipLevel;
|
||||||
int face;
|
int face;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user