integrate PfmFile with PNMImage, Texture

This commit is contained in:
David Rose 2012-08-12 15:49:08 +00:00
parent 5bd76de269
commit 7ba693137c
19 changed files with 740 additions and 326 deletions

View File

@ -28,6 +28,8 @@
#include "string_utils.h" #include "string_utils.h"
#include "preparedGraphicsObjects.h" #include "preparedGraphicsObjects.h"
#include "pnmImage.h" #include "pnmImage.h"
#include "pnmReader.h"
#include "pfmFile.h"
#include "virtualFileSystem.h" #include "virtualFileSystem.h"
#include "datagramInputFile.h" #include "datagramInputFile.h"
#include "datagramOutputFile.h" #include "datagramOutputFile.h"
@ -2913,12 +2915,40 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
} }
PNMImage image; PNMImage image;
if (header_only || textures_header_only) { PfmFile pfm;
if (!image.read_header(fullpath)) { PNMReader *image_reader = image.make_reader(fullpath, NULL, false);
if (image_reader == NULL) {
gobj_cat.error() gobj_cat.error()
<< "Texture::read() - couldn't read: " << fullpath << endl; << "Texture::read() - couldn't read: " << fullpath << endl;
return false; return false;
} }
image.copy_header_from(*image_reader);
// If it's a single-channel floating-point image file, read it by
// default into a floating-point texture. (Multi-channel image
// files are ready as integers by default, since current graphics
// API's don't support multi-channel float textures.)
bool read_floating_point;
int texture_load_type = (options.get_texture_flags() & (LoaderOptions::TF_integer | LoaderOptions::TF_float));
switch (texture_load_type) {
case LoaderOptions::TF_integer:
read_floating_point = false;
break;
case LoaderOptions::TF_float:
read_floating_point = true;
break;
default:
// Neither TF_integer nor TF_float was specified; determine which
// way the texture wants to be loaded.
read_floating_point = (image_reader->is_floating_point() && image_reader->get_num_channels() == 1);
if (!alpha_fullpath.empty()) {
read_floating_point = false;
}
}
if (header_only || textures_header_only) {
int x_size = image.get_x_size(); int x_size = image.get_x_size();
int y_size = image.get_y_size(); int y_size = image.get_y_size();
if (z == 0 && n == 0) { if (z == 0 && n == 0) {
@ -2938,20 +2968,19 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
y_size = image.get_read_y_size(); y_size = image.get_read_y_size();
} }
if (read_floating_point) {
pfm.clear(x_size, y_size, image.get_num_channels());
} else {
image = PNMImage(x_size, y_size, image.get_num_channels(), image = PNMImage(x_size, y_size, image.get_num_channels(),
image.get_maxval(), image.get_type()); image.get_maxval(), image.get_type());
image.fill(0.2, 0.3, 1.0); image.fill(0.2, 0.3, 1.0);
if (image.has_alpha()) { if (image.has_alpha()) {
image.alpha_fill(1.0); image.alpha_fill(1.0);
} }
}
delete image_reader;
} else { } else {
if (!image.read_header(fullpath, NULL, false)) {
gobj_cat.error()
<< "Texture::read() - couldn't read: " << fullpath << endl;
return false;
}
if (z == 0 && n == 0) { if (z == 0 && n == 0) {
cdata->_orig_file_x_size = image.get_x_size(); cdata->_orig_file_x_size = image.get_x_size();
cdata->_orig_file_y_size = image.get_y_size(); cdata->_orig_file_y_size = image.get_y_size();
@ -2970,7 +2999,14 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
<< "\n"; << "\n";
} }
if (!image.read(fullpath, NULL, false)) { bool success;
if (read_floating_point) {
success = pfm.read(image_reader);
} else {
success = image.read(image_reader);
}
if (!success) {
gobj_cat.error() gobj_cat.error()
<< "Texture::read() - couldn't read: " << fullpath << endl; << "Texture::read() - couldn't read: " << fullpath << endl;
return false; return false;
@ -2980,16 +3016,19 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
PNMImage alpha_image; PNMImage alpha_image;
if (!alpha_fullpath.empty()) { if (!alpha_fullpath.empty()) {
PNMReader *alpha_image_reader = alpha_image.make_reader(alpha_fullpath, NULL, false);
if (alpha_image_reader == NULL) {
gobj_cat.error()
<< "Texture::read() - couldn't read: " << alpha_fullpath << endl;
return false;
}
alpha_image.copy_header_from(*alpha_image_reader);
if (record != (BamCacheRecord *)NULL) { if (record != (BamCacheRecord *)NULL) {
record->add_dependent_file(alpha_fullpath); record->add_dependent_file(alpha_fullpath);
} }
if (header_only || textures_header_only) { if (header_only || textures_header_only) {
if (!alpha_image.read_header(alpha_fullpath)) {
gobj_cat.error()
<< "Texture::read() - couldn't read: " << alpha_fullpath << endl;
return false;
}
int x_size = image.get_x_size(); int x_size = image.get_x_size();
int y_size = image.get_y_size(); int y_size = image.get_y_size();
alpha_image = PNMImage(x_size, y_size, alpha_image.get_num_channels(), alpha_image = PNMImage(x_size, y_size, alpha_image.get_num_channels(),
@ -2998,14 +3037,9 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
if (alpha_image.has_alpha()) { if (alpha_image.has_alpha()) {
alpha_image.alpha_fill(1.0); alpha_image.alpha_fill(1.0);
} }
delete alpha_image_reader;
} else { } else {
if (!alpha_image.read_header(alpha_fullpath, NULL, true)) {
gobj_cat.error()
<< "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
return false;
}
if (image.get_x_size() != alpha_image.get_x_size() || if (image.get_x_size() != alpha_image.get_x_size() ||
image.get_y_size() != alpha_image.get_y_size()) { image.get_y_size() != alpha_image.get_y_size()) {
gobj_cat.info() gobj_cat.info()
@ -3016,7 +3050,7 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
alpha_image.set_read_size(image.get_x_size(), image.get_y_size()); alpha_image.set_read_size(image.get_x_size(), image.get_y_size());
} }
if (!alpha_image.read(alpha_fullpath, NULL, true)) { if (!alpha_image.read(alpha_image_reader)) {
gobj_cat.error() gobj_cat.error()
<< "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl; << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
return false; return false;
@ -3106,6 +3140,11 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
} }
} }
if (read_floating_point) {
if (!do_load_one(cdata, pfm, fullpath.get_basename(), z, n, options)) {
return false;
}
} else {
// Now see if we want to pad the image within a larger power-of-2 // Now see if we want to pad the image within a larger power-of-2
// image. // image.
int pad_x_size = 0; int pad_x_size = 0;
@ -3128,6 +3167,7 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
} }
do_set_pad_size(cdata, pad_x_size, pad_y_size, 0); do_set_pad_size(cdata, pad_x_size, pad_y_size, 0);
}
return true; return true;
} }
@ -3205,6 +3245,74 @@ do_load_one(CData *cdata, const PNMImage &pnmimage, const string &name, int z, i
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: Texture::do_load_one
// Access: Protected, Virtual
// Description: Internal method to load a single page or mipmap
// level.
////////////////////////////////////////////////////////////////////
bool Texture::
do_load_one(CData *cdata, const PfmFile &pfm, const string &name, int z, int n,
const LoaderOptions &options) {
if (cdata->_ram_images.size() <= 1 && n == 0) {
// A special case for mipmap level 0. When we load mipmap level
// 0, unless we already have mipmap levels, it determines the
// image properties like size and number of components.
if (!do_reconsider_z_size(cdata, z, options)) {
return false;
}
nassertr(z >= 0 && z < cdata->_z_size * cdata->_num_views, false);
if (z == 0) {
ComponentType component_type = T_float;
if (!do_reconsider_image_properties(cdata, pfm.get_x_size(), pfm.get_y_size(),
pfm.get_num_channels(), component_type,
z, options)) {
return false;
}
}
do_modify_ram_image(cdata);
cdata->_loaded_from_image = true;
}
do_modify_ram_mipmap_image(cdata, n);
// Ensure the PfmFile is an appropriate size.
int x_size = do_get_expected_mipmap_x_size(cdata, n);
int y_size = do_get_expected_mipmap_y_size(cdata, n);
if (pfm.get_x_size() != x_size ||
pfm.get_y_size() != y_size) {
gobj_cat.info()
<< "Automatically rescaling " << name;
if (n != 0) {
gobj_cat.info(false)
<< " mipmap level " << n;
}
gobj_cat.info(false)
<< " from " << pfm.get_x_size() << " by "
<< pfm.get_y_size() << " to " << x_size << " by "
<< y_size << "\n";
PfmFile scaled(pfm);
scaled.resize(x_size, y_size);
Thread::consider_yield();
convert_from_pfm(cdata->_ram_images[n]._image,
do_get_expected_ram_mipmap_page_size(cdata, n), z,
scaled, cdata->_num_components, cdata->_component_width);
} else {
// Now copy the pixel data from the PfmFile into our internal
// cdata->_image component.
convert_from_pfm(cdata->_ram_images[n]._image,
do_get_expected_ram_mipmap_page_size(cdata, n), z,
pfm, cdata->_num_components, cdata->_component_width);
}
Thread::consider_yield();
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Texture::do_read_txo_file // Function: Texture::do_read_txo_file
// Access: Protected // Access: Protected
@ -3691,16 +3799,29 @@ do_write_one(CData *cdata, const Filename &fullpath, int z, int n) {
nassertr(cdata->_ram_image_compression == CM_off, false); nassertr(cdata->_ram_image_compression == CM_off, false);
bool success;
if (cdata->_component_type == T_float) {
// Writing a floating-point texture.
PfmFile pfm;
if (!do_store_one(cdata, pfm, z, n)) {
return false;
}
success = pfm.write(fullpath);
} else {
// Writing a normal, integer texture.
PNMImage pnmimage; PNMImage pnmimage;
if (!do_store_one(cdata, pnmimage, z, n)) { if (!do_store_one(cdata, pnmimage, z, n)) {
return false; return false;
} }
success = pnmimage.write(fullpath);
}
if (!pnmimage.write(fullpath)) { if (!success) {
gobj_cat.error() gobj_cat.error()
<< "Texture::write() - couldn't write: " << fullpath << endl; << "Texture::write() - couldn't write: " << fullpath << endl;
return false; return false;
} }
return true; return true;
} }
@ -3730,6 +3851,32 @@ do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n) {
do_get_ram_mipmap_page_size(cdata, n), z); do_get_ram_mipmap_page_size(cdata, n), z);
} }
////////////////////////////////////////////////////////////////////
// Function: Texture::do_store_one
// Access: Protected
// Description: Internal method to copy a page and/or mipmap level to
// a PfmFile.
////////////////////////////////////////////////////////////////////
bool Texture::
do_store_one(CData *cdata, PfmFile &pfm, int z, int n) {
// First, reload the ram image if necessary.
do_get_uncompressed_ram_image(cdata);
if (!do_has_ram_mipmap_image(cdata, n)) {
return false;
}
nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n), false);
nassertr(cdata->_ram_image_compression == CM_off, false);
return convert_to_pfm(pfm,
do_get_expected_mipmap_x_size(cdata, n),
do_get_expected_mipmap_y_size(cdata, n),
cdata->_num_components, cdata->_component_width,
cdata->_ram_images[n]._image,
do_get_ram_mipmap_page_size(cdata, n), z);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Texture::do_write_txo_file // Function: Texture::do_write_txo_file
// Access: Private // Access: Private
@ -4497,14 +4644,18 @@ bool Texture::
do_reconsider_image_properties(CData *cdata, int x_size, int y_size, int num_components, do_reconsider_image_properties(CData *cdata, int x_size, int y_size, int num_components,
Texture::ComponentType component_type, int z, Texture::ComponentType component_type, int z,
const LoaderOptions &options) { const LoaderOptions &options) {
if (!cdata->_loaded_from_image || num_components != cdata->_num_components) { if (!cdata->_loaded_from_image || num_components != cdata->_num_components || component_type != cdata->_component_type) {
// Come up with a default format based on the number of channels. // Come up with a default format based on the number of channels.
// But only do this the first time the file is loaded, or if the // But only do this the first time the file is loaded, or if the
// number of channels in the image changes on subsequent loads. // number of channels in the image changes on subsequent loads.
switch (num_components) { switch (num_components) {
case 1: case 1:
if (component_type == T_float) {
cdata->_format = F_depth_component;
} else {
cdata->_format = F_luminance; cdata->_format = F_luminance;
}
break; break;
case 2: case 2:
@ -5711,6 +5862,35 @@ convert_from_pnmimage(PTA_uchar &image, size_t page_size, int z,
nassertv(p == &image[idx] + page_size); nassertv(p == &image[idx] + page_size);
} }
////////////////////////////////////////////////////////////////////
// Function: Texture::convert_from_pfm
// Access: Private, Static
// Description: Internal method to convert pixel data from the
// indicated PfmFile into the given ram_image.
////////////////////////////////////////////////////////////////////
void Texture::
convert_from_pfm(PTA_uchar &image, size_t page_size, int z,
const PfmFile &pfm, int num_components, int component_width) {
nassertv(component_width == 4); // Currently only PN_float32 is expected.
int x_size = pfm.get_x_size();
int y_size = pfm.get_y_size();
int idx = page_size * z;
nassertv(idx + page_size <= image.size());
PN_float32 *p = (PN_float32 *)&image[idx];
for (int j = y_size-1; j >= 0; j--) {
for (int i = 0; i < x_size; i++) {
for (int c = 0; c < num_components; ++c) {
*p = pfm.get_component(i, j, c);
++p;
}
}
}
nassertv((unsigned char *)p == &image[idx] + page_size);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Texture::convert_to_pnmimage // Function: Texture::convert_to_pnmimage
// Access: Private, Static // Access: Private, Static
@ -5769,6 +5949,36 @@ convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: Texture::convert_to_pfm
// Access: Private, Static
// Description: Internal method to convert pixel data to the
// indicated PfmFile from the given ram_image.
////////////////////////////////////////////////////////////////////
bool Texture::
convert_to_pfm(PfmFile &pfm, int x_size, int y_size,
int num_components, int component_width,
CPTA_uchar image, size_t page_size, int z) {
nassertr(component_width == 4, false); // Currently only PN_float32 is expected.
pfm.clear(x_size, y_size, num_components);
int idx = page_size * z;
nassertr(idx + page_size <= image.size(), false);
const PN_float32 *p = (const PN_float32 *)&image[idx];
for (int j = y_size-1; j >= 0; j--) {
for (int i = 0; i < x_size; i++) {
for (int c = 0; c < num_components; ++c) {
pfm.set_component(i, j, c, *p);
++p;
}
}
}
nassertr((unsigned char *)p == &image[idx] + page_size, false);
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Texture::read_dds_level_bgr8 // Function: Texture::read_dds_level_bgr8
// Access: Private, Static // Access: Private, Static

View File

@ -41,6 +41,7 @@
#include "pipelineCycler.h" #include "pipelineCycler.h"
class PNMImage; class PNMImage;
class PfmFile;
class TextureContext; class TextureContext;
class FactoryParams; class FactoryParams;
class PreparedGraphicsObjects; class PreparedGraphicsObjects;
@ -541,6 +542,9 @@ protected:
virtual bool do_load_one(CData *cdata, virtual bool do_load_one(CData *cdata,
const PNMImage &pnmimage, const string &name, const PNMImage &pnmimage, const string &name,
int z, int n, const LoaderOptions &options); int z, int n, const LoaderOptions &options);
virtual bool do_load_one(CData *cdata,
const PfmFile &pfm, const string &name,
int z, int n, const LoaderOptions &options);
bool do_read_txo_file(CData *cdata, const Filename &fullpath); bool do_read_txo_file(CData *cdata, const Filename &fullpath);
bool do_read_txo(CData *cdata, istream &in, const string &filename); bool do_read_txo(CData *cdata, istream &in, const string &filename);
bool do_read_dds_file(CData *cdata, const Filename &fullpath, bool header_only); bool do_read_dds_file(CData *cdata, const Filename &fullpath, bool header_only);
@ -550,6 +554,7 @@ protected:
bool write_pages, bool write_mipmaps); bool write_pages, bool write_mipmaps);
bool do_write_one(CData *cdata, const Filename &fullpath, int z, int n); bool do_write_one(CData *cdata, const Filename &fullpath, int z, int n);
bool do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n); bool do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n);
bool do_store_one(CData *cdata, PfmFile &pfm, int z, int n);
bool do_write_txo_file(const CData *cdata, const Filename &fullpath) const; bool do_write_txo_file(const CData *cdata, const Filename &fullpath) const;
bool do_write_txo(const CData *cdata, ostream &out, const string &filename) const; bool do_write_txo(const CData *cdata, ostream &out, const string &filename) const;
@ -656,10 +661,17 @@ private:
static void convert_from_pnmimage(PTA_uchar &image, size_t page_size, static void convert_from_pnmimage(PTA_uchar &image, size_t page_size,
int z, const PNMImage &pnmimage, int z, const PNMImage &pnmimage,
int num_components, int component_width); int num_components, int component_width);
static void convert_from_pfm(PTA_uchar &image, size_t page_size,
int z, const PfmFile &pfm,
int num_components, int component_width);
static bool convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size, static bool convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
int num_components, int component_width, int num_components, int component_width,
CPTA_uchar image, size_t page_size, CPTA_uchar image, size_t page_size,
int z); int z);
static bool convert_to_pfm(PfmFile &pfm, int x_size, int y_size,
int num_components, int component_width,
CPTA_uchar image, size_t page_size,
int z);
static PTA_uchar read_dds_level_bgr8(Texture *tex, CData *cdata, const DDSHeader &header, static PTA_uchar read_dds_level_bgr8(Texture *tex, CData *cdata, const DDSHeader &header,
int n, istream &in); int n, istream &in);
static PTA_uchar read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header, static PTA_uchar read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header,

View File

@ -12,7 +12,6 @@
#define SOURCES \ #define SOURCES \
config_pnmimage.h \ config_pnmimage.h \
pfmFile.I pfmFile.h \ pfmFile.I pfmFile.h \
pnmFileTypePfm.h \
pnmbitio.h \ pnmbitio.h \
pnmBrush.h pnmBrush.I \ pnmBrush.h pnmBrush.I \
pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \ pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \
@ -25,7 +24,6 @@
#define INCLUDED_SOURCES \ #define INCLUDED_SOURCES \
config_pnmimage.cxx \ config_pnmimage.cxx \
pfmFile.cxx \ pfmFile.cxx \
pnmFileTypePfm.cxx \
pnm-image-filter.cxx \ pnm-image-filter.cxx \
pnmbitio.cxx \ pnmbitio.cxx \
pnmBrush.cxx \ pnmBrush.cxx \
@ -38,7 +36,6 @@
#define INSTALL_HEADERS \ #define INSTALL_HEADERS \
config_pnmimage.h \ config_pnmimage.h \
pfmFile.I pfmFile.h \ pfmFile.I pfmFile.h \
pnmFileTypePfm.h \
pnmBrush.h pnmBrush.I \ pnmBrush.h pnmBrush.I \
pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \ pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \
pnmImage.h pnmImageHeader.I pnmImageHeader.h \ pnmImage.h pnmImageHeader.I pnmImageHeader.h \

View File

@ -14,7 +14,6 @@
#include "config_pnmimage.h" #include "config_pnmimage.h"
#include "pnmFileType.h" #include "pnmFileType.h"
#include "pnmFileTypePfm.h"
#include "pnmFileTypeRegistry.h" #include "pnmFileTypeRegistry.h"
#include "dconfig.h" #include "dconfig.h"
@ -66,9 +65,4 @@ init_libpnmimage() {
initialized = true; initialized = true;
PNMFileType::init_type(); PNMFileType::init_type();
PNMFileTypeRegistry *tr = PNMFileTypeRegistry::get_global_ptr();
PNMFileTypePfm::init_type();
PNMFileTypePfm::register_with_read_factory();
tr->register_type(new PNMFileTypePfm);
} }

