mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 09:23:03 -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
|
||||
"ODE", "PHYSX", "BULLET", "PANDAPHYSICS", # Physics
|
||||
"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
|
||||
"VRPN", "OPENSSL", # Transport
|
||||
"FFTW", # Algorithm helpers
|
||||
@ -604,6 +604,11 @@ if (COMPILER == "MSVC"):
|
||||
LibName("TIFF", GetThirdpartyDir() + "tiff/lib/libtiff.lib")
|
||||
else:
|
||||
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("ZLIB")==0): LibName("ZLIB", GetThirdpartyDir() + "zlib/lib/zlibstatic.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("SQUISH", "", ("squish"), "squish.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("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h"))
|
||||
SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h"))
|
||||
@ -2201,6 +2207,7 @@ DTOOL_CONFIG=[
|
||||
("PHAVE_JPEGINT_H", '1', '1'),
|
||||
("HAVE_VIDEO4LINUX", 'UNDEF', '1'),
|
||||
("HAVE_TIFF", 'UNDEF', 'UNDEF'),
|
||||
("HAVE_OPENEXR", 'UNDEF', 'UNDEF'),
|
||||
("HAVE_SGI_RGB", '1', '1'),
|
||||
("HAVE_TGA", '1', '1'),
|
||||
("HAVE_IMG", '1', '1'),
|
||||
@ -3824,7 +3831,7 @@ 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_composite2.obj', opts=OPTS, input='p3pnmimagetypes_composite2.cxx')
|
||||
|
||||
@ -3869,7 +3876,7 @@ if (not RUNTIME):
|
||||
|
||||
if (not RUNTIME):
|
||||
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']
|
||||
|
||||
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "pnmFileTypePNM.h"
|
||||
#include "pnmFileTypePfm.h"
|
||||
#include "pnmFileTypeTIFF.h"
|
||||
#include "pnmFileTypeEXR.h"
|
||||
#include "pnmFileTypeStbImage.h"
|
||||
#include "sgi.h"
|
||||
|
||||
@ -41,6 +42,7 @@ NotifyCategoryDefName(pnmimage_jpg, "jpg", pnmimage_cat);
|
||||
NotifyCategoryDefName(pnmimage_png, "png", pnmimage_cat);
|
||||
NotifyCategoryDefName(pnmimage_pnm, "pnm", pnmimage_cat);
|
||||
NotifyCategoryDefName(pnmimage_tiff, "tiff", pnmimage_cat);
|
||||
NotifyCategoryDefName(pnmimage_exr, "exr", pnmimage_cat);
|
||||
|
||||
ConfigVariableEnum<SGIStorageType> sgi_storage_type
|
||||
("sgi-storage-type", SST_rle,
|
||||
@ -241,6 +243,12 @@ init_libpnmimagetypes() {
|
||||
tr->register_type(new PNMFileTypeTIFF);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENEXR
|
||||
PNMFileTypeEXR::init_type();
|
||||
PNMFileTypeEXR::register_with_read_factory();
|
||||
tr->register_type(new PNMFileTypeEXR);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STB_IMAGE
|
||||
PNMFileTypeStbImage::init_type();
|
||||
PNMFileTypeStbImage::register_with_read_factory();
|
||||
@ -259,4 +267,7 @@ init_libpnmimagetypes() {
|
||||
#ifdef HAVE_TIFF
|
||||
ps->add_system("libtiff");
|
||||
#endif
|
||||
#ifdef HAVE_OPENEXR
|
||||
ps->add_system("openexr");
|
||||
#endif
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
NotifyCategoryDecl(pnmimage_sgi, 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_img, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||
NotifyCategoryDecl(pnmimage_soft, EXPCL_PANDA_PNMIMAGETYPES, EXPTP_PANDA_PNMIMAGETYPES);
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include "config_pnmimagetypes.cxx"
|
||||
#include "pnmFileTypeBMPReader.cxx"
|
||||
#include "pnmFileTypeBMPWriter.cxx"
|
||||
#include "pnmFileTypeIMG.cxx"
|
||||
#include "pnmFileTypeBMP.cxx"
|
||||
#include "pnmFileTypeEXR.cxx"
|
||||
#include "pnmFileTypeIMG.cxx"
|
||||
#include "pnmFileTypeJPG.cxx"
|
||||
#include "pnmFileTypeJPGReader.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