mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
integrate PfmFile with PNMImage, Texture
This commit is contained in:
parent
5bd76de269
commit
7ba693137c
@ -28,6 +28,8 @@
|
||||
#include "string_utils.h"
|
||||
#include "preparedGraphicsObjects.h"
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pfmFile.h"
|
||||
#include "virtualFileSystem.h"
|
||||
#include "datagramInputFile.h"
|
||||
#include "datagramOutputFile.h"
|
||||
@ -2913,12 +2915,40 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
|
||||
}
|
||||
|
||||
PNMImage image;
|
||||
if (header_only || textures_header_only) {
|
||||
if (!image.read_header(fullpath)) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::read() - couldn't read: " << fullpath << endl;
|
||||
return false;
|
||||
PfmFile pfm;
|
||||
PNMReader *image_reader = image.make_reader(fullpath, NULL, false);
|
||||
if (image_reader == NULL) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::read() - couldn't read: " << fullpath << endl;
|
||||
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 y_size = image.get_y_size();
|
||||
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();
|
||||
}
|
||||
|
||||
image = PNMImage(x_size, y_size, image.get_num_channels(),
|
||||
image.get_maxval(), image.get_type());
|
||||
image.fill(0.2, 0.3, 1.0);
|
||||
if (image.has_alpha()) {
|
||||
image.alpha_fill(1.0);
|
||||
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.get_maxval(), image.get_type());
|
||||
image.fill(0.2, 0.3, 1.0);
|
||||
if (image.has_alpha()) {
|
||||
image.alpha_fill(1.0);
|
||||
}
|
||||
}
|
||||
delete image_reader;
|
||||
|
||||
} 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) {
|
||||
cdata->_orig_file_x_size = image.get_x_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";
|
||||
}
|
||||
|
||||
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()
|
||||
<< "Texture::read() - couldn't read: " << fullpath << endl;
|
||||
return false;
|
||||
@ -2980,16 +3016,19 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
|
||||
|
||||
PNMImage alpha_image;
|
||||
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) {
|
||||
record->add_dependent_file(alpha_fullpath);
|
||||
}
|
||||
|
||||
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 y_size = image.get_y_size();
|
||||
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()) {
|
||||
alpha_image.alpha_fill(1.0);
|
||||
}
|
||||
delete alpha_image_reader;
|
||||
|
||||
} 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() ||
|
||||
image.get_y_size() != alpha_image.get_y_size()) {
|
||||
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());
|
||||
}
|
||||
|
||||
if (!alpha_image.read(alpha_fullpath, NULL, true)) {
|
||||
if (!alpha_image.read(alpha_image_reader)) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
|
||||
return false;
|
||||
@ -3106,28 +3140,34 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
|
||||
}
|
||||
}
|
||||
|
||||
// Now see if we want to pad the image within a larger power-of-2
|
||||
// image.
|
||||
int pad_x_size = 0;
|
||||
int pad_y_size = 0;
|
||||
if (do_get_auto_texture_scale(cdata) == ATS_pad) {
|
||||
int new_x_size = image.get_x_size();
|
||||
int new_y_size = image.get_y_size();
|
||||
if (do_adjust_this_size(cdata, new_x_size, new_y_size, fullpath.get_basename(), true)) {
|
||||
pad_x_size = new_x_size - image.get_x_size();
|
||||
pad_y_size = new_y_size - image.get_y_size();
|
||||
PNMImage new_image(new_x_size, new_y_size, image.get_num_channels(),
|
||||
image.get_maxval());
|
||||
new_image.copy_sub_image(image, 0, new_y_size - image.get_y_size());
|
||||
image.take_from(new_image);
|
||||
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
|
||||
// image.
|
||||
int pad_x_size = 0;
|
||||
int pad_y_size = 0;
|
||||
if (do_get_auto_texture_scale(cdata) == ATS_pad) {
|
||||
int new_x_size = image.get_x_size();
|
||||
int new_y_size = image.get_y_size();
|
||||
if (do_adjust_this_size(cdata, new_x_size, new_y_size, fullpath.get_basename(), true)) {
|
||||
pad_x_size = new_x_size - image.get_x_size();
|
||||
pad_y_size = new_y_size - image.get_y_size();
|
||||
PNMImage new_image(new_x_size, new_y_size, image.get_num_channels(),
|
||||
image.get_maxval());
|
||||
new_image.copy_sub_image(image, 0, new_y_size - image.get_y_size());
|
||||
image.take_from(new_image);
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_load_one(cdata, image, fullpath.get_basename(), z, n, options)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_load_one(cdata, image, fullpath.get_basename(), z, n, options)) {
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3205,6 +3245,74 @@ do_load_one(CData *cdata, const PNMImage &pnmimage, const string &name, int z, i
|
||||
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
|
||||
// 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);
|
||||
|
||||
PNMImage pnmimage;
|
||||
if (!do_store_one(cdata, pnmimage, z, n)) {
|
||||
return 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;
|
||||
if (!do_store_one(cdata, pnmimage, z, n)) {
|
||||
return false;
|
||||
}
|
||||
success = pnmimage.write(fullpath);
|
||||
}
|
||||
|
||||
if (!pnmimage.write(fullpath)) {
|
||||
if (!success) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::write() - couldn't write: " << fullpath << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
// Access: Private
|
||||
@ -4497,28 +4644,32 @@ bool Texture::
|
||||
do_reconsider_image_properties(CData *cdata, int x_size, int y_size, int num_components,
|
||||
Texture::ComponentType component_type, int z,
|
||||
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.
|
||||
// But only do this the first time the file is loaded, or if the
|
||||
// number of channels in the image changes on subsequent loads.
|
||||
|
||||
switch (num_components) {
|
||||
case 1:
|
||||
cdata->_format = F_luminance;
|
||||
if (component_type == T_float) {
|
||||
cdata->_format = F_depth_component;
|
||||
} else {
|
||||
cdata->_format = F_luminance;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 2:
|
||||
cdata->_format = F_luminance_alpha;
|
||||
break;
|
||||
|
||||
|
||||
case 3:
|
||||
cdata->_format = F_rgb;
|
||||
break;
|
||||
|
||||
|
||||
case 4:
|
||||
cdata->_format = F_rgba;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// Eh?
|
||||
nassertr(false, false);
|
||||
@ -5711,6 +5862,35 @@ convert_from_pnmimage(PTA_uchar &image, size_t page_size, int z,
|
||||
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
|
||||
// Access: Private, Static
|
||||
@ -5769,6 +5949,36 @@ convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
|
||||
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
|
||||
// Access: Private, Static
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "pipelineCycler.h"
|
||||
|
||||
class PNMImage;
|
||||
class PfmFile;
|
||||
class TextureContext;
|
||||
class FactoryParams;
|
||||
class PreparedGraphicsObjects;
|
||||
@ -541,6 +542,9 @@ protected:
|
||||
virtual bool do_load_one(CData *cdata,
|
||||
const PNMImage &pnmimage, const string &name,
|
||||
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(CData *cdata, istream &in, const string &filename);
|
||||
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 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, PfmFile &pfm, int z, int n);
|
||||
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;
|
||||
|
||||
@ -656,10 +661,17 @@ private:
|
||||
static void convert_from_pnmimage(PTA_uchar &image, size_t page_size,
|
||||
int z, const PNMImage &pnmimage,
|
||||
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,
|
||||
int num_components, int component_width,
|
||||
CPTA_uchar image, size_t page_size,
|
||||
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,
|
||||
int n, istream &in);
|
||||
static PTA_uchar read_dds_level_rgb8(Texture *tex, CData *cdata, const DDSHeader &header,
|
||||
|
@ -12,7 +12,6 @@
|
||||
#define SOURCES \
|
||||
config_pnmimage.h \
|
||||
pfmFile.I pfmFile.h \
|
||||
pnmFileTypePfm.h \
|
||||
pnmbitio.h \
|
||||
pnmBrush.h pnmBrush.I \
|
||||
pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \
|
||||
@ -25,7 +24,6 @@
|
||||
#define INCLUDED_SOURCES \
|
||||
config_pnmimage.cxx \
|
||||
pfmFile.cxx \
|
||||
pnmFileTypePfm.cxx \
|
||||
pnm-image-filter.cxx \
|
||||
pnmbitio.cxx \
|
||||
pnmBrush.cxx \
|
||||
@ -38,7 +36,6 @@
|
||||
#define INSTALL_HEADERS \
|
||||
config_pnmimage.h \
|
||||
pfmFile.I pfmFile.h \
|
||||
pnmFileTypePfm.h \
|
||||
pnmBrush.h pnmBrush.I \
|
||||
pnmFileType.h pnmFileTypeRegistry.h pnmImage.I \
|
||||
pnmImage.h pnmImageHeader.I pnmImageHeader.h \
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#include "config_pnmimage.h"
|
||||
#include "pnmFileType.h"
|
||||
#include "pnmFileTypePfm.h"
|
||||
#include "pnmFileTypeRegistry.h"
|
||||
|
||||
#include "dconfig.h"
|
||||
@ -66,9 +65,4 @@ init_libpnmimage() {
|
||||
initialized = true;
|
||||
|
||||
PNMFileType::init_type();
|
||||
|
||||
PNMFileTypeRegistry *tr = PNMFileTypeRegistry::get_global_ptr();
|
||||
PNMFileTypePfm::init_type();
|
||||
PNMFileTypePfm::register_with_read_factory();
|
||||
tr->register_type(new PNMFileTypePfm);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "config_pnmimage.cxx"
|
||||
#include "pfmFile.cxx"
|
||||
#include "pnmFileTypePfm.cxx"
|
||||
#include "pnm-image-filter.cxx"
|
||||
#include "pnmbitio.cxx"
|
||||
#include "pnmBrush.cxx"
|
||||
|
@ -23,26 +23,6 @@ is_valid() const {
|
||||
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
|
||||
// Access: Published
|
||||
@ -55,18 +35,14 @@ get_scale() const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PfmFile::get_num_channels
|
||||
// Function: PfmFile::set_scale
|
||||
// Access: Published
|
||||
// Description: A pfm file can be either 1-channel
|
||||
// (get_num_channels() == 1) or 3-channel
|
||||
// (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.
|
||||
// Description: The "scale" is reported in the pfm header and is
|
||||
// probably meaningless.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int PfmFile::
|
||||
get_num_channels() const {
|
||||
return _num_channels;
|
||||
INLINE void PfmFile::
|
||||
set_scale(PN_float32 scale) {
|
||||
_scale = scale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -82,6 +58,34 @@ has_point(int x, int y) const {
|
||||
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
|
||||
// Access: Published
|
||||
@ -90,8 +94,8 @@ has_point(int x, int y) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_float32 PfmFile::
|
||||
get_point1(int x, int y) const {
|
||||
nassertr(x >= 0 && x < _x_size, 0.0);
|
||||
nassertr(y >= 0 && y < _y_size, 0.0);
|
||||
nassertr(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size, 0.0);
|
||||
return _table[(y * _x_size + x) * _num_channels];
|
||||
}
|
||||
|
||||
@ -104,8 +108,8 @@ get_point1(int x, int y) const {
|
||||
INLINE void PfmFile::
|
||||
set_point1(int x, int y, PN_float32 point) {
|
||||
nassertv(!cnan(point));
|
||||
nassertv(x >= 0 && x < _x_size);
|
||||
nassertv(y >= 0 && y < _y_size);
|
||||
nassertv(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size);
|
||||
_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::
|
||||
get_point(int x, int y) const {
|
||||
nassertr(x >= 0 && x < _x_size, LPoint3f::zero());
|
||||
nassertr(y >= 0 && y < _y_size, LPoint3f::zero());
|
||||
nassertr(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size, LPoint3f::zero());
|
||||
return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels];
|
||||
}
|
||||
|
||||
@ -133,8 +137,8 @@ get_point(int x, int y) const {
|
||||
INLINE void PfmFile::
|
||||
set_point(int x, int y, const LVecBase3f &point) {
|
||||
nassertv(!point.is_nan());
|
||||
nassertv(x >= 0 && x < _x_size);
|
||||
nassertv(y >= 0 && y < _y_size);
|
||||
nassertv(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size);
|
||||
switch (_num_channels) {
|
||||
case 1:
|
||||
_table[(y * _x_size + x)] = point[0];
|
||||
@ -169,8 +173,8 @@ INLINE LPoint3f &PfmFile::
|
||||
modify_point(int x, int y) {
|
||||
#ifndef NDEBUG
|
||||
static LPoint3f dummy_value = LPoint3f::zero();
|
||||
nassertr(x >= 0 && x < _x_size, dummy_value);
|
||||
nassertr(y >= 0 && y < _y_size, dummy_value);
|
||||
nassertr(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size, dummy_value);
|
||||
#endif
|
||||
|
||||
return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels];
|
||||
@ -185,8 +189,8 @@ modify_point(int x, int y) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LPoint4f &PfmFile::
|
||||
get_point4(int x, int y) const {
|
||||
nassertr(x >= 0 && x < _x_size, LPoint4f::zero());
|
||||
nassertr(y >= 0 && y < _y_size, LPoint4f::zero());
|
||||
nassertr(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size, LPoint4f::zero());
|
||||
return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels];
|
||||
}
|
||||
|
||||
@ -200,8 +204,8 @@ get_point4(int x, int y) const {
|
||||
INLINE void PfmFile::
|
||||
set_point4(int x, int y, const LVecBase4f &point) {
|
||||
nassertv(!point.is_nan());
|
||||
nassertv(x >= 0 && x < _x_size);
|
||||
nassertv(y >= 0 && y < _y_size);
|
||||
nassertv(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size);
|
||||
switch (_num_channels) {
|
||||
case 1:
|
||||
_table[(y * _x_size + x)] = point[0];
|
||||
@ -239,8 +243,8 @@ INLINE LPoint4f &PfmFile::
|
||||
modify_point4(int x, int y) {
|
||||
#ifndef NDEBUG
|
||||
static LPoint4f dummy_value = LPoint4f::zero();
|
||||
nassertr(x >= 0 && x < _x_size, dummy_value);
|
||||
nassertr(y >= 0 && y < _y_size, dummy_value);
|
||||
nassertr(x >= 0 && x < _x_size &&
|
||||
y >= 0 && y < _y_size, dummy_value);
|
||||
#endif
|
||||
|
||||
return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels];
|
||||
@ -517,3 +521,30 @@ INLINE bool PfmFile::
|
||||
get_vis_2d() const {
|
||||
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);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "geomTriangles.h"
|
||||
#include "geomVertexWriter.h"
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "string_utils.h"
|
||||
#include "lens.h"
|
||||
@ -54,11 +55,9 @@ PfmFile() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PfmFile::
|
||||
PfmFile(const PfmFile ©) :
|
||||
PNMImageHeader(copy),
|
||||
_table(copy._table),
|
||||
_x_size(copy._x_size),
|
||||
_y_size(copy._y_size),
|
||||
_scale(copy._scale),
|
||||
_num_channels(copy._num_channels),
|
||||
_has_no_data_value(copy._has_no_data_value),
|
||||
_no_data_value(copy._no_data_value),
|
||||
_has_point(copy._has_point),
|
||||
@ -74,11 +73,9 @@ PfmFile(const PfmFile ©) :
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PfmFile::
|
||||
operator = (const PfmFile ©) {
|
||||
PNMImageHeader::operator = (copy);
|
||||
_table = copy._table;
|
||||
_x_size = copy._x_size;
|
||||
_y_size = copy._y_size;
|
||||
_scale = copy._scale;
|
||||
_num_channels = copy._num_channels;
|
||||
_has_no_data_value = copy._has_no_data_value;
|
||||
_no_data_value = copy._no_data_value;
|
||||
_has_point = copy._has_point;
|
||||
@ -108,7 +105,6 @@ clear() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PfmFile::
|
||||
clear(int x_size, int y_size, int num_channels) {
|
||||
nassertv(num_channels == 1 || num_channels == 3);
|
||||
nassertv(x_size >= 0 && y_size >= 0);
|
||||
_x_size = x_size;
|
||||
_y_size = y_size;
|
||||
@ -172,108 +168,49 @@ read(const Filename &fullpath) {
|
||||
// to a floating-point type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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();
|
||||
|
||||
string identifier = magic_number;
|
||||
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 (reader == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (identifier == "PF") {
|
||||
_num_channels = 3;
|
||||
if (!reader->is_valid()) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
} 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.
|
||||
if (!reader->is_floating_point()) {
|
||||
// Not a floating-point file. Quietly convert it.
|
||||
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;
|
||||
}
|
||||
|
||||
if (!pnm.read(reader)) {
|
||||
pnmimage_cat.error()
|
||||
<< "Invalid image file: " << fullpath << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return load(pnm);
|
||||
}
|
||||
|
||||
int width, height;
|
||||
PN_float32 scale;
|
||||
in >> width >> height >> scale;
|
||||
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;
|
||||
bool success = reader->read_pfm(*this);
|
||||
delete reader;
|
||||
return success;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -335,45 +272,56 @@ write(const Filename &fullpath) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PfmFile::
|
||||
write(ostream &out, const Filename &fullpath) {
|
||||
nassertr(is_valid(), false);
|
||||
|
||||
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()) {
|
||||
if (!is_valid()) {
|
||||
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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
// Access: Private
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define PFMFILE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "pnmImageHeader.h"
|
||||
#include "luse.h"
|
||||
#include "nodePath.h"
|
||||
#include "boundingHexahedron.h"
|
||||
@ -25,6 +26,8 @@
|
||||
class GeomNode;
|
||||
class Lens;
|
||||
class PNMImage;
|
||||
class PNMReader;
|
||||
class PNMWriter;
|
||||
class GeomVertexWriter;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -33,7 +36,7 @@ class GeomVertexWriter;
|
||||
// numbers, either 3-component or 1-component, or with a
|
||||
// special extension, 4-component.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_PNMIMAGE PfmFile {
|
||||
class EXPCL_PANDA_PNMIMAGE PfmFile : public PNMImageHeader {
|
||||
PUBLISHED:
|
||||
PfmFile();
|
||||
PfmFile(const PfmFile ©);
|
||||
@ -43,22 +46,23 @@ PUBLISHED:
|
||||
void clear(int x_size, int y_size, int num_channels);
|
||||
|
||||
BLOCKING bool read(const Filename &fullpath);
|
||||
BLOCKING bool read(istream &in, const Filename &fullpath = Filename(),
|
||||
const string &magic_number = string());
|
||||
BLOCKING bool read(istream &in, const Filename &fullpath = Filename());
|
||||
BLOCKING bool read(PNMReader *reader);
|
||||
BLOCKING bool write(const Filename &fullpath);
|
||||
BLOCKING bool write(ostream &out, const Filename &fullpath = Filename());
|
||||
BLOCKING bool write(PNMWriter *writer);
|
||||
|
||||
BLOCKING bool load(const PNMImage &pnmimage);
|
||||
BLOCKING bool store(PNMImage &pnmimage) 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 int get_num_channels() const;
|
||||
INLINE void set_scale(PN_float32 scale);
|
||||
|
||||
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 void set_point1(int x, int y, PN_float32 point);
|
||||
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;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
public:
|
||||
INLINE const pvector<PN_float32> &get_table() const;
|
||||
INLINE void swap_table(pvector<PN_float32> &table);
|
||||
|
||||
private:
|
||||
void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
|
||||
|
||||
@ -196,10 +206,7 @@ private:
|
||||
typedef pvector<PN_float32> Table;
|
||||
Table _table;
|
||||
|
||||
int _x_size;
|
||||
int _y_size;
|
||||
PN_float32 _scale;
|
||||
int _num_channels;
|
||||
|
||||
bool _has_no_data_value;
|
||||
LPoint4f _no_data_value;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "pnmReader.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmBrush.h"
|
||||
#include "pfmFile.h"
|
||||
#include "config_pnmimage.h"
|
||||
#include "perlinNoise2.h"
|
||||
#include "stackedPerlinNoise2.h"
|
||||
@ -307,6 +308,17 @@ read(PNMReader *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
|
||||
// truncated file.
|
||||
_y_size = reader->read_data(_array, _alpha);
|
||||
@ -400,6 +412,20 @@ write(PNMWriter *writer) const {
|
||||
}
|
||||
|
||||
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()) {
|
||||
// Copy the gray values to all channels to help out the writer.
|
||||
for (int y = 0; y < get_y_size(); y++) {
|
||||
|
@ -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
|
||||
// Access: Public, Virtual
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pnmImageHeader.h"
|
||||
|
||||
class PfmFile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PNMReader
|
||||
@ -39,6 +39,8 @@ public:
|
||||
INLINE PNMFileType *get_type() const;
|
||||
|
||||
virtual void prepare_read();
|
||||
virtual bool is_floating_point();
|
||||
virtual bool read_pfm(PfmFile &pfm);
|
||||
virtual int read_data(xel *array, xelval *alpha);
|
||||
virtual bool supports_read_row() const;
|
||||
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
|
||||
|
@ -28,6 +28,43 @@ PNMWriter::
|
||||
_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
|
||||
// Access: Public, Virtual
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "pnmImageHeader.h"
|
||||
class PfmFile;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PNMWriter
|
||||
@ -48,6 +49,10 @@ public:
|
||||
|
||||
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 bool supports_write_row() const;
|
||||
virtual bool supports_grayscale() const;
|
||||
|
@ -15,6 +15,7 @@
|
||||
pnmFileTypeIMG.h \
|
||||
pnmFileTypePNG.h \
|
||||
pnmFileTypePNM.h \
|
||||
pnmFileTypePfm.h \
|
||||
pnmFileTypeSGI.h pnmFileTypeSoftImage.h \
|
||||
pnmFileTypeTGA.h \
|
||||
pnmFileTypeTIFF.h \
|
||||
@ -28,6 +29,7 @@
|
||||
pnmFileTypeJPG.cxx pnmFileTypeJPGReader.cxx pnmFileTypeJPGWriter.cxx \
|
||||
pnmFileTypePNG.cxx \
|
||||
pnmFileTypePNM.cxx \
|
||||
pnmFileTypePfm.cxx \
|
||||
pnmFileTypeSGI.cxx \
|
||||
pnmFileTypeSGIReader.cxx pnmFileTypeSGIWriter.cxx \
|
||||
pnmFileTypeSoftImage.cxx \
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "pnmFileTypeJPG.h"
|
||||
#include "pnmFileTypePNG.h"
|
||||
#include "pnmFileTypePNM.h"
|
||||
#include "pnmFileTypePfm.h"
|
||||
#include "pnmFileTypeTIFF.h"
|
||||
#include "sgi.h"
|
||||
|
||||
@ -216,6 +217,10 @@ init_libpnmimagetypes() {
|
||||
tr->register_type(new PNMFileTypePNM);
|
||||
#endif
|
||||
|
||||
PNMFileTypePfm::init_type();
|
||||
PNMFileTypePfm::register_with_read_factory();
|
||||
tr->register_type(new PNMFileTypePfm);
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
PNMFileTypeJPG::init_type();
|
||||
PNMFileTypeJPG::register_with_read_factory();
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "pnmFileTypePNG.cxx"
|
||||
#include "pnmFileTypeTIFF.cxx"
|
||||
#include "pnmFileTypePNM.cxx"
|
||||
#include "pnmFileTypePfm.cxx"
|
||||
#include "pnmFileTypeSGI.cxx"
|
||||
#include "pnmFileTypeSGIReader.cxx"
|
||||
#include "pnmFileTypeSGIWriter.cxx"
|
||||
|
@ -13,6 +13,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pnmFileTypePfm.h"
|
||||
#include "pfmFile.h"
|
||||
#include "config_pnmimage.h"
|
||||
|
||||
#include "pnmFileTypeRegistry.h"
|
||||
@ -134,45 +135,115 @@ PNMFileTypePfm::Reader::
|
||||
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
|
||||
PNMReader(type, file, owns_file)
|
||||
{
|
||||
PfmFile pfm;
|
||||
if (!pfm.read(*file, Filename(), magic_number)) {
|
||||
read_magic_number(_file, magic_number, 2);
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
pfm.store(_image);
|
||||
PNMImageHeader::operator = (_image);
|
||||
(*_file) >> _x_size >> _y_size >> _scale;
|
||||
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
|
||||
// Description: 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.
|
||||
// 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().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int PNMFileTypePfm::Reader::
|
||||
read_data(xel *array, xelval *alpha) {
|
||||
bool PNMFileTypePfm::Reader::
|
||||
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()) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
nassertr(_image.get_x_size() == get_x_size() &&
|
||||
_image.get_y_size() == get_y_size(), 0);
|
||||
|
||||
memcpy(array, _image.get_array(), get_x_size() * get_y_size() * sizeof(xel));
|
||||
|
||||
if (has_alpha()) {
|
||||
memcpy(alpha, _image.get_alpha_array(), get_x_size() * get_y_size() * sizeof(xelval));
|
||||
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 = _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
|
||||
// Description: 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.
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int PNMFileTypePfm::Writer::
|
||||
write_data(xel *array, xelval *alpha) {
|
||||
if (_x_size <= 0 || _y_size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
bool PNMFileTypePfm::Writer::
|
||||
supports_floating_point() {
|
||||
return true;
|
||||
}
|
||||
|
||||
PNMImage image;
|
||||
image.copy_header_from(*this);
|
||||
nassertr(image.get_x_size() == get_x_size() &&
|
||||
image.get_y_size() == get_y_size(), 0);
|
||||
memcpy(image.get_array(), array, get_x_size() * get_y_size() * sizeof(xel));
|
||||
if (has_alpha()) {
|
||||
memcpy(image.get_alpha_array(), alpha, get_x_size() * get_y_size() * sizeof(xelval));
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMFileTypePfm::Writer::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 PNMFileTypePfm::Writer::
|
||||
supports_integer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
PfmFile pfm;
|
||||
if (!pfm.load(image)) {
|
||||
return 0;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMFileTypePfm::Writer::write_pfm
|
||||
// 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)) {
|
||||
return 0;
|
||||
}
|
||||
switch (pfm.get_num_channels()) {
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
@ -48,18 +48,21 @@ public:
|
||||
class Reader : public PNMReader {
|
||||
public:
|
||||
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:
|
||||
PNMImage _image;
|
||||
PN_float32 _scale;
|
||||
};
|
||||
|
||||
class Writer : public PNMWriter {
|
||||
public:
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -46,6 +46,8 @@ PUBLISHED:
|
||||
TF_allow_1d = 0x0010, // If texture is Nx1, make a 1-d texture
|
||||
TF_generate_mipmaps = 0x0020, // Consider generating mipmaps
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user