mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 01:44:06 -04:00
add support for OpenEXR floating-point image files
This commit is contained in:
parent
063f9bbc4d
commit
403dd39934
@ -78,7 +78,7 @@ PkgListSet(["PYTHON", "DIRECT", # Python support
|
|||||||
"VORBIS", "FFMPEG", "SWSCALE", "SWRESAMPLE", # Audio decoding
|
"VORBIS", "FFMPEG", "SWSCALE", "SWRESAMPLE", # Audio decoding
|
||||||
"ODE", "PHYSX", "BULLET", "PANDAPHYSICS", # Physics
|
"ODE", "PHYSX", "BULLET", "PANDAPHYSICS", # Physics
|
||||||
"SPEEDTREE", # SpeedTree
|
"SPEEDTREE", # SpeedTree
|
||||||
"ZLIB", "PNG", "JPEG", "TIFF", "SQUISH", "FREETYPE", # 2D Formats support
|
"ZLIB", "PNG", "JPEG", "TIFF", "OPENEXR", "SQUISH", "FREETYPE", # 2D Formats support
|
||||||
] + MAYAVERSIONS + MAXVERSIONS + [ "FCOLLADA", "ASSIMP", # 3D Formats support
|
] + MAYAVERSIONS + MAXVERSIONS + [ "FCOLLADA", "ASSIMP", # 3D Formats support
|
||||||
"VRPN", "OPENSSL", # Transport
|
"VRPN", "OPENSSL", # Transport
|
||||||
"FFTW", # Algorithm helpers
|
"FFTW", # Algorithm helpers
|
||||||
@ -604,6 +604,11 @@ if (COMPILER == "MSVC"):
|
|||||||
LibName("TIFF", GetThirdpartyDir() + "tiff/lib/libtiff.lib")
|
LibName("TIFF", GetThirdpartyDir() + "tiff/lib/libtiff.lib")
|
||||||
else:
|
else:
|
||||||
LibName("TIFF", GetThirdpartyDir() + "tiff/lib/tiff.lib")
|
LibName("TIFF", GetThirdpartyDir() + "tiff/lib/tiff.lib")
|
||||||
|
if (PkgSkip("OPENEXR")==0):
|
||||||
|
LibName("OPENEXR", GetThirdpartyDir() + "openexr/lib/IlmImf-2_2.lib")
|
||||||
|
LibName("OPENEXR", GetThirdpartyDir() + "openexr/lib/IlmThread-2_2.lib")
|
||||||
|
LibName("OPENEXR", GetThirdpartyDir() + "openexr/lib/Iex-2_2.lib")
|
||||||
|
LibName("OPENEXR", GetThirdpartyDir() + "openexr/lib/Half.lib")
|
||||||
if (PkgSkip("JPEG")==0): LibName("JPEG", GetThirdpartyDir() + "jpeg/lib/jpeg-static.lib")
|
if (PkgSkip("JPEG")==0): LibName("JPEG", GetThirdpartyDir() + "jpeg/lib/jpeg-static.lib")
|
||||||
if (PkgSkip("ZLIB")==0): LibName("ZLIB", GetThirdpartyDir() + "zlib/lib/zlibstatic.lib")
|
if (PkgSkip("ZLIB")==0): LibName("ZLIB", GetThirdpartyDir() + "zlib/lib/zlibstatic.lib")
|
||||||
if (PkgSkip("VRPN")==0): LibName("VRPN", GetThirdpartyDir() + "vrpn/lib/vrpn.lib")
|
if (PkgSkip("VRPN")==0): LibName("VRPN", GetThirdpartyDir() + "vrpn/lib/vrpn.lib")
|
||||||
@ -778,6 +783,7 @@ if (COMPILER=="GCC"):
|
|||||||
SmartPkgEnable("OPENAL", "openal", ("openal"), "AL/al.h", framework = "OpenAL")
|
SmartPkgEnable("OPENAL", "openal", ("openal"), "AL/al.h", framework = "OpenAL")
|
||||||
SmartPkgEnable("SQUISH", "", ("squish"), "squish.h")
|
SmartPkgEnable("SQUISH", "", ("squish"), "squish.h")
|
||||||
SmartPkgEnable("TIFF", "libtiff-4", ("tiff"), "tiff.h")
|
SmartPkgEnable("TIFF", "libtiff-4", ("tiff"), "tiff.h")
|
||||||
|
SmartPkgEnable("OPENEXR", "", ("openexr"), "ImfOutputFile.h")
|
||||||
SmartPkgEnable("VRPN", "", ("vrpn", "quat"), ("vrpn", "quat.h", "vrpn/vrpn_Types.h"))
|
SmartPkgEnable("VRPN", "", ("vrpn", "quat"), ("vrpn", "quat.h", "vrpn/vrpn_Types.h"))
|
||||||
SmartPkgEnable("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h"))
|
SmartPkgEnable("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h"))
|
||||||
SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h"))
|
SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h"))
|
||||||
@ -2201,6 +2207,7 @@ DTOOL_CONFIG=[
|
|||||||
("PHAVE_JPEGINT_H", '1', '1'),
|
("PHAVE_JPEGINT_H", '1', '1'),
|
||||||
("HAVE_VIDEO4LINUX", 'UNDEF', '1'),
|
("HAVE_VIDEO4LINUX", 'UNDEF', '1'),
|
||||||
("HAVE_TIFF", 'UNDEF', 'UNDEF'),
|
("HAVE_TIFF", 'UNDEF', 'UNDEF'),
|
||||||
|
("HAVE_OPENEXR", 'UNDEF', 'UNDEF'),
|
||||||
("HAVE_SGI_RGB", '1', '1'),
|
("HAVE_SGI_RGB", '1', '1'),
|
||||||
("HAVE_TGA", '1', '1'),
|
("HAVE_TGA", '1', '1'),
|
||||||
("HAVE_IMG", '1', '1'),
|
("HAVE_IMG", '1', '1'),
|
||||||
@ -3824,7 +3831,7 @@ if (not RUNTIME):
|
|||||||
#
|
#
|
||||||
|
|
||||||
if (not RUNTIME):
|
if (not RUNTIME):
|
||||||
OPTS=['DIR:panda/src/pnmimagetypes', 'DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'PNG', 'ZLIB', 'JPEG', 'TIFF']
|
OPTS=['DIR:panda/src/pnmimagetypes', 'DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'PNG', 'ZLIB', 'JPEG', 'TIFF', 'OPENEXR']
|
||||||
TargetAdd('p3pnmimagetypes_composite1.obj', opts=OPTS, input='p3pnmimagetypes_composite1.cxx')
|
TargetAdd('p3pnmimagetypes_composite1.obj', opts=OPTS, input='p3pnmimagetypes_composite1.cxx')
|
||||||
TargetAdd('p3pnmimagetypes_composite2.obj', opts=OPTS, input='p3pnmimagetypes_composite2.cxx')
|
TargetAdd('p3pnmimagetypes_composite2.obj', opts=OPTS, input='p3pnmimagetypes_composite2.cxx')
|
||||||
|
|
||||||
@ -3869,7 +3876,7 @@ if (not RUNTIME):
|
|||||||
|
|
||||||
if (not RUNTIME):
|
if (not RUNTIME):
|
||||||
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG',
|
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG',
|
||||||
'TIFF', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
'TIFF', 'OPENEXR', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
||||||
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
||||||
|
|
||||||
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "pnmFileTypePNM.h"
|
#include "pnmFileTypePNM.h"
|
||||||
#include "pnmFileTypePfm.h"
|
#include "pnmFileTypePfm.h"
|
||||||
#include "pnmFileTypeTIFF.h"
|
#include "pnmFileTypeTIFF.h"
|
||||||
|
#include "pnmFileTypeEXR.h"
|
||||||
#include "pnmFileTypeStbImage.h"
|
#include "pnmFileTypeStbImage.h"
|
||||||
#include "sgi.h"
|
#include "sgi.h"
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ NotifyCategoryDefName(pnmimage_jpg, "jpg", pnmimage_cat);
|
|||||||
NotifyCategoryDefName(pnmimage_png, "png", pnmimage_cat);
|
NotifyCategoryDefName(pnmimage_png, "png", pnmimage_cat);
|
||||||
NotifyCategoryDefName(pnmimage_pnm, "pnm", pnmimage_cat);
|
NotifyCategoryDefName(pnmimage_pnm, "pnm", pnmimage_cat);
|
||||||
NotifyCategoryDefName(pnmimage_tiff, "tiff", pnmimage_cat);
|
NotifyCategoryDefName(pnmimage_tiff, "tiff", pnmimage_cat);
|
||||||
|
NotifyCategoryDefName(pnmimage_exr, "exr", pnmimage_cat);
|
||||||
|
|
||||||
ConfigVariableEnum<SGIStorageType> sgi_storage_type
|
ConfigVariableEnum<SGIStorageType> sgi_storage_type
|
||||||
("sgi-storage-type", SST_rle,
|
("sgi-storage-type", SST_rle,
|
||||||
@ -241,6 +243,12 @@ init_libpnmimagetypes() {
|
|||||||
tr->register_type(new PNMFileTypeTIFF);
|
tr->register_type(new PNMFileTypeTIFF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENEXR
|
||||||
|
PNMFileTypeEXR::init_type();
|
||||||
|
PNMFileTypeEXR::register_with_read_factory();
|
||||||
|
tr->register_type(new PNMFileTypeEXR);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STB_IMAGE
|
#ifdef HAVE_STB_IMAGE
|
||||||
PNMFileTypeStbImage::init_type();
|
PNMFileTypeStbImage::init_type();
|
||||||
PNMFileTypeStbImage::register_with_read_factory();
|
PNMFileTypeStbImage::register_with_read_factory();
|
||||||
@ -259,4 +267,7 @@ init_libpnmimagetypes() {
|
|||||||
#ifdef HAVE_TIFF
|
#ifdef HAVE_TIFF
|
||||||
ps->add_system("libtiff");
|
ps->add_system("libtiff");
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_OPENEXR
|
||||||
|
ps->add_system("openexr");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
NotifyCategoryDecl(pnmimage_sgi, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
NotifyCategoryDecl(pnmimage_sgi, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||||
NotifyCategoryDecl(pnmimage_tiff, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
NotifyCategoryDecl(pnmimage_tiff, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||||
|
NotifyCategoryDecl(pnmimage_exr, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||||
NotifyCategoryDecl(pnmimage_tga, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
NotifyCategoryDecl(pnmimage_tga, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||||
NotifyCategoryDecl(pnmimage_img, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
NotifyCategoryDecl(pnmimage_img, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||||
NotifyCategoryDecl(pnmimage_soft, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
NotifyCategoryDecl(pnmimage_soft, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "config_pnmimagetypes.cxx"
|
#include "config_pnmimagetypes.cxx"
|
||||||
#include "pnmFileTypeBMPReader.cxx"
|
#include "pnmFileTypeBMPReader.cxx"
|
||||||
#include "pnmFileTypeBMPWriter.cxx"
|
#include "pnmFileTypeBMPWriter.cxx"
|
||||||
#include "pnmFileTypeIMG.cxx"
|
|
||||||
#include "pnmFileTypeBMP.cxx"
|
#include "pnmFileTypeBMP.cxx"
|
||||||
|
#include "pnmFileTypeEXR.cxx"
|
||||||
|
#include "pnmFileTypeIMG.cxx"
|
||||||
#include "pnmFileTypeJPG.cxx"
|
#include "pnmFileTypeJPG.cxx"
|
||||||
#include "pnmFileTypeJPGReader.cxx"
|
#include "pnmFileTypeJPGReader.cxx"
|
||||||
#include "pnmFileTypeJPGWriter.cxx"
|
#include "pnmFileTypeJPGWriter.cxx"
|
||||||
|
470
panda/src/pnmimagetypes/pnmFileTypeEXR.cxx
Normal file
470
panda/src/pnmimagetypes/pnmFileTypeEXR.cxx
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file pnmFileTypeEXR.cxx
|
||||||
|
* @author drose
|
||||||
|
* @date 2000-06-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pnmFileTypeEXR.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENEXR
|
||||||
|
|
||||||
|
#include "config_pnmimagetypes.h"
|
||||||
|
|
||||||
|
#include "pnmFileTypeRegistry.h"
|
||||||
|
#include "bamReader.h"
|
||||||
|
#include "pfmFile.h"
|
||||||
|
|
||||||
|
#include <ImfOutputFile.h>
|
||||||
|
#include <ImfChannelList.h>
|
||||||
|
#include <ImfVersion.h>
|
||||||
|
|
||||||
|
TypeHandle PNMFileTypeEXR::_type_handle;
|
||||||
|
|
||||||
|
static const char * const extensions_exr[] = {
|
||||||
|
"exr"
|
||||||
|
};
|
||||||
|
static const int num_extensions_exr = sizeof(extensions_exr) / sizeof(const char *);
|
||||||
|
|
||||||
|
// A wrapper class to map OpenEXR's OStream class onto std::ostream.
|
||||||
|
class ImfStdOstream : public IMF::OStream {
|
||||||
|
public:
|
||||||
|
ImfStdOstream(std::ostream &strm) : IMF::OStream("ostream"), _strm(strm) {}
|
||||||
|
|
||||||
|
virtual void write(const char c[/*n*/], int n) {
|
||||||
|
_strm.write(c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual IMF::Int64 tellp() {
|
||||||
|
return _strm.tellp();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void seekp(IMF::Int64 pos) {
|
||||||
|
_strm.seekp(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ostream &_strm;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A wrapper class to map OpenEXR's IStream class onto std::istream.
|
||||||
|
class ImfStdIstream : public IMF::IStream {
|
||||||
|
public:
|
||||||
|
ImfStdIstream(std::istream &strm, const std::string &magic_number) : IMF::IStream("istream"), _strm(strm) {
|
||||||
|
// Start by putting back the magic number.
|
||||||
|
for (std::string::const_reverse_iterator mi = magic_number.rbegin();
|
||||||
|
mi != magic_number.rend();
|
||||||
|
mi++) {
|
||||||
|
_strm.putback(*mi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isMemoryMapped () const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool read (char c[/*n*/], int n) {
|
||||||
|
_strm.read(c, n);
|
||||||
|
if (_strm.gcount() != n) {
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool not_eof = !_strm.eof();
|
||||||
|
return not_eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual IMF::Int64 tellg() {
|
||||||
|
return _strm.tellg();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void seekg(IMF::Int64 pos) {
|
||||||
|
_strm.seekg(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void clear() {
|
||||||
|
_strm.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::istream &_strm;
|
||||||
|
};
|
||||||
|
|
||||||
|
PNMFileTypeEXR::
|
||||||
|
PNMFileTypeEXR() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a few words describing the file type.
|
||||||
|
*/
|
||||||
|
string PNMFileTypeEXR::
|
||||||
|
get_name() const {
|
||||||
|
return "OpenEXR";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of different possible filename extensions associated
|
||||||
|
* with this particular file type.
|
||||||
|
*/
|
||||||
|
int PNMFileTypeEXR::
|
||||||
|
get_num_extensions() const {
|
||||||
|
return num_extensions_exr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the nth possible filename extension associated with this particular
|
||||||
|
* file type, without a leading dot.
|
||||||
|
*/
|
||||||
|
string PNMFileTypeEXR::
|
||||||
|
get_extension(int n) const {
|
||||||
|
nassertr(n >= 0 && n < num_extensions_exr, string());
|
||||||
|
return extensions_exr[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a suitable filename extension (without a leading dot) to suggest
|
||||||
|
* for files of this type, or empty string if no suggestions are available.
|
||||||
|
*/
|
||||||
|
string PNMFileTypeEXR::
|
||||||
|
get_suggested_extension() const {
|
||||||
|
return "exr";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this particular file type uses a magic number to identify
|
||||||
|
* it, false otherwise.
|
||||||
|
*/
|
||||||
|
bool PNMFileTypeEXR::
|
||||||
|
has_magic_number() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the indicated "magic number" byte stream (the initial few
|
||||||
|
* bytes read from the file) matches this particular file type, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
bool PNMFileTypeEXR::
|
||||||
|
matches_magic_number(const string &magic_number) const {
|
||||||
|
nassertr(magic_number.size() >= 2, false);
|
||||||
|
|
||||||
|
if (magic_number.size() >= 4) {
|
||||||
|
// If we have already read all four bytes, use the built-in
|
||||||
|
// function to check them.
|
||||||
|
return IMF::isImfMagic(magic_number.data());
|
||||||
|
} else {
|
||||||
|
// Otherwise, check only the first two bytes and call it good enough.
|
||||||
|
return magic_number[0] == ((IMF::MAGIC >> 0) & 0x00ff) &&
|
||||||
|
magic_number[1] == ((IMF::MAGIC >> 8) & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates and returns a new PNMReader suitable for reading from this file
|
||||||
|
* type, if possible. If reading from this file type is not supported,
|
||||||
|
* returns NULL.
|
||||||
|
*/
|
||||||
|
PNMReader *PNMFileTypeEXR::
|
||||||
|
make_reader(istream *file, bool owns_file, const string &magic_number) {
|
||||||
|
init_pnm();
|
||||||
|
return new Reader(this, file, owns_file, magic_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates and returns a new PNMWriter suitable for reading from this file
|
||||||
|
* type, if possible. If writing files of this type is not supported, returns
|
||||||
|
* NULL.
|
||||||
|
*/
|
||||||
|
PNMWriter *PNMFileTypeEXR::
|
||||||
|
make_writer(ostream *file, bool owns_file) {
|
||||||
|
init_pnm();
|
||||||
|
return new Writer(this, file, owns_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PNMFileTypeEXR::Reader::
|
||||||
|
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
|
||||||
|
PNMReader(type, file, owns_file),
|
||||||
|
_strm(new ImfStdIstream(*_file, magic_number)),
|
||||||
|
_imf_file(*_strm)
|
||||||
|
{
|
||||||
|
const IMF::Header &header = _imf_file.header();
|
||||||
|
|
||||||
|
IMATH_NAMESPACE::Box2i dw = header.dataWindow();
|
||||||
|
_x_size = dw.max.x - dw.min.x + 1;
|
||||||
|
_y_size = dw.max.y - dw.min.y + 1;
|
||||||
|
|
||||||
|
// Find the channels we care about, and ensure they're placed in the
|
||||||
|
// correct order.
|
||||||
|
_channel_names.clear();
|
||||||
|
|
||||||
|
const IMF::ChannelList &channels = header.channels();
|
||||||
|
|
||||||
|
// Note: including Y in this list allows us to handle grayscale or
|
||||||
|
// grayscale/alpha images correctly, but also incorrectly detects
|
||||||
|
// luminance/chroma images as grayscale only. However, these kind
|
||||||
|
// of images are a pain to handle anyway, so maybe that's OK.
|
||||||
|
const char *possible_channel_names[] = { "R", "G", "B", "Y", "A", NULL };
|
||||||
|
for (const char **pni = possible_channel_names; *pni != NULL; ++pni) {
|
||||||
|
std::string name = *pni;
|
||||||
|
IMF::ChannelList::ConstIterator ci = channels.find(name);
|
||||||
|
if (ci != channels.end()) {
|
||||||
|
// Found a match.
|
||||||
|
if (name == "Y" && !_channel_names.empty()) {
|
||||||
|
// Y is luminance or grayscale. Ignore Y if there are
|
||||||
|
// already any RGB channels.
|
||||||
|
} else {
|
||||||
|
_channel_names.push_back(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_channel_names.empty()) {
|
||||||
|
// Didn't find any channel names that match R, G, B, A, so just
|
||||||
|
// ask for RGB anyway and trust the OpenEXR library to do the
|
||||||
|
// right thing. Actually, it just fills them with black, but
|
||||||
|
// whatever.
|
||||||
|
_channel_names.push_back("R");
|
||||||
|
_channel_names.push_back("G");
|
||||||
|
_channel_names.push_back("B");
|
||||||
|
}
|
||||||
|
|
||||||
|
_num_channels = (int)_channel_names.size();
|
||||||
|
if (_num_channels == 0 || _num_channels > 4) {
|
||||||
|
_is_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We read all OpenEXR files to floating-point, even UINT type, so
|
||||||
|
// _maxval doesn't matter. But we set it anyway.
|
||||||
|
_maxval = 65535;
|
||||||
|
|
||||||
|
_is_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PNMFileTypeEXR::Reader::
|
||||||
|
~Reader() {
|
||||||
|
delete _strm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this PNMFileType represents a floating-point image type,
|
||||||
|
* false if it is a normal, integer type. If this returns true, read_pfm() is
|
||||||
|
* implemented instead of read_data().
|
||||||
|
*/
|
||||||
|
bool PNMFileTypeEXR::Reader::
|
||||||
|
is_floating_point() {
|
||||||
|
// We read everything to floating-point, since even the UINT type is
|
||||||
|
// 32 bits, more fidelity than we can represent in our 16-bit
|
||||||
|
// PNMImage.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads floating-point data directly into the indicated PfmFile. Returns
|
||||||
|
* true on success, false on failure.
|
||||||
|
*/
|
||||||
|
bool PNMFileTypeEXR::Reader::
|
||||||
|
read_pfm(PfmFile &pfm) {
|
||||||
|
pfm.clear(_x_size, _y_size, _num_channels);
|
||||||
|
vector_float table;
|
||||||
|
pfm.swap_table(table);
|
||||||
|
|
||||||
|
PN_float32 *table_data = table.data();
|
||||||
|
size_t x_stride = sizeof(PN_float32) * pfm.get_num_channels();
|
||||||
|
size_t y_stride = x_stride * pfm.get_x_size();
|
||||||
|
nassertr(y_stride * pfm.get_y_size() <= table.size() * sizeof(PN_float32), false);
|
||||||
|
|
||||||
|
const IMF::Header &header = _imf_file.header();
|
||||||
|
IMATH_NAMESPACE::Box2i dw = header.dataWindow();
|
||||||
|
|
||||||
|
IMF::FrameBuffer frameBuffer;
|
||||||
|
for (int ci = 0; ci < pfm.get_num_channels(); ++ci) {
|
||||||
|
char *base = (char *)(table_data - (dw.min.x + dw.min.y * pfm.get_x_size()) * pfm.get_num_channels() + ci);
|
||||||
|
frameBuffer.insert(_channel_names[ci].c_str(),
|
||||||
|
IMF::Slice(IMF::FLOAT, base, x_stride, y_stride,
|
||||||
|
1, 1, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
_imf_file.setFrameBuffer(frameBuffer);
|
||||||
|
|
||||||
|
try {
|
||||||
|
_imf_file.readPixels(dw.min.y, dw.max.y);
|
||||||
|
} catch (const std::exception &exc) {
|
||||||
|
pnmimage_exr_cat.error()
|
||||||
|
<< exc.what() << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfm.swap_table(table);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads in an entire image all at once, storing it in the pre-allocated
|
||||||
|
* _x_size * _y_size array and alpha pointers. (If the image type has no
|
||||||
|
* alpha channel, alpha is ignored.) Returns the number of rows correctly
|
||||||
|
* read.
|
||||||
|
*
|
||||||
|
* Derived classes need not override this if they instead provide
|
||||||
|
* supports_read_row() and read_row(), below.
|
||||||
|
*/
|
||||||
|
int PNMFileTypeEXR::Reader::
|
||||||
|
read_data(xel *array, xelval *alpha) {
|
||||||
|
// This should never come here, since we always read to
|
||||||
|
// floating-point data.
|
||||||
|
nassertr(false, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PNMFileTypeEXR::Writer::
|
||||||
|
Writer(PNMFileType *type, ostream *file, bool owns_file) :
|
||||||
|
PNMWriter(type, file, owns_file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this PNMFileType can accept a floating-point image type,
|
||||||
|
* false if it can only accept a normal, integer type. If this returns true,
|
||||||
|
* write_pfm() is implemented.
|
||||||
|
*/
|
||||||
|
bool PNMFileTypeEXR::Writer::
|
||||||
|
supports_floating_point() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this PNMFileType can accept an integer image type, false if
|
||||||
|
* it can only accept a floating-point type. If this returns true,
|
||||||
|
* write_data() or write_row() is implemented.
|
||||||
|
*/
|
||||||
|
bool PNMFileTypeEXR::Writer::
|
||||||
|
supports_integer() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes floating-point data from the indicated PfmFile. Returns true on
|
||||||
|
* success, false on failure.
|
||||||
|
*/
|
||||||
|
bool PNMFileTypeEXR::Writer::
|
||||||
|
write_pfm(const PfmFile &pfm) {
|
||||||
|
const vector_float &table = pfm.get_table();
|
||||||
|
const PN_float32 *table_data = table.data();
|
||||||
|
size_t x_stride = sizeof(PN_float32) * pfm.get_num_channels();
|
||||||
|
size_t y_stride = x_stride * pfm.get_x_size();
|
||||||
|
nassertr(y_stride * pfm.get_y_size() <= table.size() * sizeof(PN_float32), false);
|
||||||
|
|
||||||
|
const char *channel_names_1[] = { "G" };
|
||||||
|
const char *channel_names_2[] = { "G", "A" };
|
||||||
|
const char *channel_names_3[] = { "R", "G", "B" };
|
||||||
|
const char *channel_names_4[] = { "R", "G", "B", "A" };
|
||||||
|
const char **channel_names = NULL;
|
||||||
|
|
||||||
|
switch (pfm.get_num_channels()) {
|
||||||
|
case 1:
|
||||||
|
channel_names = channel_names_1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
channel_names = channel_names_2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
channel_names = channel_names_3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
channel_names = channel_names_4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
IMF::Header header(pfm.get_x_size(), pfm.get_y_size());
|
||||||
|
for (int ci = 0; ci < pfm.get_num_channels(); ++ci) {
|
||||||
|
header.channels().insert(channel_names[ci], IMF::Channel(IMF::FLOAT));
|
||||||
|
}
|
||||||
|
|
||||||
|
IMF::FrameBuffer frameBuffer;
|
||||||
|
for (int ci = 0; ci < pfm.get_num_channels(); ++ci) {
|
||||||
|
const char *base = (const char *)(table_data + ci);
|
||||||
|
frameBuffer.insert(channel_names[ci],
|
||||||
|
IMF::Slice(IMF::FLOAT, (char *)base, x_stride, y_stride));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImfStdOstream strm(*_file);
|
||||||
|
IMF::OutputFile file(strm, header);
|
||||||
|
file.setFrameBuffer(frameBuffer);
|
||||||
|
|
||||||
|
try {
|
||||||
|
file.writePixels(pfm.get_y_size());
|
||||||
|
} catch (const std::exception &exc) {
|
||||||
|
pnmimage_exr_cat.error()
|
||||||
|
<< exc.what() << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes out an entire image all at once, including the header, based on the
|
||||||
|
* image data stored in the given _x_size * _y_size array and alpha pointers.
|
||||||
|
* (If the image type has no alpha channel, alpha is ignored.) Returns the
|
||||||
|
* number of rows correctly written.
|
||||||
|
*
|
||||||
|
* It is the user's responsibility to fill in the header data via calls to
|
||||||
|
* set_x_size(), set_num_channels(), etc., or copy_header_from(), before
|
||||||
|
* calling write_data().
|
||||||
|
*
|
||||||
|
* It is important to delete the PNMWriter class after successfully writing
|
||||||
|
* the data. Failing to do this may result in some data not getting flushed!
|
||||||
|
*
|
||||||
|
* Derived classes need not override this if they instead provide
|
||||||
|
* supports_streaming() and write_row(), below.
|
||||||
|
*/
|
||||||
|
int PNMFileTypeEXR::Writer::
|
||||||
|
write_data(xel *array, xelval *alpha) {
|
||||||
|
// This should never come here, since we always write to
|
||||||
|
// floating-point data.
|
||||||
|
nassertr(false, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the current object as something that can be read from a Bam file.
|
||||||
|
*/
|
||||||
|
void PNMFileTypeEXR::
|
||||||
|
register_with_read_factory() {
|
||||||
|
BamReader::get_factory()->
|
||||||
|
register_factory(get_class_type(), make_PNMFileTypeEXR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called by the BamReader when an object of this type is
|
||||||
|
* encountered in a Bam file; it should allocate and return a new object with
|
||||||
|
* all the data read.
|
||||||
|
*
|
||||||
|
* In the case of the PNMFileType objects, since these objects are all shared,
|
||||||
|
* we just pull the object from the registry.
|
||||||
|
*/
|
||||||
|
TypedWritable *PNMFileTypeEXR::
|
||||||
|
make_PNMFileTypeEXR(const FactoryParams ¶ms) {
|
||||||
|
return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAVE_OPENEXR
|
110
panda/src/pnmimagetypes/pnmFileTypeEXR.h
Normal file
110
panda/src/pnmimagetypes/pnmFileTypeEXR.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file pnmFileTypeEXR.h
|
||||||
|
* @author drose
|
||||||
|
* @date 2000-06-17
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PNMFILETYPEEXR_H
|
||||||
|
#define PNMFILETYPEEXR_H
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENEXR
|
||||||
|
|
||||||
|
#include "pnmFileType.h"
|
||||||
|
#include "pnmReader.h"
|
||||||
|
#include "pnmWriter.h"
|
||||||
|
|
||||||
|
#include <ImfInputFile.h>
|
||||||
|
#include <ImfNamespace.h>
|
||||||
|
|
||||||
|
namespace IMF = OPENEXR_IMF_NAMESPACE;
|
||||||
|
|
||||||
|
class ImfStdIstream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For reading and writing EXR floating-point or integer files.
|
||||||
|
*/
|
||||||
|
class EXPCL_PANDA_PNMIMAGETYPES PNMFileTypeEXR : public PNMFileType {
|
||||||
|
public:
|
||||||
|
PNMFileTypeEXR();
|
||||||
|
|
||||||
|
virtual string get_name() const;
|
||||||
|
|
||||||
|
virtual int get_num_extensions() const;
|
||||||
|
virtual string get_extension(int n) const;
|
||||||
|
virtual string get_suggested_extension() const;
|
||||||
|
|
||||||
|
virtual bool has_magic_number() const;
|
||||||
|
virtual bool matches_magic_number(const string &magic_number) const;
|
||||||
|
|
||||||
|
virtual PNMReader *make_reader(istream *file, bool owns_file = true,
|
||||||
|
const string &magic_number = string());
|
||||||
|
virtual PNMWriter *make_writer(ostream *file, bool owns_file = true);
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Reader : public PNMReader {
|
||||||
|
public:
|
||||||
|
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number);
|
||||||
|
virtual ~Reader();
|
||||||
|
|
||||||
|
virtual bool is_floating_point();
|
||||||
|
virtual bool read_pfm(PfmFile &pfm);
|
||||||
|
virtual int read_data(xel *array, xelval *alpha);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class ImfStdIstream *_strm;
|
||||||
|
IMF::InputFile _imf_file;
|
||||||
|
|
||||||
|
typedef std::vector<std::string> ChannelNames;
|
||||||
|
ChannelNames _channel_names;
|
||||||
|
IMF::PixelType _best_pixel_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Writer : public PNMWriter {
|
||||||
|
public:
|
||||||
|
Writer(PNMFileType *type, ostream *file, bool owns_file);
|
||||||
|
|
||||||
|
virtual bool supports_floating_point();
|
||||||
|
virtual bool supports_integer();
|
||||||
|
virtual bool write_pfm(const PfmFile &pfm);
|
||||||
|
virtual int write_data(xel *array, xelval *alpha);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// The TypedWritable interface follows.
|
||||||
|
public:
|
||||||
|
static void register_with_read_factory();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static TypedWritable *make_PNMFileTypeEXR(const FactoryParams ¶ms);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static TypeHandle get_class_type() {
|
||||||
|
return _type_handle;
|
||||||
|
}
|
||||||
|
static void init_type() {
|
||||||
|
PNMFileType::init_type();
|
||||||
|
register_type(_type_handle, "PNMFileTypeEXR",
|
||||||
|
PNMFileType::get_class_type());
|
||||||
|
}
|
||||||
|
virtual TypeHandle get_type() const {
|
||||||
|
return get_class_type();
|
||||||
|
}
|
||||||
|
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TypeHandle _type_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HAVE_OPENEXR
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user