move pfmfile to grutil

This commit is contained in:
David Rose 2011-03-14 20:10:00 +00:00
parent 2a691dd339
commit d91a11a836
10 changed files with 218 additions and 1073 deletions

View File

@ -15,7 +15,26 @@
#define SOURCES \
config_pfm.cxx config_pfm.h \
pfmFile.cxx pfmFile.h \
pfmTrans.cxx pfmTrans.h
#end bin_target
#begin bin_target
#define TARGET pfm-bba
#define LOCAL_LIBS progbase
#define SOURCES \
config_pfm.cxx config_pfm.h \
pfmBba.cxx pfmBba.h
#end bin_target
//#begin bin_target
// #define TARGET pfm-wallpaper
// #define LOCAL_LIBS progbase
//
// #define SOURCES \
// config_pfm.cxx config_pfm.h \
// pfmWallpaper.cxx pfmWallpaper.h
//
//#end bin_target

View File

@ -19,17 +19,6 @@
Configure(config_pfm);
NotifyCategoryDef(pfm, "");
ConfigVariableBool pfm_force_littleendian
("pfm-force-littleendian", false,
PRC_DESC("This forces a pfm file to be read as a sequence of little-endian "
"floats, even if its scale factor is given as a positive number."));
ConfigVariableBool pfm_reverse_dimensions
("pfm-reverse-dimensions", false,
PRC_DESC("Understands that the width and height of a pfm file are given "
"backwards, in the form height width instead of width height, "
"on input. Does not affect output, which is always written width height."));
ConfigVariableDouble pfm_bba_dist
("pfm-bba-dist", "0.2 0.05",
PRC_DESC("Specifies the point_dist and sample_radius, in UV space, for "

View File

@ -23,8 +23,6 @@
NotifyCategoryDeclNoExport(pfm);
extern ConfigVariableBool pfm_force_littleendian;
extern ConfigVariableBool pfm_reverse_dimensions;
extern ConfigVariableDouble pfm_bba_dist;
extern void init_libpfm();

147
pandatool/src/pfmprogs/pfmBba.cxx Executable file
View File

@ -0,0 +1,147 @@
// Filename: pfmBba.cxx
// Created by: drose (02Mar11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "pfmBba.h"
#include "config_pfm.h"
#include "pfmFile.h"
#include "pystub.h"
////////////////////////////////////////////////////////////////////
// Function: PfmBba::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PfmBba::
PfmBba() {
set_program_description
("pfm-bba generates a .bba file from a .pfm file that lists the "
"planar bounding volume of the pfm's internal data.");
add_option
("z", "", 0,
"Treats (0,0,0) in the pfm file as a special don't-touch value.",
&PfmBba::dispatch_none, &_got_zero_special);
add_option
("o", "filename", 50,
"Specify the filename to which the resulting bba file will be written.",
&PfmBba::dispatch_filename, &_got_output_filename, &_output_filename);
}
////////////////////////////////////////////////////////////////////
// Function: PfmBba::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void PfmBba::
run() {
Filenames::const_iterator fi;
for (fi = _input_filenames.begin(); fi != _input_filenames.end(); ++fi) {
PfmFile file;
if (!file.read(*fi)) {
nout << "Cannot read " << *fi << "\n";
exit(1);
}
if (!process_pfm(*fi, file)) {
exit(1);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmBba::process_pfm
// Access: Public
// Description: Handles a single pfm file.
////////////////////////////////////////////////////////////////////
bool PfmBba::
process_pfm(const Filename &input_filename, PfmFile &file) {
file.set_zero_special(_got_zero_special);
Filename bba_filename;
if (_got_output_filename) {
bba_filename = _output_filename;
} else {
bba_filename = input_filename;
bba_filename.set_extension("bba");
}
if (!bba_filename.empty()) {
bba_filename.set_text();
PT(BoundingHexahedron) bounds = file.compute_planar_bounds(pfm_bba_dist[0], pfm_bba_dist[1]);
nassertr(bounds != (BoundingHexahedron *)NULL, false);
pofstream out;
if (!bba_filename.open_write(out)) {
pfm_cat.error()
<< "Unable to open " << bba_filename << "\n";
return false;
}
// This is the order expected by our existing bba system.
static const int ri = 0;
static const int reorder_points[][8] = {
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // unfiltered
{ 7, 5, 1, 3, 6, 4, 0, 2 }, // front, floor
{ 4, 6, 2, 0, 5, 7, 3, 1 }, // left
{ 7, 5, 1, 3, 2, 0, 4, 6 }, // right
};
for (int i = 0; i < bounds->get_num_points(); ++i) {
LPoint3f p = bounds->get_point(reorder_points[ri][i]);
out << p[0] << "," << p[1] << "," << p[2] << "\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PfmBba::handle_args
// Access: Protected, Virtual
// Description: Does something with the additional arguments on the
// command line (after all the -options have been
// parsed). Returns true if the arguments are good,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool PfmBba::
handle_args(ProgramBase::Args &args) {
if (args.empty()) {
nout << "You must specify the pfm file(s) to read on the command line.\n";
return false;
}
if (args.size() > 1 && _got_output_filename) {
nout << "Cannot use -o when multiple pfm files are specified.\n";
return false;
}
Args::const_iterator ai;
for (ai = args.begin(); ai != args.end(); ++ai) {
_input_filenames.push_back(Filename::from_os_specific(*ai));
}
return true;
}
int main(int argc, char *argv[]) {
// A call to pystub() to force libpystub.so to be linked in.
pystub();
PfmBba prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
}

50
pandatool/src/pfmprogs/pfmBba.h Executable file
View File

@ -0,0 +1,50 @@
// Filename: pfmBba.h
// Created by: drose (02Mar11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef PFMBBA_H
#define PFMBBA_H
#include "pandatoolbase.h"
#include "programBase.h"
#include "filename.h"
#include "pvector.h"
#include "nodePath.h"
#include "luse.h"
class PfmFile;
////////////////////////////////////////////////////////////////////
// Class : PfmBba
// Description : Generates a bounding-box description of a pfm file.
////////////////////////////////////////////////////////////////////
class PfmBba : public ProgramBase {
public:
PfmBba();
void run();
bool process_pfm(const Filename &input_filename, PfmFile &file);
protected:
virtual bool handle_args(Args &args);
private:
typedef pvector<Filename> Filenames;
Filenames _input_filenames;
bool _got_zero_special;
bool _got_output_filename;
Filename _output_filename;
};
#endif

View File

@ -1,151 +0,0 @@
// Filename: pfmFile.I
// Created by: drose (23Dec10)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PfmFile::is_valid
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool PfmFile::
is_valid() const {
return _num_channels != 0 && (_x_size * _y_size == (int)_table.size());
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_x_size
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE int PfmFile::
get_x_size() const {
return _x_size;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_y_size
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE int PfmFile::
get_y_size() const {
return _y_size;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_scale
// Access: Public
// Description: The "scale" is reported in the pfm header and is
// probably meaningless.
////////////////////////////////////////////////////////////////////
INLINE float PfmFile::
get_scale() const {
return _scale;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_num_channels
// Access: Public
// 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.
////////////////////////////////////////////////////////////////////
INLINE int PfmFile::
get_num_channels() const {
return _num_channels;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_point
// Access: Public
// Description: Returns the 3-component point value at the indicated
// point. In a 1-channel image, the channel value is in
// the x component.
////////////////////////////////////////////////////////////////////
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());
return _table[y * _x_size + x];
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::modify_point
// Access: Public
// Description: Returns a modifiable 3-component point value at the
// indicated point.
////////////////////////////////////////////////////////////////////
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);
#endif
return _table[y * _x_size + x];
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_zero_special
// Access: Public
// Description: Sets the zero_special flag. When this flag is true,
// values of (0, 0, 0) in the pfm file are treated as a
// special case, and are not processed.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_zero_special(bool zero_special) {
_zero_special = zero_special;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_zero_special
// Access: Public
// Description: Returns the zero_special flag. When this flag is true,
// values of (0, 0, 0) in the pfm file are treated as a
// special case, and are not processed.
////////////////////////////////////////////////////////////////////
INLINE bool PfmFile::
get_zero_special() const {
return _zero_special;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_vis_inverse
// Access: Public
// Description: Sets the vis_inverse flag. When this flag is true,
// vis meshes and point clouds are generated with the
// 3-d depth value in the texture coordinates, and the
// 2-d index value in the vertex position. When it is
// false, meshes are generated normally, with the 3-d
// depth value in the vertex position and the 2-d index
// value in the texture coordinates.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_vis_inverse(bool vis_inverse) {
_vis_inverse = vis_inverse;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_vis_inverse
// Access: Public
// Description: Returns the vis_inverse flag. See set_vis_inverse().
////////////////////////////////////////////////////////////////////
INLINE bool PfmFile::
get_vis_inverse() const {
return _vis_inverse;
}

View File

@ -1,778 +0,0 @@
// Filename: pfmFile.cxx
// Created by: drose (23Dec10)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "config_pfm.h"
#include "pfmFile.h"
#include "virtualFileSystem.h"
#include "pandaFileStream.h"
#include "littleEndian.h"
#include "bigEndian.h"
#include "cmath.h"
#include "geomNode.h"
#include "geom.h"
#include "geomVertexData.h"
#include "geomVertexFormat.h"
#include "geomPoints.h"
#include "geomTriangles.h"
#include "geomVertexWriter.h"
#include "look_at.h"
////////////////////////////////////////////////////////////////////
// Function: PfmFile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PfmFile::
PfmFile() {
_zero_special = false;
_vis_inverse = false;
clear();
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PfmFile::
PfmFile(const PfmFile &copy) :
_table(copy._table),
_x_size(copy._x_size),
_y_size(copy._y_size),
_scale(copy._scale),
_num_channels(copy._num_channels),
_zero_special(copy._zero_special)
{
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::Copy Assignment
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
operator = (const PfmFile &copy) {
_table = copy._table;
_x_size = copy._x_size;
_y_size = copy._y_size;
_scale = copy._scale;
_num_channels = copy._num_channels;
_zero_special = copy._zero_special;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::clear
// Access: Public
// Description: Eliminates all data in the file.
////////////////////////////////////////////////////////////////////
void PfmFile::
clear() {
_x_size = 0;
_y_size = 0;
_num_channels = 0;
_table.clear();
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::read
// Access: Public
// Description: Reads the PFM data from the indicated file, returning
// true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PfmFile::
read(const Filename &fullpath) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
Filename filename = Filename::binary_filename(fullpath);
PT(VirtualFile) file = vfs->get_file(filename);
if (file == (VirtualFile *)NULL) {
// No such file.
pfm_cat.error()
<< "Could not find " << fullpath << "\n";
return false;
}
if (pfm_cat.is_debug()) {
pfm_cat.debug()
<< "Reading PFM file " << filename << "\n";
}
istream *in = file->open_read_file(true);
bool success = read(*in);
vfs->close_read_file(in);
return success;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::read
// Access: Public
// Description: Reads the PFM data from the indicated stream,
// returning true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PfmFile::
read(istream &in) {
clear();
string identifier;
in >> identifier;
if (identifier == "PF") {
_num_channels = 3;
} else if (identifier == "Pf") {
_num_channels = 1;
} else {
pfm_cat.error()
<< "Not a pfm file.\n";
return false;
}
int width, height;
float scale;
in >> width >> height >> scale;
if (!in) {
pfm_cat.error()
<< "Error parsing pfm header.\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;
_table.reserve(size);
if (little_endian) {
for (int i = 0; i < size; ++i) {
LPoint3f point = LPoint3f::zero();
for (int ci = 0; ci < _num_channels; ++ci) {
float data;
in.read((char *)&data, sizeof(data));
LittleEndian value(&data, sizeof(data));
value.store_value(&(point[ci]), sizeof(point[ci]));
}
_table.push_back(point);
}
} else {
for (int i = 0; i < size; ++i) {
LPoint3f point = LPoint3f::zero();
for (int ci = 0; ci < _num_channels; ++ci) {
float data;
in.read((char *)&data, sizeof(data));
BigEndian value(&data, sizeof(data));
value.store_value(&(point[ci]), sizeof(point[ci]));
}
_table.push_back(point);
}
}
if (in.fail() && !in.eof()) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::write
// Access: Public
// Description: Writes the PFM data to the indicated file, returning
// true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PfmFile::
write(const Filename &fullpath) {
Filename filename = Filename::binary_filename(fullpath);
pofstream out;
if (!filename.open_write(out)) {
pfm_cat.error()
<< "Unable to open " << filename << "\n";
return false;
}
if (pfm_cat.is_debug()) {
pfm_cat.debug()
<< "Writing PFM file " << filename << "\n";
}
return write(out);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::write
// Access: Public
// Description: Writes the PFM data to the indicated stream,
// returning true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool PfmFile::
write(ostream &out) {
nassertr(is_valid(), false);
if (_num_channels == 1) {
out << "Pf\n";
} else {
out << "PF\n";
}
out << _x_size << " " << _y_size << "\n";
float scale = cabs(_scale);
if (scale == 0.0f) {
scale = 1.0f;
}
#ifndef WORDS_BIGENDIAN
// Little-endian must write negative values for scale.
scale = -scale;
#endif
out << scale << "\n";
int size = _x_size * _y_size;
for (int i = 0; i < size; ++i) {
const LPoint3f &point = _table[i];
for (int ci = 0; ci < _num_channels; ++ci) {
float data = point[ci];
out.write((const char *)&data, sizeof(data));
}
}
if (out.fail()) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::resize
// Access: Public
// Description: Applies a simple filter to resample the pfm file
// in-place to the indicated size. Don't confuse this
// with applying a scale to all of the points via
// xform().
////////////////////////////////////////////////////////////////////
void PfmFile::
resize(int new_x_size, int new_y_size) {
Table new_data;
new_data.reserve(new_x_size * new_y_size);
double from_x0, from_x1, from_y0, from_y1;
double x_scale = (double)(_x_size - 1) / (double)(new_x_size - 1);
double y_scale = (double)(_y_size - 1) / (double)(new_y_size - 1);
from_y0 = 0.0;
for (int to_y = 0; to_y < new_y_size; ++to_y) {
from_y1 = (to_y + 0.5) * y_scale;
from_y1 = min(from_y1, (double) _y_size);
from_x0 = 0.0;
for (int to_x = 0; to_x < new_x_size; ++to_x) {
from_x1 = (to_x + 0.5) * x_scale;
from_x1 = min(from_x1, (double) _x_size);
// Now the box from (from_x0, from_y0) - (from_x1, from_y1)
// but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
LPoint3f result;
box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
new_data.push_back(result);
from_x0 = from_x1;
}
from_y0 = from_y1;
}
_table.swap(new_data);
_x_size = new_x_size;
_y_size = new_y_size;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::reverse_rows
// Access: Public
// Description: Performs an in-place reversal of the row (y) data.
////////////////////////////////////////////////////////////////////
void PfmFile::
reverse_rows() {
nassertv(is_valid());
Table reversed;
reversed.reserve(_table.size());
for (int yi = 0; yi < _y_size; ++yi) {
int source_yi = _y_size - 1 - yi;
int start = source_yi * _x_size;
reversed.insert(reversed.end(),
_table.begin() + start, _table.begin() + start + _x_size);
}
nassertv(reversed.size() == _table.size());
_table.swap(reversed);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::xform
// Access: Public
// Description: Applies the indicated transform matrix to all points
// in-place.
////////////////////////////////////////////////////////////////////
void PfmFile::
xform(const LMatrix4f &transform) {
nassertv(is_valid());
Table::iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
if (_zero_special && (*ti) == LPoint3f::zero()) {
continue;
}
(*ti) = (*ti) * transform;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::compute_planar_bounds
// Access: Public
// Description: Computes the minmax bounding volume of the points in
// 3-D space, assuming the points represent a
// mostly-planar surface.
//
// This algorithm works by sampling the (square)
// sample_radius pixels at three of the four point_dist
// corners around the center (cx - pd, cx + pd) and so
// on, to determine the plane of the surface. Then all
// of the points are projected into that plane and the
// bounding volume within that plane is determined.
//
// point_dist and sample_radius are in UV space, i.e. in
// the range 0..1.
////////////////////////////////////////////////////////////////////
PT(BoundingHexahedron) PfmFile::
compute_planar_bounds(double point_dist, double sample_radius) const {
LPoint3f p0, p1, p2;
compute_sample_point(p0, 0.5 + point_dist, 0.5 - point_dist, sample_radius);
compute_sample_point(p1, 0.5 + point_dist, 0.5 + point_dist, sample_radius);
compute_sample_point(p2, 0.5 - point_dist, 0.5 + point_dist, sample_radius);
LPoint3f normal;
normal[0] = p0[1] * p1[2] - p0[2] * p1[1];
normal[1] = p0[2] * p1[0] - p0[0] * p1[2];
normal[2] = p0[0] * p1[1] - p0[1] * p1[0];
normal[0] += p1[1] * p2[2] - p1[2] * p2[1];
normal[1] += p1[2] * p2[0] - p1[0] * p2[2];
normal[2] += p1[0] * p2[1] - p1[1] * p2[0];
normal[0] += p2[1] * p0[2] - p2[2] * p0[1];
normal[1] += p2[2] * p0[0] - p2[0] * p0[2];
normal[2] += p2[0] * p0[1] - p2[1] * p0[0];
normal.normalize();
// Compute the transform necessary to rotate all of the points into
// the Y = 0 plane.
LMatrix4f rotate;
look_at(rotate, normal, p1 - p0);
LMatrix4f rinv;
rinv.invert_from(rotate);
LPoint3f trans = p0 * rinv;
rinv.set_row(3, -trans);
rotate.invert_from(rinv);
// Now determine the minmax in the XZ plane.
float min_x, min_z, max_x, max_z;
bool got_point = false;
Table::const_iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
if (_zero_special && (*ti) == LPoint3f::zero()) {
continue;
}
LPoint3f point = (*ti) * rinv;
if (!got_point) {
min_x = point[0];
min_z = point[2];
max_x = point[0];
max_z = point[2];
got_point = true;
} else {
min_x = min(min_x, point[0]);
min_z = min(min_z, point[2]);
max_x = max(max_x, point[0]);
max_z = max(max_z, point[2]);
}
}
PT(BoundingHexahedron) bounds = new BoundingHexahedron
(LPoint3f(min_x, 0, min_z), LPoint3f(max_x, 0, min_z),
LPoint3f(min_x, 0, max_z), LPoint3f(max_x, 0, max_z),
LPoint3f(min_x, 0, min_z), LPoint3f(max_x, 0, min_z),
LPoint3f(min_x, 0, max_z), LPoint3f(max_x, 0, max_z));
// Rotate the bounding volume back into the original space of the
// screen.
bounds->xform(rotate);
return bounds;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::generate_vis_points
// Access: Public
// Description: Creates a point cloud with the points of the pfm as
// 3-d coordinates in space, and texture coordinates
// ranging from 0 .. 1 based on the position within the
// pfm grid.
////////////////////////////////////////////////////////////////////
NodePath PfmFile::
generate_vis_points() const {
nassertr(is_valid(), NodePath());
CPT(GeomVertexFormat) format;
if (_vis_inverse) {
// We need a 3-d texture coordinate if we're inverted the vis.
GeomVertexArrayFormat *v3t3 = new GeomVertexArrayFormat
(InternalName::get_vertex(), 3,
Geom::NT_float32, Geom::C_point,
InternalName::get_texcoord(), 3,
Geom::NT_float32, Geom::C_texcoord);
format = GeomVertexFormat::register_format(v3t3);
} else {
format = GeomVertexFormat::get_v3t2();
}
PT(GeomVertexData) vdata = new GeomVertexData
("points", format, Geom::UH_static);
vdata->set_num_rows(_x_size * _y_size);
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
const LPoint3f &point = get_point(xi, yi);
LPoint2f uv(float(xi) / float(_x_size - 1),
float(yi) / float(_y_size - 1));
if (_vis_inverse) {
vertex.add_data2f(uv);
texcoord.add_data3f(point);
} else {
vertex.add_data3f(point);
texcoord.add_data2f(uv);
}
}
}
PT(Geom) geom = new Geom(vdata);
PT(GeomPoints) points = new GeomPoints(Geom::UH_static);
points->add_next_vertices(_x_size * _y_size);
geom->add_primitive(points);
PT(GeomNode) gnode = new GeomNode("");
gnode->add_geom(geom);
return NodePath(gnode);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::generate_vis_mesh
// Access: Public
// Description: Creates a triangle mesh with the points of the pfm as
// 3-d coordinates in space, and texture coordinates
// ranging from 0 .. 1 based on the position within the
// pfm grid.
////////////////////////////////////////////////////////////////////
NodePath PfmFile::
generate_vis_mesh() const {
nassertr(is_valid(), NodePath());
PT(GeomNode) gnode = new GeomNode("");
PT(Geom) geom1 = make_vis_mesh_geom(false);
gnode->add_geom(geom1);
PT(Geom) geom2 = make_vis_mesh_geom(true);
gnode->add_geom(geom2);
return NodePath(gnode);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::make_vis_mesh_geom
// Access: Private
// Description: Returns a triangle mesh for the pfm. If inverted is
// true, the mesh is facing the opposite direction.
////////////////////////////////////////////////////////////////////
PT(Geom) PfmFile::
make_vis_mesh_geom(bool inverted) const {
CPT(GeomVertexFormat) format;
if (_vis_inverse) {
// We need a 3-d texture coordinate if we're inverted the vis.
// But we don't need normals in that case.
GeomVertexArrayFormat *v3t3 = new GeomVertexArrayFormat
(InternalName::get_vertex(), 3,
Geom::NT_float32, Geom::C_point,
InternalName::get_texcoord(), 3,
Geom::NT_float32, Geom::C_texcoord);
format = GeomVertexFormat::register_format(v3t3);
} else {
// Otherwise, we only need a 2-d texture coordinate, and we do
// want normals.
format = GeomVertexFormat::get_v3n3t2();
}
PT(GeomVertexData) vdata = new GeomVertexData
("mesh", format, Geom::UH_static);
int num_vertices = _x_size * _y_size;
vdata->set_num_rows(num_vertices);
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
GeomVertexWriter normal(vdata, InternalName::get_normal());
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
const LPoint3f &point = get_point(xi, yi);
LPoint2f uv(float(xi) / float(_x_size - 1),
float(yi) / float(_y_size - 1));
if (_vis_inverse) {
vertex.add_data2f(uv);
texcoord.add_data3f(point);
} else {
vertex.add_data3f(point);
texcoord.add_data2f(uv);
// Calculate the normal based on two neighboring vertices.
LPoint3f v[3];
v[0] = get_point(xi, yi);
if (xi + 1 < _x_size) {
v[1] = get_point(xi + 1, yi);
} else {
v[1] = v[0];
v[0] = get_point(xi - 1, yi);
}
if (yi + 1 < _y_size) {
v[2] = get_point(xi, yi + 1);
} else {
v[2] = v[0];
v[0] = get_point(xi, yi - 1);
}
LVector3f n = LVector3f::zero();
for (int i = 0; i < 3; ++i) {
const LPoint3f &v0 = v[i];
const LPoint3f &v1 = v[(i + 1) % 3];
n[0] += v0[1] * v1[2] - v0[2] * v1[1];
n[1] += v0[2] * v1[0] - v0[0] * v1[2];
n[2] += v0[0] * v1[1] - v0[1] * v1[0];
}
n.normalize();
if (inverted) {
n = -n;
}
normal.add_data3f(n);
}
}
}
PT(Geom) geom = new Geom(vdata);
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
if (num_vertices > 0xffff) {
// We need 32-bit indices.
tris->set_index_type(Geom::NT_uint32);
}
// We get direct access to the vertices data so we can speed things
// up by pre-specifying the number of vertices. Need a better
// interface to do this same thing using the high-level access
// methods.
int num_indices = (_x_size - 1) * (_y_size - 1) * 6;
PT(GeomVertexArrayData) indices = tris->modify_vertices();
indices->set_num_rows(num_indices);
GeomVertexWriter index(indices, 0);
int actual_num_indices = 0;
for (int yi = 0; yi < _y_size - 1; ++yi) {
for (int xi = 0; xi < _x_size - 1; ++xi) {
if (_zero_special) {
if (get_point(xi, yi) == LPoint3f::zero() ||
get_point(xi, yi + 1) == LPoint3f::zero() ||
get_point(xi + 1, yi + 1) == LPoint3f::zero() ||
get_point(xi + 1, yi) == LPoint3f::zero()) {
continue;
}
}
int vi0 = ((xi) + (yi) * _x_size);
int vi1 = ((xi) + (yi + 1) * _x_size);
int vi2 = ((xi + 1) + (yi + 1) * _x_size);
int vi3 = ((xi + 1) + (yi) * _x_size);
if (inverted) {
index.add_data1i(vi2);
index.add_data1i(vi0);
index.add_data1i(vi1);
index.add_data1i(vi3);
index.add_data1i(vi0);
index.add_data1i(vi2);
} else {
index.add_data1i(vi2);
index.add_data1i(vi1);
index.add_data1i(vi0);
index.add_data1i(vi3);
index.add_data1i(vi2);
index.add_data1i(vi0);
}
actual_num_indices += 6;
}
}
indices->set_num_rows(actual_num_indices);
geom->add_primitive(tris);
return geom;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::compute_sample_point
// Access: Private
// Description: Computes the average of all the point within
// sample_radius (manhattan distance) and the indicated
// point.
//
// Unlike box_filter_*(), these point values are given
// in UV space, in the range 0..1.
////////////////////////////////////////////////////////////////////
void PfmFile::
compute_sample_point(LPoint3f &result,
double x, double y, double sample_radius) const {
x *= _x_size;
y *= _y_size;
double xr = sample_radius * _x_size;
double yr = sample_radius * _y_size;
box_filter_region(result, x - xr, y - yr, x + xr, y + yr);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_region
// Access: Private
// Description: Averages all the points in the rectangle from x0
// .. y0 to x1 .. y1 into result. The region may be
// defined by floating-point boundaries; the result will
// be weighted by the degree of coverage of each
// included point.
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_region(LPoint3f &result,
double x0, double y0, double x1, double y1) const {
result = LPoint3f::zero();
double coverage = 0.0;
assert(y0 >= 0.0 && y1 >= 0.0);
int y = (int)y0;
// Get the first (partial) row
box_filter_line(result, coverage, x0, y, x1, (double)(y+1)-y0);
int y_last = (int)y1;
if (y < y_last) {
y++;
while (y < y_last) {
// Get each consecutive (complete) row
box_filter_line(result, coverage, x0, y, x1, 1.0);
y++;
}
// Get the final (partial) row
double y_contrib = y1 - (double)y_last;
if (y_contrib > 0.0001) {
box_filter_line(result, coverage, x0, y, x1, y_contrib);
}
}
if (coverage != 0.0) {
result /= coverage;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_line
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_line(LPoint3f &result, double &coverage,
double x0, int y, double x1, double y_contrib) const {
int x = (int)x0;
// Get the first (partial) xel
box_filter_point(result, coverage, x, y, (double)(x+1)-x0, y_contrib);
int x_last = (int)x1;
if (x < x_last) {
x++;
while (x < x_last) {
// Get each consecutive (complete) xel
box_filter_point(result, coverage, x, y, 1.0, y_contrib);
x++;
}
// Get the final (partial) xel
double x_contrib = x1 - (double)x_last;
if (x_contrib > 0.0001) {
box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_point
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_point(LPoint3f &result, double &coverage,
int x, int y, double x_contrib, double y_contrib) const {
const LPoint3f &point = get_point(x, y);
if (_zero_special && point == LPoint3f::zero()) {
return;
}
double contrib = x_contrib * y_contrib;
result += point * contrib;
coverage += contrib;
}

View File

@ -1,94 +0,0 @@
// Filename: pfmFile.h
// Created by: drose (23Dec10)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef PFMFILE_H
#define PFMFILE_H
#include "pandatoolbase.h"
#include "luse.h"
#include "nodePath.h"
#include "boundingHexahedron.h"
////////////////////////////////////////////////////////////////////
// Class : PfmFile
// Description : Defines a pfm file, a 2-d table of floating-point
// numbers, either 3-component or 1-component.
////////////////////////////////////////////////////////////////////
class PfmFile {
public:
PfmFile();
PfmFile(const PfmFile &copy);
void operator = (const PfmFile &copy);
void clear();
bool read(const Filename &fullpath);
bool read(istream &in);
bool write(const Filename &fullpath);
bool write(ostream &out);
INLINE bool is_valid() const;
INLINE int get_x_size() const;
INLINE int get_y_size() const;
INLINE float get_scale() const;
INLINE int get_num_channels() const;
INLINE const LPoint3f &get_point(int x, int y) const;
INLINE LPoint3f &modify_point(int x, int y);
INLINE void set_zero_special(bool zero_special);
INLINE bool get_zero_special() const;
void resize(int new_x_size, int new_y_size);
void reverse_rows();
void xform(const LMatrix4f &transform);
PT(BoundingHexahedron) compute_planar_bounds(double point_dist, double sample_radius) const;
INLINE void set_vis_inverse(bool vis_inverse);
INLINE bool get_vis_inverse() const;
NodePath generate_vis_points() const;
NodePath generate_vis_mesh() const;
private:
PT(Geom) make_vis_mesh_geom(bool inverted) const;
void compute_sample_point(LPoint3f &result,
double x, double y, double sample_radius) const;
void box_filter_region(LPoint3f &result,
double x0, double y0, double x1, double y1) const;
void box_filter_line(LPoint3f &result, double &coverage,
double x0, int y, double x1, double y_contrib) const;
void box_filter_point(LPoint3f &result, double &coverage,
int x, int y, double x_contrib, double y_contrib) const;
private:
typedef pvector<LPoint3f> Table;
Table _table;
int _x_size;
int _y_size;
float _scale;
int _num_channels;
bool _zero_special;
bool _vis_inverse;
};
#include "pfmFile.I"
#endif

View File

@ -72,12 +72,6 @@ PfmTrans() {
"in lieu of the -o option.",
&PfmTrans::dispatch_filename, &_got_output_dirname, &_output_dirname);
add_option
("bba", "", 50,
"Generates a .bba file alongside each output file that lists the "
"planar bounding volume of each pfm file's data.",
&PfmTrans::dispatch_none, &_got_bba);
add_option
("vis", "filename.bam", 60,
"Generates a bam file that represents a visualization of the pfm file "
@ -149,7 +143,7 @@ process_pfm(const Filename &input_filename, PfmFile &file) {
}
if (_got_vis_filename) {
NodePath mesh = file.generate_vis_mesh();
NodePath mesh = file.generate_vis_mesh(true);
if (_got_vistex_filename) {
PT(Texture) tex = TexturePool::load_texture(_vistex_filename);
if (tex == NULL) {
@ -173,34 +167,6 @@ process_pfm(const Filename &input_filename, PfmFile &file) {
}
if (!output_filename.empty()) {
if (_got_bba) {
Filename bba_filename = output_filename;
bba_filename.set_text();
bba_filename.set_extension("bba");
PT(BoundingHexahedron) bounds = file.compute_planar_bounds(pfm_bba_dist[0], pfm_bba_dist[1]);
nassertr(bounds != (BoundingHexahedron *)NULL, false);
pofstream out;
if (!bba_filename.open_write(out)) {
pfm_cat.error()
<< "Unable to open " << bba_filename << "\n";
return false;
}
// This is the order expected by our existing bba system.
static const int ri = 0;
static const int reorder_points[][8] = {
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // unfiltered
{ 7, 5, 1, 3, 6, 4, 0, 2 }, // front, floor
{ 4, 6, 2, 0, 5, 7, 3, 1 }, // left
{ 7, 5, 1, 3, 2, 0, 4, 6 }, // right
};
for (int i = 0; i < bounds->get_num_points(); ++i) {
LPoint3f p = bounds->get_point(reorder_points[ri][i]);
out << p[0] << "," << p[1] << "," << p[2] << "\n";
}
}
return file.write(output_filename);
}

View File

@ -56,7 +56,6 @@ private:
bool _got_vis_inverse;
bool _got_resize;
int _resize[2];
bool _got_bba;
bool _got_output_filename;
Filename _output_filename;