mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 09:23:03 -04:00
pfmprogs
This commit is contained in:
parent
eafad905c5
commit
ab0645ab79
21
pandatool/src/pfmprogs/Sources.pp
Executable file
21
pandatool/src/pfmprogs/Sources.pp
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#define OTHER_LIBS \
|
||||||
|
egg:c pandaegg:m \
|
||||||
|
pipeline:c event:c pstatclient:c panda:m \
|
||||||
|
pandabase:c pnmimage:c mathutil:c linmath:c putil:c express:c \
|
||||||
|
pandaexpress:m \
|
||||||
|
interrogatedb:c prc:c dconfig:c dtoolconfig:m \
|
||||||
|
dtoolutil:c dtoolbase:c dtool:m \
|
||||||
|
$[if $[WANT_NATIVE_NET],nativenet:c] \
|
||||||
|
$[if $[and $[HAVE_NET],$[WANT_NATIVE_NET]],net:c downloader:c] \
|
||||||
|
pystub
|
||||||
|
|
||||||
|
#begin bin_target
|
||||||
|
#define TARGET pfm-trans
|
||||||
|
#define LOCAL_LIBS progbase
|
||||||
|
|
||||||
|
#define SOURCES \
|
||||||
|
config_pfm.cxx config_pfm.h \
|
||||||
|
pfmFile.cxx pfmFile.h \
|
||||||
|
pfmTrans.cxx pfmTrans.h
|
||||||
|
|
||||||
|
#end bin_target
|
58
pandatool/src/pfmprogs/config_pfm.cxx
Executable file
58
pandatool/src/pfmprogs/config_pfm.cxx
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
// Filename: config_pfm.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 "dconfig.h"
|
||||||
|
|
||||||
|
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 "
|
||||||
|
"compute bba files with pfm_trans."));
|
||||||
|
|
||||||
|
ConfigureFn(config_pfm) {
|
||||||
|
init_libpfm();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: init_libpfm
|
||||||
|
// Description: Initializes the library. This must be called at
|
||||||
|
// least once before any of the functions or classes in
|
||||||
|
// this library can be used. Normally it will be
|
||||||
|
// called by the static initializers and need not be
|
||||||
|
// called explicitly, but special cases exist.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void
|
||||||
|
init_libpfm() {
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
32
pandatool/src/pfmprogs/config_pfm.h
Executable file
32
pandatool/src/pfmprogs/config_pfm.h
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
// Filename: config_pfm.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 CONFIG_PFM_H
|
||||||
|
#define CONFIG_PFM_H
|
||||||
|
|
||||||
|
#include "pandatoolbase.h"
|
||||||
|
|
||||||
|
#include "notifyCategoryProxy.h"
|
||||||
|
#include "configVariableBool.h"
|
||||||
|
#include "configVariableDouble.h"
|
||||||
|
|
||||||
|
NotifyCategoryDeclNoExport(pfm);
|
||||||
|
|
||||||
|
extern ConfigVariableBool pfm_force_littleendian;
|
||||||
|
extern ConfigVariableBool pfm_reverse_dimensions;
|
||||||
|
extern ConfigVariableDouble pfm_bba_dist;
|
||||||
|
|
||||||
|
extern void init_libpfm();
|
||||||
|
|
||||||
|
#endif
|
125
pandatool/src/pfmprogs/pfmFile.I
Executable file
125
pandatool/src/pfmprogs/pfmFile.I
Executable file
@ -0,0 +1,125 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
592
pandatool/src/pfmprogs/pfmFile.cxx
Executable file
592
pandatool/src/pfmprogs/pfmFile.cxx
Executable file
@ -0,0 +1,592 @@
|
|||||||
|
// 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 "geomVertexWriter.h"
|
||||||
|
#include "look_at.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmFile::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
PfmFile::
|
||||||
|
PfmFile() {
|
||||||
|
_zero_special = false;
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmFile::Copy Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
PfmFile::
|
||||||
|
PfmFile(const PfmFile ©) :
|
||||||
|
_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 ©) {
|
||||||
|
_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 / (double)new_x_size;
|
||||||
|
double y_scale = (double)_y_size / (double)new_y_size;
|
||||||
|
|
||||||
|
from_y0 = 0;
|
||||||
|
for (int to_y = 0; to_y < new_y_size; ++to_y) {
|
||||||
|
from_y1 = (to_y+1) * y_scale;
|
||||||
|
|
||||||
|
from_x0 = 0;
|
||||||
|
for (int to_x = 0; to_x < new_x_size; ++to_x) {
|
||||||
|
from_x1 = (to_x+1) * x_scale;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
cerr << "p0 = " << p0 << "\np1 = " << p1 << "\np2 = " << p2
|
||||||
|
<< "\nnormal = " << normal << "\n";
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
PT(GeomVertexData) vdata = new GeomVertexData
|
||||||
|
("points", GeomVertexFormat::get_v3t2(),
|
||||||
|
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) {
|
||||||
|
vertex.add_data3f(get_point(xi, yi));
|
||||||
|
texcoord.add_data2f(float(xi) / float(_x_size - 1),
|
||||||
|
float(yi) / float(_y_size - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::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;
|
||||||
|
}
|
87
pandatool/src/pfmprogs/pfmFile.h
Executable file
87
pandatool/src/pfmprogs/pfmFile.h
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
// 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 ©);
|
||||||
|
void operator = (const PfmFile ©);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
NodePath generate_vis_points() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "pfmFile.I"
|
||||||
|
|
||||||
|
#endif
|
444
pandatool/src/pfmprogs/pfmTrans.cxx
Executable file
444
pandatool/src/pfmprogs/pfmTrans.cxx
Executable file
@ -0,0 +1,444 @@
|
|||||||
|
// Filename: pfmTrans.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 "pfmTrans.h"
|
||||||
|
#include "config_pfm.h"
|
||||||
|
#include "pfmFile.h"
|
||||||
|
#include "pystub.h"
|
||||||
|
#include "texture.h"
|
||||||
|
#include "texturePool.h"
|
||||||
|
#include "pointerTo.h"
|
||||||
|
#include "string_utils.h"
|
||||||
|
#include "pandaFileStream.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
PfmTrans::
|
||||||
|
PfmTrans() {
|
||||||
|
_got_transform = false;
|
||||||
|
_transform = LMatrix4f::ident_mat();
|
||||||
|
|
||||||
|
add_transform_options();
|
||||||
|
|
||||||
|
set_program_description
|
||||||
|
("pfm-trans reads an pfm file and transforms it, filters it, "
|
||||||
|
"operates on it, writing the output to another pfm file. A pfm "
|
||||||
|
"file contains a 2-d table of floating-point values.");
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("r", "", 0,
|
||||||
|
"Reverses the rows of the pfm data vertically.",
|
||||||
|
&PfmTrans::dispatch_none, &_got_reverse);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("z", "", 0,
|
||||||
|
"Treats (0,0,0) in the pfm file as a special don't-touch value.",
|
||||||
|
&PfmTrans::dispatch_none, &_got_zero_special);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("resize", "width,height", 0,
|
||||||
|
"Resamples the pfm file to scale it to the indicated grid size. "
|
||||||
|
"A simple box filter is applied during the scale. Don't confuse this "
|
||||||
|
"with -TS, which scales the individual point values, but doesn't "
|
||||||
|
"change the number of points.",
|
||||||
|
&PfmTrans::dispatch_int_pair, &_got_resize, &_resize);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("o", "filename", 50,
|
||||||
|
"Specify the filename to which the resulting pfm file will be written. "
|
||||||
|
"This is only valid when there is only one input pfm file on the command "
|
||||||
|
"line. If you want to process multiple files simultaneously, you must "
|
||||||
|
"use -d.",
|
||||||
|
&PfmTrans::dispatch_filename, &_got_output_filename, &_output_filename);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("d", "dirname", 50,
|
||||||
|
"Specify the name of the directory in which to write the processed pfm "
|
||||||
|
"files. If you are processing only one pfm file, this may be omitted "
|
||||||
|
"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 "
|
||||||
|
"as a 3-D geometric mesh. If -vistex is specified, the mesh is "
|
||||||
|
"textured.",
|
||||||
|
&PfmTrans::dispatch_filename, &_got_vis_filename, &_vis_filename);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("vistex", "texture.jpg", 60,
|
||||||
|
"Specifies the name of the texture to apply to the visualization.",
|
||||||
|
&PfmTrans::dispatch_filename, &_got_vistex_filename, &_vistex_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::run
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PfmTrans::
|
||||||
|
run() {
|
||||||
|
if (_got_vis_filename) {
|
||||||
|
_mesh_root = NodePath("mesh_root");
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_got_vis_filename) {
|
||||||
|
_mesh_root.write_bam_file(_vis_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::process_pfm
|
||||||
|
// Access: Public
|
||||||
|
// Description: Handles a single pfm file.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool PfmTrans::
|
||||||
|
process_pfm(const Filename &input_filename, PfmFile &file) {
|
||||||
|
file.set_zero_special(_got_zero_special);
|
||||||
|
|
||||||
|
if (_got_resize) {
|
||||||
|
file.resize(_resize[0], _resize[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_got_reverse) {
|
||||||
|
file.reverse_rows();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_got_transform) {
|
||||||
|
file.xform(_transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_got_vis_filename) {
|
||||||
|
NodePath mesh = file.generate_vis_points();
|
||||||
|
if (_got_vistex_filename) {
|
||||||
|
PT(Texture) tex = TexturePool::load_texture(_vistex_filename);
|
||||||
|
if (tex == NULL) {
|
||||||
|
nout << "Couldn't find " << _vistex_filename << "\n";
|
||||||
|
} else {
|
||||||
|
mesh.set_texture(tex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mesh.set_name(input_filename.get_basename_wo_extension());
|
||||||
|
mesh.reparent_to(_mesh_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
Filename output_filename;
|
||||||
|
if (_got_output_filename) {
|
||||||
|
output_filename = _output_filename;
|
||||||
|
} else if (_got_output_dirname) {
|
||||||
|
output_filename = Filename(_output_dirname, input_filename.get_basename());
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < bounds->get_num_points(); ++i) {
|
||||||
|
LPoint3f p = bounds->get_point(i);
|
||||||
|
out << p[0] << "," << p[1] << "," << p[2] << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file.write(output_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::add_transform_options
|
||||||
|
// Access: Public
|
||||||
|
// Description: Adds -TS, -TT, etc. as valid options for this
|
||||||
|
// program. If the user specifies one of the options on
|
||||||
|
// the command line, the data will be transformed when
|
||||||
|
// the egg file is written out.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PfmTrans::
|
||||||
|
add_transform_options() {
|
||||||
|
add_option
|
||||||
|
("TS", "sx[,sy,sz]", 49,
|
||||||
|
"Scale the model uniformly by the given factor (if only one number "
|
||||||
|
"is given) or in each axis by sx, sy, sz (if three numbers are given).",
|
||||||
|
&PfmTrans::dispatch_scale, &_got_transform, &_transform);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("TR", "x,y,z", 49,
|
||||||
|
"Rotate the model x degrees about the x axis, then y degrees about the "
|
||||||
|
"y axis, and then z degrees about the z axis.",
|
||||||
|
&PfmTrans::dispatch_rotate_xyz, &_got_transform, &_transform);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("TA", "angle,x,y,z", 49,
|
||||||
|
"Rotate the model angle degrees counterclockwise about the given "
|
||||||
|
"axis.",
|
||||||
|
&PfmTrans::dispatch_rotate_axis, &_got_transform, &_transform);
|
||||||
|
|
||||||
|
add_option
|
||||||
|
("TT", "x,y,z", 49,
|
||||||
|
"Translate the model by the indicated amount.\n\n"
|
||||||
|
"All transformation options (-TS, -TR, -TA, -TT) are cumulative and are "
|
||||||
|
"applied in the order they are encountered on the command line.",
|
||||||
|
&PfmTrans::dispatch_translate, &_got_transform, &_transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::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 PfmTrans::
|
||||||
|
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 (_got_output_filename && args.size() == 1) {
|
||||||
|
if (_got_output_dirname) {
|
||||||
|
nout << "Cannot specify both -o and -d.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::dispatch_scale
|
||||||
|
// Access: Protected, Static
|
||||||
|
// Description: Handles -TS, which specifies a scale transform. Var
|
||||||
|
// is an LMatrix4f.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool PfmTrans::
|
||||||
|
dispatch_scale(const string &opt, const string &arg, void *var) {
|
||||||
|
LMatrix4f *transform = (LMatrix4f *)var;
|
||||||
|
|
||||||
|
vector_string words;
|
||||||
|
tokenize(arg, words, ",");
|
||||||
|
|
||||||
|
float sx, sy, sz;
|
||||||
|
|
||||||
|
bool okflag = false;
|
||||||
|
if (words.size() == 3) {
|
||||||
|
okflag =
|
||||||
|
string_to_float(words[0], sx) &&
|
||||||
|
string_to_float(words[1], sy) &&
|
||||||
|
string_to_float(words[2], sz);
|
||||||
|
|
||||||
|
} else if (words.size() == 1) {
|
||||||
|
okflag =
|
||||||
|
string_to_float(words[0], sx);
|
||||||
|
sy = sz = sx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!okflag) {
|
||||||
|
nout << "-" << opt
|
||||||
|
<< " requires one or three numbers separated by commas.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*transform = (*transform) * LMatrix4f::scale_mat(sx, sy, sz);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::dispatch_rotate_xyz
|
||||||
|
// Access: Protected, Static
|
||||||
|
// Description: Handles -TR, which specifies a rotate transform about
|
||||||
|
// the three cardinal axes. Var is an LMatrix4f.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool PfmTrans::
|
||||||
|
dispatch_rotate_xyz(ProgramBase *self, const string &opt, const string &arg, void *var) {
|
||||||
|
PfmTrans *base = (PfmTrans *)self;
|
||||||
|
return base->ns_dispatch_rotate_xyz(opt, arg, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::ns_dispatch_rotate_xyz
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Handles -TR, which specifies a rotate transform about
|
||||||
|
// the three cardinal axes. Var is an LMatrix4f.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool PfmTrans::
|
||||||
|
ns_dispatch_rotate_xyz(const string &opt, const string &arg, void *var) {
|
||||||
|
LMatrix4f *transform = (LMatrix4f *)var;
|
||||||
|
|
||||||
|
vector_string words;
|
||||||
|
tokenize(arg, words, ",");
|
||||||
|
|
||||||
|
LVecBase3f xyz;
|
||||||
|
|
||||||
|
bool okflag = false;
|
||||||
|
if (words.size() == 3) {
|
||||||
|
okflag =
|
||||||
|
string_to_float(words[0], xyz[0]) &&
|
||||||
|
string_to_float(words[1], xyz[1]) &&
|
||||||
|
string_to_float(words[2], xyz[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!okflag) {
|
||||||
|
nout << "-" << opt
|
||||||
|
<< " requires three numbers separated by commas.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LMatrix4f mat =
|
||||||
|
LMatrix4f::rotate_mat(xyz[0], LVector3f(1.0, 0.0, 0.0)) *
|
||||||
|
LMatrix4f::rotate_mat(xyz[1], LVector3f(0.0, 1.0, 0.0)) *
|
||||||
|
LMatrix4f::rotate_mat(xyz[2], LVector3f(0.0, 0.0, 1.0));
|
||||||
|
|
||||||
|
*transform = (*transform) * mat;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::dispatch_rotate_axis
|
||||||
|
// Access: Protected, Static
|
||||||
|
// Description: Handles -TA, which specifies a rotate transform about
|
||||||
|
// an arbitrary axis. Var is an LMatrix4f.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool PfmTrans::
|
||||||
|
dispatch_rotate_axis(ProgramBase *self, const string &opt, const string &arg, void *var) {
|
||||||
|
PfmTrans *base = (PfmTrans *)self;
|
||||||
|
return base->ns_dispatch_rotate_axis(opt, arg, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::ns_dispatch_rotate_axis
|
||||||
|
// Access: Protected
|
||||||
|
// Description: Handles -TA, which specifies a rotate transform about
|
||||||
|
// an arbitrary axis. Var is an LMatrix4f.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool PfmTrans::
|
||||||
|
ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var) {
|
||||||
|
LMatrix4f *transform = (LMatrix4f *)var;
|
||||||
|
|
||||||
|
vector_string words;
|
||||||
|
tokenize(arg, words, ",");
|
||||||
|
|
||||||
|
float angle;
|
||||||
|
LVecBase3f axis;
|
||||||
|
|
||||||
|
bool okflag = false;
|
||||||
|
if (words.size() == 4) {
|
||||||
|
okflag =
|
||||||
|
string_to_float(words[0], angle) &&
|
||||||
|
string_to_float(words[1], axis[0]) &&
|
||||||
|
string_to_float(words[2], axis[1]) &&
|
||||||
|
string_to_float(words[3], axis[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!okflag) {
|
||||||
|
nout << "-" << opt
|
||||||
|
<< " requires four numbers separated by commas.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*transform = (*transform) * LMatrix4f::rotate_mat(angle, axis);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PfmTrans::dispatch_translate
|
||||||
|
// Access: Protected, Static
|
||||||
|
// Description: Handles -TT, which specifies a translate transform.
|
||||||
|
// Var is an LMatrix4f.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool PfmTrans::
|
||||||
|
dispatch_translate(const string &opt, const string &arg, void *var) {
|
||||||
|
LMatrix4f *transform = (LMatrix4f *)var;
|
||||||
|
|
||||||
|
vector_string words;
|
||||||
|
tokenize(arg, words, ",");
|
||||||
|
|
||||||
|
LVector3f trans;
|
||||||
|
|
||||||
|
bool okflag = false;
|
||||||
|
if (words.size() == 3) {
|
||||||
|
okflag =
|
||||||
|
string_to_float(words[0], trans[0]) &&
|
||||||
|
string_to_float(words[1], trans[1]) &&
|
||||||
|
string_to_float(words[2], trans[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!okflag) {
|
||||||
|
nout << "-" << opt
|
||||||
|
<< " requires three numbers separated by commas.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*transform = (*transform) * LMatrix4f::translate_mat(trans);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
// A call to pystub() to force libpystub.so to be linked in.
|
||||||
|
pystub();
|
||||||
|
|
||||||
|
PfmTrans prog;
|
||||||
|
prog.parse_command_line(argc, argv);
|
||||||
|
prog.run();
|
||||||
|
return 0;
|
||||||
|
}
|
75
pandatool/src/pfmprogs/pfmTrans.h
Executable file
75
pandatool/src/pfmprogs/pfmTrans.h
Executable file
@ -0,0 +1,75 @@
|
|||||||
|
// Filename: pfmTrans.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 PFMTRANS_H
|
||||||
|
#define PFMTRANS_H
|
||||||
|
|
||||||
|
#include "pandatoolbase.h"
|
||||||
|
#include "programBase.h"
|
||||||
|
#include "filename.h"
|
||||||
|
#include "pvector.h"
|
||||||
|
#include "nodePath.h"
|
||||||
|
#include "luse.h"
|
||||||
|
|
||||||
|
class PfmFile;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : PfmTrans
|
||||||
|
// Description : Operates on a pfm file.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class PfmTrans : public ProgramBase {
|
||||||
|
public:
|
||||||
|
PfmTrans();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
bool process_pfm(const Filename &input_filename, PfmFile &file);
|
||||||
|
|
||||||
|
void add_transform_options();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool handle_args(Args &args);
|
||||||
|
|
||||||
|
static bool dispatch_scale(const string &opt, const string &arg, void *var);
|
||||||
|
static bool dispatch_rotate_xyz(ProgramBase *self, const string &opt, const string &arg, void *var);
|
||||||
|
bool ns_dispatch_rotate_xyz(const string &opt, const string &arg, void *var);
|
||||||
|
static bool dispatch_rotate_axis(ProgramBase *self, const string &opt, const string &arg, void *var);
|
||||||
|
bool ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var);
|
||||||
|
static bool dispatch_translate(const string &opt, const string &arg, void *var);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef pvector<Filename> Filenames;
|
||||||
|
Filenames _input_filenames;
|
||||||
|
|
||||||
|
bool _got_reverse;
|
||||||
|
bool _got_zero_special;
|
||||||
|
bool _got_resize;
|
||||||
|
int _resize[2];
|
||||||
|
bool _got_bba;
|
||||||
|
|
||||||
|
bool _got_output_filename;
|
||||||
|
Filename _output_filename;
|
||||||
|
bool _got_output_dirname;
|
||||||
|
Filename _output_dirname;
|
||||||
|
bool _got_vis_filename;
|
||||||
|
Filename _vis_filename;
|
||||||
|
bool _got_vistex_filename;
|
||||||
|
Filename _vistex_filename;
|
||||||
|
|
||||||
|
bool _got_transform;
|
||||||
|
LMatrix4f _transform;
|
||||||
|
|
||||||
|
NodePath _mesh_root;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user