View File

@ -1,6 +1,5 @@
#include "config_pnmimage.cxx" #include "config_pnmimage.cxx"
#include "pfmFile.cxx" #include "pfmFile.cxx"
#include "pnmFileTypePfm.cxx"
#include "pnm-image-filter.cxx" #include "pnm-image-filter.cxx"
#include "pnmbitio.cxx" #include "pnmbitio.cxx"
#include "pnmBrush.cxx" #include "pnmBrush.cxx"

View File

@ -23,26 +23,6 @@ is_valid() const {
return _num_channels != 0 && (_x_size * _y_size * _num_channels <= (int)_table.size()); return _num_channels != 0 && (_x_size * _y_size * _num_channels <= (int)_table.size());
} }
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_x_size
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE int PfmFile::
get_x_size() const {
return _x_size;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_y_size
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE int PfmFile::
get_y_size() const {
return _y_size;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_scale // Function: PfmFile::get_scale
// Access: Published // Access: Published
@ -55,18 +35,14 @@ get_scale() const {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_num_channels // Function: PfmFile::set_scale
// Access: Published // Access: Published
// Description: A pfm file can be either 1-channel // Description: The "scale" is reported in the pfm header and is
// (get_num_channels() == 1) or 3-channel // probably meaningless.
// (get_num_channels() == 3). In the case of a
// 1-channel file, the values can be found in the x
// component of each point, and the y and z components
// are unused.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE int PfmFile:: INLINE void PfmFile::
get_num_channels() const { set_scale(PN_float32 scale) {
return _num_channels; _scale = scale;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -82,6 +58,34 @@ has_point(int x, int y) const {
return _has_point(this, x, y); return _has_point(this, x, y);
} }
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_component
// Access: Published
// Description: Returns the cth component of the point value at the
// indicated point.
////////////////////////////////////////////////////////////////////
INLINE PN_float32 PfmFile::
get_component(int x, int y, int c) const {
nassertr(x >= 0 && x < _x_size &&
y >= 0 && y < _y_size &&
c >= 0 && c < _num_channels, 0.0f);
return _table[(y * _x_size + x) * _num_channels + c];
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_component
// Access: Published
// Description: Replaces the cth component of the point value at the
// indicated point.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_component(int x, int y, int c, PN_float32 value) {
nassertv(x >= 0 && x < _x_size &&
y >= 0 && y < _y_size &&
c >= 0 && c < _num_channels);
_table[(y * _x_size + x) * _num_channels + c] = value;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_point1 // Function: PfmFile::get_point1
// Access: Published // Access: Published
@ -90,8 +94,8 @@ has_point(int x, int y) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE PN_float32 PfmFile:: INLINE PN_float32 PfmFile::
get_point1(int x, int y) const { get_point1(int x, int y) const {
nassertr(x >= 0 && x < _x_size, 0.0); nassertr(x >= 0 && x < _x_size &&
nassertr(y >= 0 && y < _y_size, 0.0); y >= 0 && y < _y_size, 0.0);
return _table[(y * _x_size + x) * _num_channels]; return _table[(y * _x_size + x) * _num_channels];
} }
@ -104,8 +108,8 @@ get_point1(int x, int y) const {
INLINE void PfmFile:: INLINE void PfmFile::
set_point1(int x, int y, PN_float32 point) { set_point1(int x, int y, PN_float32 point) {
nassertv(!cnan(point)); nassertv(!cnan(point));
nassertv(x >= 0 && x < _x_size); nassertv(x >= 0 && x < _x_size &&
nassertv(y >= 0 && y < _y_size); y >= 0 && y < _y_size);
_table[(y * _x_size + x) * _num_channels] = point; _table[(y * _x_size + x) * _num_channels] = point;
} }
@ -118,8 +122,8 @@ set_point1(int x, int y, PN_float32 point) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE const LPoint3f &PfmFile:: INLINE const LPoint3f &PfmFile::
get_point(int x, int y) const { get_point(int x, int y) const {
nassertr(x >= 0 && x < _x_size, LPoint3f::zero()); nassertr(x >= 0 && x < _x_size &&
nassertr(y >= 0 && y < _y_size, LPoint3f::zero()); y >= 0 && y < _y_size, LPoint3f::zero());
return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]; return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels];
} }
@ -133,8 +137,8 @@ get_point(int x, int y) const {
INLINE void PfmFile:: INLINE void PfmFile::
set_point(int x, int y, const LVecBase3f &point) { set_point(int x, int y, const LVecBase3f &point) {
nassertv(!point.is_nan()); nassertv(!point.is_nan());
nassertv(x >= 0 && x < _x_size); nassertv(x >= 0 && x < _x_size &&
nassertv(y >= 0 && y < _y_size); y >= 0 && y < _y_size);
switch (_num_channels) { switch (_num_channels) {
case 1: case 1:
_table[(y * _x_size + x)] = point[0]; _table[(y * _x_size + x)] = point[0];
@ -169,8 +173,8 @@ INLINE LPoint3f &PfmFile::
modify_point(int x, int y) { modify_point(int x, int y) {
#ifndef NDEBUG #ifndef NDEBUG
static LPoint3f dummy_value = LPoint3f::zero(); static LPoint3f dummy_value = LPoint3f::zero();
nassertr(x >= 0 && x < _x_size, dummy_value); nassertr(x >= 0 && x < _x_size &&
nassertr(y >= 0 && y < _y_size, dummy_value); y >= 0 && y < _y_size, dummy_value);
#endif #endif
return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]; return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels];
@ -185,8 +189,8 @@ modify_point(int x, int y) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE const LPoint4f &PfmFile:: INLINE const LPoint4f &PfmFile::
get_point4(int x, int y) const { get_point4(int x, int y) const {
nassertr(x >= 0 && x < _x_size, LPoint4f::zero()); nassertr(x >= 0 && x < _x_size &&
nassertr(y >= 0 && y < _y_size, LPoint4f::zero()); y >= 0 && y < _y_size, LPoint4f::zero());
return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]; return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels];
} }
@ -200,8 +204,8 @@ get_point4(int x, int y) const {
INLINE void PfmFile:: INLINE void PfmFile::
set_point4(int x, int y, const LVecBase4f &point) { set_point4(int x, int y, const LVecBase4f &point) {
nassertv(!point.is_nan()); nassertv(!point.is_nan());
nassertv(x >= 0 && x < _x_size); nassertv(x >= 0 && x < _x_size &&
nassertv(y >= 0 && y < _y_size); y >= 0 && y < _y_size);
switch (_num_channels) { switch (_num_channels) {
case 1: case 1:
_table[(y * _x_size + x)] = point[0]; _table[(y * _x_size + x)] = point[0];
@ -239,8 +243,8 @@ INLINE LPoint4f &PfmFile::
modify_point4(int x, int y) { modify_point4(int x, int y) {
#ifndef NDEBUG #ifndef NDEBUG
static LPoint4f dummy_value = LPoint4f::zero(); static LPoint4f dummy_value = LPoint4f::zero();
nassertr(x >= 0 && x < _x_size, dummy_value); nassertr(x >= 0 && x < _x_size &&
nassertr(y >= 0 && y < _y_size, dummy_value); y >= 0 && y < _y_size, dummy_value);
#endif #endif
return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]; return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels];
@ -517,3 +521,30 @@ INLINE bool PfmFile::
get_vis_2d() const { get_vis_2d() const {
return _vis_2d; return _vis_2d;
} }
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_table
// Access: Public
// Description: This is a very low-level function that returns a
// read-only reference to the internal table of
// floating-point numbers. Use this method at your own
// risk.
////////////////////////////////////////////////////////////////////
INLINE const pvector<PN_float32> &PfmFile::
get_table() const {
return _table;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::swap_table
// Access: Public
// Description: This is a very low-level function that completely
// exchanges the PfmFile's internal table of
// floating-point numbers with whatever you supply. The
// provided table must have an appropriate size. Use
// this method at your own risk.
////////////////////////////////////////////////////////////////////
void PfmFile::
swap_table(pvector<PN_float32> &table) {
_table.swap(table);
}

View File

@ -27,6 +27,7 @@
#include "geomTriangles.h" #include "geomTriangles.h"
#include "geomVertexWriter.h" #include "geomVertexWriter.h"
#include "pnmImage.h" #include "pnmImage.h"
#include "pnmReader.h"
#include "pnmWriter.h" #include "pnmWriter.h"
#include "string_utils.h" #include "string_utils.h"
#include "lens.h" #include "lens.h"
@ -54,11 +55,9 @@ PfmFile() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PfmFile:: PfmFile::
PfmFile(const PfmFile &copy) : PfmFile(const PfmFile &copy) :
PNMImageHeader(copy),
_table(copy._table), _table(copy._table),
_x_size(copy._x_size),
_y_size(copy._y_size),
_scale(copy._scale), _scale(copy._scale),
_num_channels(copy._num_channels),
_has_no_data_value(copy._has_no_data_value), _has_no_data_value(copy._has_no_data_value),
_no_data_value(copy._no_data_value), _no_data_value(copy._no_data_value),
_has_point(copy._has_point), _has_point(copy._has_point),
@ -74,11 +73,9 @@ PfmFile(const PfmFile &copy) :
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void PfmFile:: void PfmFile::
operator = (const PfmFile &copy) { operator = (const PfmFile &copy) {
PNMImageHeader::operator = (copy);
_table = copy._table; _table = copy._table;
_x_size = copy._x_size;
_y_size = copy._y_size;
_scale = copy._scale; _scale = copy._scale;
_num_channels = copy._num_channels;
_has_no_data_value = copy._has_no_data_value; _has_no_data_value = copy._has_no_data_value;
_no_data_value = copy._no_data_value; _no_data_value = copy._no_data_value;
_has_point = copy._has_point; _has_point = copy._has_point;
@ -108,7 +105,6 @@ clear() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void PfmFile:: void PfmFile::
clear(int x_size, int y_size, int num_channels) { clear(int x_size, int y_size, int num_channels) {
nassertv(num_channels == 1 || num_channels == 3);
nassertv(x_size >= 0 && y_size >= 0); nassertv(x_size >= 0 && y_size >= 0);
_x_size = x_size; _x_size = x_size;
_y_size = y_size; _y_size = y_size;
@ -172,108 +168,49 @@ read(const Filename &fullpath) {
// to a floating-point type. // to a floating-point type.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool PfmFile:: bool PfmFile::
read(istream &in, const Filename &fullpath, const string &magic_number) { read(istream &in, const Filename &fullpath) {
PNMReader *reader = make_reader(&in, false, fullpath);
if (reader == (PNMReader *)NULL) {
clear();
return false;
}
return read(reader);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::read
// Access: Published
// Description: Reads the PFM data using the indicated PNMReader.
//
// The PNMReader is always deleted upon completion,
// whether successful or not.
////////////////////////////////////////////////////////////////////
bool PfmFile::
read(PNMReader *reader) {
clear(); clear();
string identifier = magic_number; if (reader == NULL) {
PNMImageHeader::read_magic_number(&in, identifier, 2);
if (identifier == "pf") {
// In this case, we're probably reading a special-extension
// 4-channel pfm file, and we need a four-byte magic number to
// confirm this and fully identify the file format.
PNMImageHeader::read_magic_number(&in, identifier, 4);
}
if (identifier == "PF") {
_num_channels = 3;
} else if (identifier == "Pf") {
_num_channels = 1;
} else if (identifier == "pf4c") {
_num_channels = 4;
} else {
// Not a PFM file. Maybe it's a more conventional image file that
// we can read into a PFM.
PNMImage pnm;
PNMReader *reader = pnm.make_reader
(&in, false, fullpath, identifier, NULL, false);
if (reader == (PNMReader *)NULL) {
pnmimage_cat.error()
<< "Not a PFM file or known image file type: " << fullpath << "\n";
return false; return false;
} }
if (!reader->is_valid()) {
delete reader;
return false;
}
if (!reader->is_floating_point()) {
// Not a floating-point file. Quietly convert it.
PNMImage pnm;
if (!pnm.read(reader)) { if (!pnm.read(reader)) {
pnmimage_cat.error()
<< "Invalid image file: " << fullpath << "\n";
return false; return false;
} }
return load(pnm); return load(pnm);
} }
int width, height; bool success = reader->read_pfm(*this);
PN_float32 scale; delete reader;
in >> width >> height >> scale; return success;
if (!in) {
pnmimage_cat.error()
<< "Error parsing PFM header: " << fullpath << "\n";
return false;
}
// Skip the last newline/whitespace character before the raw data
// begins.
in.get();
bool little_endian = false;
if (scale < 0) {
scale = -scale;
little_endian = true;
}
if (pfm_force_littleendian) {
little_endian = true;
}
if (pfm_reverse_dimensions) {
int t = width;
width = height;
height = t;
}
_x_size = width;
_y_size = height;
_scale = scale;
// So far, so good. Now read the data.
int size = _x_size * _y_size * _num_channels;
// We allocate a little bit bigger to allow safe overflow: you can
// call get_point3() or get_point4() on the last point of a 1- or
// 3-channel image.
_table.insert(_table.end(), size + 4, (PN_float32)0.0);
in.read((char *)&_table[0], sizeof(PN_float32) * size);
if (in.fail() && !in.eof()) {
return false;
}
// Now we may have to endian-reverse the data.
#ifdef WORDS_BIGENDIAN
bool endian_reversed = little_endian;
#else
bool endian_reversed = !little_endian;
#endif
if (endian_reversed) {
for (int ti = 0; ti < size; ++ti) {
ReversedNumericData nd(&_table[ti], sizeof(PN_float32));
nd.store_value(&_table[ti], sizeof(PN_float32));
}
}
return true;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -335,45 +272,56 @@ write(const Filename &fullpath) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool PfmFile:: bool PfmFile::
write(ostream &out, const Filename &fullpath) { write(ostream &out, const Filename &fullpath) {
nassertr(is_valid(), false); if (!is_valid()) {
switch (_num_channels) {
case 1:
out << "Pf\n";
break;
case 3:
out << "PF\n";
break;
case 4:
out << "pf4c\n";
break;
default:
nassertr(false, false);
}
out << _x_size << " " << _y_size << "\n";
PN_float32 scale = cabs(_scale);
if (scale == 0.0f) {
scale = 1.0f;
}
#ifndef WORDS_BIGENDIAN
// Little-endian computers must write a negative scale to indicate
// the little-endian nature of the output.
scale = -scale;
#endif
out << scale << "\n";
int size = _x_size * _y_size * _num_channels;
out.write((const char *)&_table[0], sizeof(PN_float32) * size);
if (out.fail()) {
return false; return false;
} }
nassertr(sizeof(PN_float32) == 4, false);
return true; PNMWriter *writer = make_writer(fullpath);
if (writer == (PNMWriter *)NULL) {
return false;
}
return write(writer);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::write
// Access: Published
// Description: Writes the PFM data using the indicated PNMWriter.
//
// The PNMWriter is always deleted upon completion,
// whether successful or not.
////////////////////////////////////////////////////////////////////
bool PfmFile::
write(PNMWriter *writer) {
if (writer == NULL) {
return false;
}
if (!is_valid()) {
delete writer;
return false;
}
writer->copy_header_from(*this);
if (!writer->supports_floating_point()) {
// Hmm, it's an integer file type. Convert it from the
// floating-point data we have.
PNMImage pnmimage;
if (!store(pnmimage)) {
delete writer;
return false;
}
writer->copy_header_from(pnmimage);
bool success = writer->write_data(pnmimage.get_array(), pnmimage.get_alpha_array());
delete writer;
return success;
}
bool success = writer->write_pfm(*this);
delete writer;
return success;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1436,6 +1384,17 @@ generate_vis_mesh(MeshFace face) const {
return NodePath(gnode); return NodePath(gnode);
} }
////////////////////////////////////////////////////////////////////
// Function: PfmFile::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
output(ostream &out) const {
out << "floating-point image: " << _x_size << " by " << _y_size << " pixels, "
<< _num_channels << " channels.";
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PfmFile::make_vis_mesh_geom // Function: PfmFile::make_vis_mesh_geom
// Access: Private // Access: Private

View File

@ -16,6 +16,7 @@
#define PFMFILE_H #define PFMFILE_H
#include "pandabase.h" #include "pandabase.h"
#include "pnmImageHeader.h"
#include "luse.h" #include "luse.h"
#include "nodePath.h" #include "nodePath.h"
#include "boundingHexahedron.h" #include "boundingHexahedron.h"
@ -25,6 +26,8 @@
class GeomNode; class GeomNode;
class Lens; class Lens;
class PNMImage; class PNMImage;
class PNMReader;
class PNMWriter;
class GeomVertexWriter; class GeomVertexWriter;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -33,7 +36,7 @@ class GeomVertexWriter;
// numbers, either 3-component or 1-component, or with a // numbers, either 3-component or 1-component, or with a
// special extension, 4-component. // special extension, 4-component.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PNMIMAGE PfmFile { class EXPCL_PANDA_PNMIMAGE PfmFile : public PNMImageHeader {
PUBLISHED: PUBLISHED:
PfmFile(); PfmFile();
PfmFile(const PfmFile &copy); PfmFile(const PfmFile &copy);
@ -43,22 +46,23 @@ PUBLISHED:
void clear(int x_size, int y_size, int num_channels); void clear(int x_size, int y_size, int num_channels);
BLOCKING bool read(const Filename &fullpath); BLOCKING bool read(const Filename &fullpath);
BLOCKING bool read(istream &in, const Filename &fullpath = Filename(), BLOCKING bool read(istream &in, const Filename &fullpath = Filename());
const string &magic_number = string()); BLOCKING bool read(PNMReader *reader);
BLOCKING bool write(const Filename &fullpath); BLOCKING bool write(const Filename &fullpath);
BLOCKING bool write(ostream &out, const Filename &fullpath = Filename()); BLOCKING bool write(ostream &out, const Filename &fullpath = Filename());
BLOCKING bool write(PNMWriter *writer);
BLOCKING bool load(const PNMImage &pnmimage); BLOCKING bool load(const PNMImage &pnmimage);
BLOCKING bool store(PNMImage &pnmimage) const; BLOCKING bool store(PNMImage &pnmimage) const;
INLINE bool is_valid() const; INLINE bool is_valid() const;
INLINE int get_x_size() const;
INLINE int get_y_size() const;
INLINE PN_float32 get_scale() const; INLINE PN_float32 get_scale() const;
INLINE int get_num_channels() const; INLINE void set_scale(PN_float32 scale);
INLINE bool has_point(int x, int y) const; INLINE bool has_point(int x, int y) const;
INLINE PN_float32 get_component(int x, int y, int c) const;
INLINE void set_component(int x, int y, int c, PN_float32 value);
INLINE PN_float32 get_point1(int x, int y) const; INLINE PN_float32 get_point1(int x, int y) const;
INLINE void set_point1(int x, int y, PN_float32 point); INLINE void set_point1(int x, int y, PN_float32 point);
INLINE const LPoint3f &get_point(int x, int y) const; INLINE const LPoint3f &get_point(int x, int y) const;
@ -131,6 +135,12 @@ PUBLISHED:
}; };
BLOCKING NodePath generate_vis_mesh(MeshFace face = MF_front) const; BLOCKING NodePath generate_vis_mesh(MeshFace face = MF_front) const;
void output(ostream &out) const;
public:
INLINE const pvector<PN_float32> &get_table() const;
INLINE void swap_table(pvector<PN_float32> &table);
private: private:
void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const; void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
@ -196,10 +206,7 @@ private:
typedef pvector<PN_float32> Table; typedef pvector<PN_float32> Table;
Table _table; Table _table;
int _x_size;
int _y_size;
PN_float32 _scale; PN_float32 _scale;
int _num_channels;
bool _has_no_data_value; bool _has_no_data_value;
LPoint4f _no_data_value; LPoint4f _no_data_value;

View File

@ -16,6 +16,7 @@
#include "pnmReader.h" #include "pnmReader.h"
#include "pnmWriter.h" #include "pnmWriter.h"
#include "pnmBrush.h" #include "pnmBrush.h"
#include "pfmFile.h"
#include "config_pnmimage.h" #include "config_pnmimage.h"
#include "perlinNoise2.h" #include "perlinNoise2.h"
#include "stackedPerlinNoise2.h" #include "stackedPerlinNoise2.h"
@ -307,6 +308,17 @@ read(PNMReader *reader) {
copy_header_from(*reader); copy_header_from(*reader);
if (reader->is_floating_point()) {
// Hmm, it's a floating-point file. Quietly convert it to integer.
PfmFile pfm;
if (!reader->read_pfm(pfm)) {
delete reader;
return false;
}
delete reader;
return pfm.store(*this);
}
// We reassign y_size after reading because we might have read a // We reassign y_size after reading because we might have read a
// truncated file. // truncated file.
_y_size = reader->read_data(_array, _alpha); _y_size = reader->read_data(_array, _alpha);
@ -400,6 +412,20 @@ write(PNMWriter *writer) const {
} }
writer->copy_header_from(*this); writer->copy_header_from(*this);
if (!writer->supports_integer()) {
// Hmm, it's only a floating-point file type. Convert it from the
// integer data we have.
PfmFile pfm;
if (!pfm.load(*this)) {
delete writer;
return false;
}
bool success = writer->write_pfm(pfm);
delete writer;
return success;
}
if (is_grayscale() && !writer->supports_grayscale()) { if (is_grayscale() && !writer->supports_grayscale()) {
// Copy the gray values to all channels to help out the writer. // Copy the gray values to all channels to help out the writer.
for (int y = 0; y < get_y_size(); y++) { for (int y = 0; y < get_y_size(); y++) {

View File

@ -70,6 +70,30 @@ prepare_read() {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: PNMReader::is_floating_point
// Access: Public, Virtual
// Description: 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 PNMReader::
is_floating_point() {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PNMReader::read_pfm
// Access: Public, Virtual
// Description: Reads floating-point data directly into the indicated
// PfmFile. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PNMReader::
read_pfm(PfmFile &pfm) {
return false;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PNMReader::read_data // Function: PNMReader::read_data
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -18,7 +18,7 @@
#include "pandabase.h" #include "pandabase.h"
#include "pnmImageHeader.h" #include "pnmImageHeader.h"
class PfmFile;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : PNMReader // Class : PNMReader
@ -39,6 +39,8 @@ public:
INLINE PNMFileType *get_type() const; INLINE PNMFileType *get_type() const;
virtual void prepare_read(); virtual void prepare_read();
virtual bool is_floating_point();
virtual bool read_pfm(PfmFile &pfm);
virtual int read_data(xel *array, xelval *alpha); virtual int read_data(xel *array, xelval *alpha);
virtual bool supports_read_row() const; virtual bool supports_read_row() const;
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size); virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);

View File

@ -28,6 +28,43 @@ PNMWriter::
_file = (ostream *)NULL; _file = (ostream *)NULL;
} }
////////////////////////////////////////////////////////////////////
// Function: PNMWriter::supports_floating_point
// Access: Public, Virtual
// Description: 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 PNMWriter::
supports_floating_point() {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PNMWriter::supports_integer
// Access: Public, Virtual
// Description: 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 PNMWriter::
supports_integer() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PNMWriter::write_pfm
// Access: Public, Virtual
// Description: Writes floating-point data from the indicated
// PfmFile. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PNMWriter::
write_pfm(const PfmFile &pfm) {
return false;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PNMWriter::write_data // Function: PNMWriter::write_data
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -18,6 +18,7 @@
#include "pandabase.h" #include "pandabase.h"
#include "pnmImageHeader.h" #include "pnmImageHeader.h"
class PfmFile;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : PNMWriter // Class : PNMWriter
@ -48,6 +49,10 @@ public:
INLINE void copy_header_from(const PNMImageHeader &header); INLINE void copy_header_from(const PNMImageHeader &header);
virtual bool supports_floating_point();
virtual bool supports_integer();
virtual bool write_pfm(const PfmFile &pfm);
virtual int write_data(xel *array, xelval *alpha); virtual int write_data(xel *array, xelval *alpha);
virtual bool supports_write_row() const; virtual bool supports_write_row() const;
virtual bool supports_grayscale() const; virtual bool supports_grayscale() const;

View File

@ -15,6 +15,7 @@
pnmFileTypeIMG.h \ pnmFileTypeIMG.h \
pnmFileTypePNG.h \ pnmFileTypePNG.h \
pnmFileTypePNM.h \ pnmFileTypePNM.h \
pnmFileTypePfm.h \
pnmFileTypeSGI.h pnmFileTypeSoftImage.h \ pnmFileTypeSGI.h pnmFileTypeSoftImage.h \
pnmFileTypeTGA.h \ pnmFileTypeTGA.h \
pnmFileTypeTIFF.h \ pnmFileTypeTIFF.h \
@ -28,6 +29,7 @@
pnmFileTypeJPG.cxx pnmFileTypeJPGReader.cxx pnmFileTypeJPGWriter.cxx \ pnmFileTypeJPG.cxx pnmFileTypeJPGReader.cxx pnmFileTypeJPGWriter.cxx \
pnmFileTypePNG.cxx \ pnmFileTypePNG.cxx \
pnmFileTypePNM.cxx \ pnmFileTypePNM.cxx \
pnmFileTypePfm.cxx \
pnmFileTypeSGI.cxx \ pnmFileTypeSGI.cxx \
pnmFileTypeSGIReader.cxx pnmFileTypeSGIWriter.cxx \ pnmFileTypeSGIReader.cxx pnmFileTypeSGIWriter.cxx \
pnmFileTypeSoftImage.cxx \ pnmFileTypeSoftImage.cxx \

View File

@ -21,6 +21,7 @@
#include "pnmFileTypeJPG.h" #include "pnmFileTypeJPG.h"
#include "pnmFileTypePNG.h" #include "pnmFileTypePNG.h"
#include "pnmFileTypePNM.h" #include "pnmFileTypePNM.h"
#include "pnmFileTypePfm.h"
#include "pnmFileTypeTIFF.h" #include "pnmFileTypeTIFF.h"
#include "sgi.h" #include "sgi.h"
@ -216,6 +217,10 @@ init_libpnmimagetypes() {
tr->register_type(new PNMFileTypePNM); tr->register_type(new PNMFileTypePNM);
#endif #endif
PNMFileTypePfm::init_type();
PNMFileTypePfm::register_with_read_factory();
tr->register_type(new PNMFileTypePfm);
#ifdef HAVE_JPEG #ifdef HAVE_JPEG
PNMFileTypeJPG::init_type(); PNMFileTypeJPG::init_type();
PNMFileTypeJPG::register_with_read_factory(); PNMFileTypeJPG::register_with_read_factory();

View File

@ -1,6 +1,7 @@
#include "pnmFileTypePNG.cxx" #include "pnmFileTypePNG.cxx"
#include "pnmFileTypeTIFF.cxx" #include "pnmFileTypeTIFF.cxx"
#include "pnmFileTypePNM.cxx" #include "pnmFileTypePNM.cxx"
#include "pnmFileTypePfm.cxx"
#include "pnmFileTypeSGI.cxx" #include "pnmFileTypeSGI.cxx"
#include "pnmFileTypeSGIReader.cxx" #include "pnmFileTypeSGIReader.cxx"
#include "pnmFileTypeSGIWriter.cxx" #include "pnmFileTypeSGIWriter.cxx"

View File

@ -13,6 +13,7 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
#include "pnmFileTypePfm.h" #include "pnmFileTypePfm.h"
#include "pfmFile.h"
#include "config_pnmimage.h" #include "config_pnmimage.h"
#include "pnmFileTypeRegistry.h" #include "pnmFileTypeRegistry.h"
@ -134,45 +135,115 @@ PNMFileTypePfm::Reader::
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) : Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
PNMReader(type, file, owns_file) PNMReader(type, file, owns_file)
{ {
PfmFile pfm; read_magic_number(_file, magic_number, 2);
if (!pfm.read(*file, Filename(), magic_number)) {
if (magic_number == "pf") {
// In this case, we're probably reading a special-extension
// 4-channel pfm file, and we need a four-byte magic number to
// confirm this and fully identify the file format.
read_magic_number(_file, magic_number, 4);
}
if (magic_number == "PF") {
_num_channels = 3;
} else if (magic_number == "Pf") {
_num_channels = 1;
} else if (magic_number == "pf4c") {
// Special DRZ extension.
_num_channels = 4;
} else {
pnmimage_cat.debug()
<< "Not a PFM file\n";
_is_valid = false; _is_valid = false;
return; return;
} }
pfm.store(_image); (*_file) >> _x_size >> _y_size >> _scale;
PNMImageHeader::operator = (_image); if (!(*_file)) {
pnmimage_cat.debug()
<< "Error parsing PFM header\n";
_is_valid = false;
return;
}
// Skip the last newline/whitespace character before the raw data
// begins.
(*_file).get();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PNMFileTypePfm::Reader::read_data // Function: PNMFileTypePfm::Reader::is_floating_point
// Access: Public, Virtual // Access: Public, Virtual
// Description: Reads in an entire image all at once, storing it in // Description: Returns true if this PNMFileType represents a
// the pre-allocated _x_size * _y_size array and alpha // floating-point image type, false if it is a normal,
// pointers. (If the image type has no alpha channel, // integer type. If this returns true, read_pfm() is
// alpha is ignored.) Returns the number of rows // implemented instead of read_data().
// correctly read.
//
// Derived classes need not override this if they
// instead provide supports_read_row() and read_row(),
// below.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
int PNMFileTypePfm::Reader:: bool PNMFileTypePfm::Reader::
read_data(xel *array, xelval *alpha) { is_floating_point() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PNMFileTypePfm::Reader::read_pfm
// Access: Public, Virtual
// Description: Reads floating-point data directly into the indicated
// PfmFile. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PNMFileTypePfm::Reader::
read_pfm(PfmFile &pfm) {
if (!is_valid()) { if (!is_valid()) {
return 0; return false;
} }
nassertr(_image.get_x_size() == get_x_size() && bool little_endian = false;
_image.get_y_size() == get_y_size(), 0); if (_scale < 0) {
_scale = -_scale;
memcpy(array, _image.get_array(), get_x_size() * get_y_size() * sizeof(xel)); little_endian = true;
}
if (has_alpha()) { if (pfm_force_littleendian) {
memcpy(alpha, _image.get_alpha_array(), get_x_size() * get_y_size() * sizeof(xelval)); little_endian = true;
}
if (pfm_reverse_dimensions) {
int t = _x_size;
_x_size = _y_size;
_y_size = t;
} }
return get_y_size(); pfm.clear(_x_size, _y_size, _num_channels);
pfm.set_scale(_scale);
// So far, so good. Now read the data.
int size = _x_size * _y_size * _num_channels;
pvector<PN_float32> table;
pfm.swap_table(table);
(*_file).read((char *)&table[0], sizeof(PN_float32) * size);
if ((*_file).fail() && !(*_file).eof()) {
pfm.clear();
return false;
}
// Now we may have to endian-reverse the data.
#ifdef WORDS_BIGENDIAN
bool endian_reversed = little_endian;
#else
bool endian_reversed = !little_endian;
#endif
if (endian_reversed) {
for (int ti = 0; ti < size; ++ti) {
ReversedNumericData nd(&table[ti], sizeof(PN_float32));
nd.store_value(&table[ti], sizeof(PN_float32));
}
}
pfm.swap_table(table);
return true;
} }
@ -188,52 +259,79 @@ Writer(PNMFileType *type, ostream *file, bool owns_file) :
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PNMFileTypePfm::write_data // Function: PNMFileTypePfm::Writer::supports_floating_point
// Access: Public, Virtual // Access: Public, Virtual
// Description: Writes out an entire image all at once, including the // Description: Returns true if this PNMFileType can accept a
// header, based on the image data stored in the given // floating-point image type, false if it can only
// _x_size * _y_size array and alpha pointers. (If the // accept a normal, integer type. If this returns true,
// image type has no alpha channel, alpha is ignored.) // write_pfm() is implemented.
// 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 PNMFileTypePfm::Writer:: bool PNMFileTypePfm::Writer::
write_data(xel *array, xelval *alpha) { supports_floating_point() {
if (_x_size <= 0 || _y_size <= 0) { return true;
return 0; }
}
PNMImage image; ////////////////////////////////////////////////////////////////////
image.copy_header_from(*this); // Function: PNMFileTypePfm::Writer::supports_integer
nassertr(image.get_x_size() == get_x_size() && // Access: Public, Virtual
image.get_y_size() == get_y_size(), 0); // Description: Returns true if this PNMFileType can accept an
memcpy(image.get_array(), array, get_x_size() * get_y_size() * sizeof(xel)); // integer image type, false if it can only
if (has_alpha()) { // accept a floating-point type. If this returns true,
memcpy(image.get_alpha_array(), alpha, get_x_size() * get_y_size() * sizeof(xelval)); // write_data() or write_row() is implemented.
} ////////////////////////////////////////////////////////////////////
bool PNMFileTypePfm::Writer::
supports_integer() {
return false;
}
PfmFile pfm; ////////////////////////////////////////////////////////////////////
if (!pfm.load(image)) { // Function: PNMFileTypePfm::Writer::write_pfm
return 0; // Access: Public, Virtual
} // Description: Writes floating-point data from the indicated
// PfmFile. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PNMFileTypePfm::Writer::
write_pfm(const PfmFile &pfm) {
nassertr(pfm.is_valid(), false);
if (!pfm.write(*_file)) { switch (pfm.get_num_channels()) {
return 0; case 1:
} (*_file) << "Pf\n";
break;
return get_y_size(); case 3:
(*_file) << "PF\n";
break;
case 4:
(*_file) << "pf4c\n";
break;
default:
nassertr(false, false);
}
(*_file) << pfm.get_x_size() << " " << pfm.get_y_size() << "\n";
PN_float32 scale = cabs(pfm.get_scale());
if (scale == 0.0f) {
scale = 1.0f;
}
#ifndef WORDS_BIGENDIAN
// Little-endian computers must write a negative scale to indicate
// the little-endian nature of the output.
scale = -scale;
#endif
(*_file) << scale << "\n";
int size = pfm.get_x_size() * pfm.get_y_size() * pfm.get_num_channels();
const pvector<PN_float32> &table = pfm.get_table();
(*_file).write((const char *)&table[0], sizeof(PN_float32) * size);
if ((*_file).fail()) {
return false;
}
nassertr(sizeof(PN_float32) == 4, false);
return true;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -49,17 +49,20 @@ public:
public: public:
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number); Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number);
virtual int read_data(xel *array, xelval *alpha); virtual bool is_floating_point();
virtual bool read_pfm(PfmFile &pfm);
private: private:
PNMImage _image; PN_float32 _scale;
}; };
class Writer : public PNMWriter { class Writer : public PNMWriter {
public: public:
Writer(PNMFileType *type, ostream *file, bool owns_file); Writer(PNMFileType *type, ostream *file, bool owns_file);
virtual int write_data(xel *array, xelval *alpha); virtual bool supports_floating_point();
virtual bool supports_integer();
virtual bool write_pfm(const PfmFile &pfm);
}; };

View File

@ -46,6 +46,8 @@ PUBLISHED:
TF_allow_1d = 0x0010, // If texture is Nx1, make a 1-d texture TF_allow_1d = 0x0010, // If texture is Nx1, make a 1-d texture
TF_generate_mipmaps = 0x0020, // Consider generating mipmaps TF_generate_mipmaps = 0x0020, // Consider generating mipmaps
TF_multiview = 0x0040, // Load a multiview texture in pages TF_multiview = 0x0040, // Load a multiview texture in pages
TF_integer = 0x0080, // Load as an integer (RGB) texture
TF_float = 0x0100, // Load as a floating-point (depth) texture
}; };
LoaderOptions(int flags = LF_search | LF_report_errors); LoaderOptions(int flags = LF_search | LF_report_errors);