Add support for FreeImage in nvimage.
Add support for floating point input images in nvtt.
This commit is contained in:
parent
47bdab8e27
commit
c01566cd2f
@ -11,6 +11,7 @@
|
||||
#cmakedefine HAVE_JPEG
|
||||
#cmakedefine HAVE_TIFF
|
||||
#cmakedefine HAVE_OPENEXR
|
||||
#cmakedefine HAVE_FREEIMAGE
|
||||
|
||||
#cmakedefine HAVE_MAYA
|
||||
|
||||
|
@ -51,6 +51,11 @@ IF(OPENEXR_FOUND)
|
||||
INCLUDE_DIRECTORIES(${OPENEXR_INCLUDE_PATHS})
|
||||
ENDIF(OPENEXR_FOUND)
|
||||
|
||||
IF(FREEIMAGE_FOUND)
|
||||
SET(LIBS ${LIBS} ${FREEIMAGE_LIBRARIES})
|
||||
INCLUDE_DIRECTORIES(${FREEIMAGE_INCLUDE_PATHS})
|
||||
ENDIF(FREEIMAGE_FOUND)
|
||||
|
||||
# targets
|
||||
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 <nvimage/Image.h>
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
#include "ColorSpace.h"
|
||||
|
||||
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
|
||||
#define NV_IMAGE_COLORSPACE_H
|
||||
|
@ -40,6 +40,10 @@ extern "C" {
|
||||
# include <ImfArray.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_FREEIMAGE)
|
||||
# include <FreeImage.h>
|
||||
#endif
|
||||
|
||||
using namespace nv;
|
||||
|
||||
namespace {
|
||||
@ -58,6 +62,9 @@ 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)
|
||||
{
|
||||
@ -78,10 +85,16 @@ Image * nv::ImageIO::load(const char * fileName, Stream & s)
|
||||
nvDebugCheck(s.isLoading());
|
||||
|
||||
const char * extension = Path::extension(fileName);
|
||||
|
||||
|
||||
if (strCaseCmp(extension, ".tga") == 0) {
|
||||
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 (strCaseCmp(extension, ".jpg") == 0 || strCaseCmp(extension, ".jpeg") == 0) {
|
||||
return loadJPG(s);
|
||||
@ -92,10 +105,13 @@ Image * nv::ImageIO::load(const char * fileName, Stream & s)
|
||||
return loadPNG(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strCaseCmp(extension, ".psd") == 0) {
|
||||
return loadPSD(s);
|
||||
}
|
||||
|
||||
// @@ use image plugins?
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -157,6 +173,12 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s)
|
||||
return loadFloatEXR(fileName, s);
|
||||
}
|
||||
#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
|
||||
if (strCaseCmp(extension, ".pfm") == 0) {
|
||||
@ -600,6 +622,206 @@ Image * nv::ImageIO::loadPSD(Stream & s)
|
||||
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)
|
||||
|
||||
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);
|
||||
memcpy(image->pixels(), data, width * height * 4);
|
||||
m.images[idx].data = image;
|
||||
m.images[idx].uint8data = image;
|
||||
}
|
||||
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
|
||||
{
|
||||
@ -467,7 +467,7 @@ const Image * InputOptions::Private::image(uint idx) const
|
||||
return image.uint8data.ptr();
|
||||
}
|
||||
|
||||
const FloatImage * InputOptions::Private::image(uint idx) const
|
||||
const FloatImage * InputOptions::Private::floatImage(uint idx) const
|
||||
{
|
||||
nvDebugCheck(idx < faceCount * mipmapCount);
|
||||
|
||||
|
@ -104,6 +104,8 @@ namespace nvtt
|
||||
{
|
||||
InputImage() {}
|
||||
|
||||
bool hasValidData() const { return uint8data != NULL || floatdata != NULL; }
|
||||
|
||||
int mipLevel;
|
||||
int face;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user