fix build circularity issue

This commit is contained in:
David Rose 2012-10-01 00:40:56 +00:00
parent 25870f099f
commit 8e3e89b5b3
12 changed files with 1070 additions and 971 deletions

View File

@ -25,6 +25,7 @@
lineSegs.I lineSegs.h \
multitexReducer.I multitexReducer.h multitexReducer.cxx \
nodeVertexTransform.I nodeVertexTransform.h \
pfmVizzer.I pfmVizzer.h \
rigidBodyCombiner.I rigidBodyCombiner.h
#define INCLUDED_SOURCES \
@ -39,6 +40,7 @@
sceneGraphAnalyzerMeter.cxx \
heightfieldTesselator.cxx \
nodeVertexTransform.cxx \
pfmVizzer.cxx \
pipeOcclusionCullTraverser.cxx \
lineSegs.cxx \
rigidBodyCombiner.cxx
@ -56,6 +58,7 @@
lineSegs.I lineSegs.h \
multitexReducer.I multitexReducer.h \
nodeVertexTransform.I nodeVertexTransform.h \
pfmVizzer.I pfmVizzer.h \
rigidBodyCombiner.I rigidBodyCombiner.h
#define IGATESCAN all

View File

@ -72,6 +72,18 @@ ConfigVariableBool movies_sync_pages
"such as cube maps, 3-d textures, or stereo textures, or textures "
"with separate color and alpha channel movie sources."));
ConfigVariableInt pfm_vis_max_vertices
("pfm-vis-max-vertices", 65535,
PRC_DESC("Specifies the maximum number of vertex entries that may appear in "
"a single generated mesh. If the mesh would require more than that, "
"the mesh is subdivided into smaller pieces."));
ConfigVariableInt pfm_vis_max_indices
("pfm-vis-max-indices", 1048576,
PRC_DESC("Specifies the maximum number of vertex references that may appear in "
"a single generated mesh. If the mesh would require more than that, "
"the mesh is subdivided into smaller pieces."));
////////////////////////////////////////////////////////////////////
// Function: init_libgrutil
// Description: Initializes the library. This must be called at

View File

@ -37,6 +37,9 @@ extern ConfigVariableDouble scene_graph_analyzer_meter_side_margins;
extern ConfigVariableBool movies_sync_pages;
extern ConfigVariableInt pfm_vis_max_vertices;
extern ConfigVariableInt pfm_vis_max_indices;
extern EXPCL_PANDA_GRUTIL void init_libgrutil();
#endif

View File

@ -1,6 +1,8 @@
#include "meshDrawer.cxx"
#include "meshDrawer2D.cxx"
#include "movieTexture.cxx"
#include "nodeVertexTransform.cxx"
#include "pipeOcclusionCullTraverser.cxx"
#include "pfmVizzer.cxx"
#include "rigidBodyCombiner.cxx"
#include "meshDrawer.cxx"
#include "meshDrawer2D.cxx"

View File

@ -0,0 +1,182 @@
// Filename: pfmVizzer.I
// Created by: drose (30Sep12)
//
////////////////////////////////////////////////////////////////////
//
// 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: PfmVizzer::get_pfm
// Access: Published
// Description: Returns the reference to the PfmFile manipulated by
// thiz PfmVizzer.
////////////////////////////////////////////////////////////////////
INLINE PfmFile &PfmVizzer::
get_pfm() {
return _pfm;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::get_pfm
// Access: Published
// Description: Returns the reference to the PfmFile manipulated by
// thiz PfmVizzer.
////////////////////////////////////////////////////////////////////
INLINE const PfmFile &PfmVizzer::
get_pfm() const {
return _pfm;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::set_vis_inverse
// Access: Published
// 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.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmVizzer::
set_vis_inverse(bool vis_inverse) {
_vis_inverse = vis_inverse;
clear_vis_columns();
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::get_vis_inverse
// Access: Published
// Description: Returns the vis_inverse flag. See set_vis_inverse().
////////////////////////////////////////////////////////////////////
INLINE bool PfmVizzer::
get_vis_inverse() const {
return _vis_inverse;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::set_flat_texcoord_name
// Access: Published
// Description: If the flat_texcoord_name is specified, it is the
// name of an additional vertex column that will be
// created for the "flat" texture coordinates, i.e. the
// original 0..1 values that correspond to the 2-D index
// position of each point in the original pfm file.
//
// These are the same values that will be assigned to
// the default texture coordinates if the vis_inverse
// flag is *not* true.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmVizzer::
set_flat_texcoord_name(InternalName *flat_texcoord_name) {
_flat_texcoord_name = flat_texcoord_name;
clear_vis_columns();
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::clear_flat_texcoord_name
// Access: Published
// Description: Resets the flat_texcoord_name to empty, so that
// additional texture coordinates are not created.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmVizzer::
clear_flat_texcoord_name() {
_flat_texcoord_name = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::get_flat_texcoord_name
// Access: Published
// Description: Returns the flat_texcoord_name. See set_flat_texcoord_name().
////////////////////////////////////////////////////////////////////
INLINE InternalName *PfmVizzer::
get_flat_texcoord_name() const {
return _flat_texcoord_name;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::set_vis_2d
// Access: Published
// Description: Sets the vis_2d flag. When this flag is true,
// only the first two (x, y) value of each depth point
// is considered meaningful; the z component is ignored.
// This is only relevant for generating visualizations.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmVizzer::
set_vis_2d(bool vis_2d) {
_vis_2d = vis_2d;
clear_vis_columns();
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::get_vis_2d
// Access: Published
// Description: Returns the vis_2d flag. See set_vis_2d().
////////////////////////////////////////////////////////////////////
INLINE bool PfmVizzer::
get_vis_2d() const {
return _vis_2d;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::set_vis_blend
// Access: Published
// Description: Specifies a blending map--a grayscale image--that
// will be applied to the vertex color during
// generate_vis_mesh() and generate_vis_points(). The
// image size must exactly match the mesh size of the
// PfmVizzer.
//
// Ownership of the pointer is not kept by the PfmVizzer;
// it is your responsibility to ensure it does not
// destruct during the lifetime of the PfmVizzer (or at
// least not before your subsequent call to
// generate_vis_mesh()).
////////////////////////////////////////////////////////////////////
INLINE void PfmVizzer::
set_vis_blend(const PNMImage *vis_blend) {
_vis_blend = vis_blend;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::set_vis_blend
// Access: Published
// Description: Removes the blending map set by a prior call to
// set_vis_blend().
////////////////////////////////////////////////////////////////////
INLINE void PfmVizzer::
clear_vis_blend() {
_vis_blend = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::get_vis_blend
// Access: Published
// Description: Returns the blending map set by the most recent call
// to set_vis_blend(), or NULL if there is no blending
// map in effect.
////////////////////////////////////////////////////////////////////
INLINE const PNMImage *PfmVizzer::
get_vis_blend() const {
return _vis_blend;
}

View File

@ -0,0 +1,743 @@
// Filename: pfmVizzer.cxx
// Created by: drose (30Sep12)
//
////////////////////////////////////////////////////////////////////
//
// 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 "pfmVizzer.h"
#include "geomNode.h"
#include "geom.h"
#include "geomVertexData.h"
#include "geomVertexFormat.h"
#include "geomPoints.h"
#include "geomTriangles.h"
#include "geomVertexWriter.h"
#include "lens.h"
#include "config_grutil.h"
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::Constructor
// Access: Published
// Description: The PfmVizzer constructor receives a reference to a
// PfmFile which it will operate on. It does not keep
// ownership of this reference; it is your
// responsibility to ensure the PfmFile does not
// destruct during the lifetime of the PfmVizzer.
////////////////////////////////////////////////////////////////////
PfmVizzer::
PfmVizzer(PfmFile &pfm) : _pfm(pfm) {
_vis_inverse = false;
_vis_2d = false;
_vis_blend = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::project
// Access: Published
// Description: Adjusts each (x, y, z) point of the Pfm file by
// projecting it through the indicated lens, converting
// each point to a (u, v, w) texture coordinate. The
// resulting file can be generated to a mesh (with
// set_vis_inverse(true) and generate_vis_mesh())
// that will apply the lens distortion to an arbitrary
// texture image.
////////////////////////////////////////////////////////////////////
void PfmVizzer::
project(const Lens *lens) {
nassertv(_pfm.is_valid());
static LMatrix4f to_uv(0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f);
for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
LPoint3f &p = _pfm.modify_point(xi, yi);
LPoint3 film;
lens->project(LCAST(PN_stdfloat, p), film);
p = to_uv.xform_point(LCAST(PN_float32, film));
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::extrude
// Access: Published
// Description: Converts each (u, v, depth) point of the Pfm file to
// an (x, y, z) point, by reversing project(). If the
// original file is only a 1-d file, assumes that it is
// a depth map with implicit (u, v) coordinates.
//
// This method is only valid for a linear lens (e.g. a
// PerspectiveLens or OrthographicLens). Non-linear
// lenses don't necessarily compute a sensible depth
// coordinate.
////////////////////////////////////////////////////////////////////
void PfmVizzer::
extrude(const Lens *lens) {
nassertv(_pfm.is_valid());
nassertv(lens->is_linear());
static LMatrix4 from_uv(2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, -1.0, 1.0);
const LMatrix4 &proj_mat_inv = lens->get_projection_mat_inv();
PfmFile result;
result.clear(_pfm.get_x_size(), _pfm.get_y_size(), 3);
result.set_zero_special(true);
if (_pfm.get_num_channels() == 1) {
// Create an implicit UV coordinate for each point.
LPoint2 uv_scale(1.0, 1.0);
if (_pfm.get_x_size() > 1) {
uv_scale[0] = 1.0 / PN_stdfloat(_pfm.get_x_size() - 1);
}
if (_pfm.get_y_size() > 1) {
uv_scale[1] = 1.0 / PN_stdfloat(_pfm.get_y_size() - 1);
}
for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
LPoint3 p;
p.set((PN_stdfloat)xi * uv_scale[0],
(PN_stdfloat)yi * uv_scale[1],
(PN_stdfloat)_pfm.get_point1(xi, yi));
from_uv.xform_point_in_place(p);
proj_mat_inv.xform_point_general_in_place(p);
result.set_point(xi, yi, p);
}
}
} else {
// Use the existing UV coordinate for each point.
for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
LPoint3 p;
p = LCAST(PN_stdfloat, _pfm.get_point(xi, yi));
from_uv.xform_point_in_place(p);
proj_mat_inv.xform_point_general_in_place(p);
result.set_point(xi, yi, p);
}
}
}
_pfm = result;
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::clear_vis_columns
// Access: Published
// Description: Removes all of the previously-added vis columns in
// preparation for building a new list. See
// add_vis_column().
////////////////////////////////////////////////////////////////////
void PfmVizzer::
clear_vis_columns() {
_vis_columns.clear();
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::add_vis_column
// Access: Published
// Description: Adds a new vis column specification to the list of
// vertex data columns that will be generated at the
// next call to generate_vis_points() or
// generate_vis_mesh(). This advanced interface
// supercedes the higher-level set_vis_inverse(),
// set_flat_texcoord_name(), and set_vis_2d().
//
// If you use this advanced interface, you must specify
// explicitly the complete list of data columns to be
// created in the resulting GeomVertexData, by calling
// add_vis_column() each time. For each column, you
// specify the source of the column in the PFMFile, the
// target column and name in the GeomVertexData, and an
// optional transform matrix and/or lens to transform
// and project the point before generating it.
////////////////////////////////////////////////////////////////////
void PfmVizzer::
add_vis_column(ColumnType source, ColumnType target,
InternalName *name, const TransformState *transform,
const Lens *lens) {
add_vis_column(_vis_columns, source, target, name, transform, lens);
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::generate_vis_points
// Access: Published
// 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 PfmVizzer::
generate_vis_points() const {
nassertr(_pfm.is_valid(), NodePath());
CPT(GeomVertexFormat) format;
if (_vis_inverse) {
if (_vis_2d) {
format = GeomVertexFormat::get_v3t2();
} else {
// We need a 3-d texture coordinate if we're inverting the vis
// and it's 3-d.
GeomVertexArrayFormat *v3t3 = new GeomVertexArrayFormat
(InternalName::get_vertex(), 3,
Geom::NT_stdfloat, Geom::C_point,
InternalName::get_texcoord(), 3,
Geom::NT_stdfloat, 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(_pfm.get_x_size() * _pfm.get_y_size());
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
LPoint2f uv_scale(1.0, 1.0);
if (_pfm.get_x_size() > 1) {
uv_scale[0] = 1.0f / PN_float32(_pfm.get_x_size() - 1);
}
if (_pfm.get_y_size() > 1) {
uv_scale[1] = 1.0f / PN_float32(_pfm.get_y_size() - 1);
}
int num_points = 0;
for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
if (!_pfm.has_point(xi, yi)) {
continue;
}
const LPoint3f &point = _pfm.get_point(xi, yi);
LPoint2f uv(PN_float32(xi) * uv_scale[0],
PN_float32(yi) * uv_scale[1]);
if (_vis_inverse) {
vertex.add_data2f(uv);
texcoord.add_data3f(point);
} else if (_vis_2d) {
vertex.add_data2f(point[0], point[1]);
texcoord.add_data2f(uv);
} else {
vertex.add_data3f(point);
texcoord.add_data2f(uv);
}
++num_points;
}
}
PT(Geom) geom = new Geom(vdata);
PT(GeomPoints) points = new GeomPoints(Geom::UH_static);
points->add_next_vertices(num_points);
geom->add_primitive(points);
PT(GeomNode) gnode = new GeomNode("");
gnode->add_geom(geom);
return NodePath(gnode);
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::generate_vis_mesh
// Access: Published
// 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 PfmVizzer::
generate_vis_mesh(MeshFace face) const {
nassertr(_pfm.is_valid(), NodePath());
nassertr(face != 0, NodePath());
if (_pfm.get_num_channels() == 1 && _vis_columns.empty()) {
// If we're generating a default mesh from a one-channel pfm file,
// expand it to a three-channel pfm file to make the visualization
// useful.
PfmFile expanded;
expanded.clear_to_texcoords(_pfm.get_x_size(), _pfm.get_y_size());
expanded.copy_channel(2, _pfm, 0);
PfmVizzer exvizzer(expanded);
return exvizzer.generate_vis_mesh(face);
}
if (_pfm.get_x_size() == 1 || _pfm.get_y_size() == 1) {
// Can't generate a 1-d mesh, so generate points in this case.
return generate_vis_points();
}
PT(GeomNode) gnode = new GeomNode("");
if (face & MF_front) {
make_vis_mesh_geom(gnode, false);
}
if (face & MF_back) {
make_vis_mesh_geom(gnode, true);
}
return NodePath(gnode);
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::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.
////////////////////////////////////////////////////////////////////
void PfmVizzer::
make_vis_mesh_geom(GeomNode *gnode, bool inverted) const {
int num_x_cells = 1;
int num_y_cells = 1;
int x_size = _pfm.get_x_size();
int y_size = _pfm.get_y_size();
// This is the number of independent vertices we will require.
int num_vertices = x_size * y_size;
if (num_vertices == 0) {
// Trivial no-op.
return;
}
bool reverse_normals = inverted;
bool reverse_faces = inverted;
if (!is_right_handed(get_default_coordinate_system())) {
reverse_faces = !reverse_faces;
}
// This is the max number of vertex indices we might add to the
// GeomTriangles. (We might actually add fewer than this due to
// omitting the occasional missing data point.)
int max_indices = (x_size - 1) * (y_size - 1) * 6;
while (num_vertices > pfm_vis_max_vertices || max_indices > pfm_vis_max_indices) {
// Too many vertices in one mesh. Subdivide the mesh into smaller
// pieces.
if (num_x_cells > num_y_cells) {
++num_y_cells;
} else {
++num_x_cells;
}
x_size = (_pfm.get_x_size() + num_x_cells - 1) / num_x_cells + 1;
y_size = (_pfm.get_y_size() + num_y_cells - 1) / num_y_cells + 1;
num_vertices = x_size * y_size;
max_indices = (x_size - 1) * (y_size - 1) * 6;
}
// OK, now we know how many cells we need.
if (grutil_cat.is_debug()) {
grutil_cat.debug()
<< "Generating mesh with " << num_x_cells << " x " << num_y_cells
<< " pieces.\n";
}
VisColumns vis_columns = _vis_columns;
if (vis_columns.empty()) {
build_auto_vis_columns(vis_columns, true);
}
CPT(GeomVertexFormat) format = make_array_format(vis_columns);
for (int yci = 0; yci < num_y_cells; ++yci) {
int y_begin = (yci * _pfm.get_y_size()) / num_y_cells;
int y_end = ((yci + 1) * _pfm.get_y_size()) / num_y_cells;
// Include the first vertex from the next strip in this strip's
// vertices, so we are connected.
y_end = min(y_end + 1, _pfm.get_y_size());
y_size = y_end - y_begin;
if (y_size == 0) {
continue;
}
for (int xci = 0; xci < num_x_cells; ++xci) {
int x_begin = (xci * _pfm.get_x_size()) / num_x_cells;
int x_end = ((xci + 1) * _pfm.get_x_size()) / num_x_cells;
x_end = min(x_end + 1, _pfm.get_x_size());
x_size = x_end - x_begin;
if (x_size == 0) {
continue;
}
num_vertices = x_size * y_size;
max_indices = (x_size - 1) * (y_size - 1) * 6;
ostringstream mesh_name;
mesh_name << "mesh_" << xci << "_" << yci;
PT(GeomVertexData) vdata = new GeomVertexData
(mesh_name.str(), format, Geom::UH_static);
vdata->set_num_rows(num_vertices);
// Fill in all of the vertices.
for (VisColumns::const_iterator vci = vis_columns.begin();
vci != vis_columns.end();
++vci) {
const VisColumn &column = *vci;
GeomVertexWriter vwriter(vdata, column._name);
vwriter.set_row(0);
for (int yi = y_begin; yi < y_end; ++yi) {
for (int xi = x_begin; xi < x_end; ++xi) {
column.add_data(*this, vwriter, xi, yi, reverse_normals);
}
}
}
PT(Geom) geom = new Geom(vdata);
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
tris->reserve_num_vertices(max_indices);
for (int yi = y_begin; yi < y_end - 1; ++yi) {
for (int xi = x_begin; xi < x_end - 1; ++xi) {
if (_pfm.has_no_data_value()) {
if (!_pfm.has_point(xi, yi) ||
!_pfm.has_point(xi, yi + 1) ||
!_pfm.has_point(xi + 1, yi + 1) ||
!_pfm.has_point(xi + 1, yi)) {
continue;
}
}
int xi0 = xi - x_begin;
int yi0 = yi - y_begin;
int vi0 = ((xi0) + (yi0) * x_size);
int vi1 = ((xi0) + (yi0 + 1) * x_size);
int vi2 = ((xi0 + 1) + (yi0 + 1) * x_size);
int vi3 = ((xi0 + 1) + (yi0) * x_size);
if (reverse_faces) {
tris->add_vertices(vi2, vi0, vi1);
tris->close_primitive();
tris->add_vertices(vi3, vi0, vi2);
tris->close_primitive();
} else {
tris->add_vertices(vi2, vi1, vi0);
tris->close_primitive();
tris->add_vertices(vi3, vi2, vi0);
tris->close_primitive();
}
}
}
geom->add_primitive(tris);
gnode->add_geom(geom);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::add_vis_column
// Access: Private, Static
// Description: The private implementation of the public
// add_vis_column(), this adds the column to the
// indicated specific vector.
////////////////////////////////////////////////////////////////////
void PfmVizzer::
add_vis_column(VisColumns &vis_columns, ColumnType source, ColumnType target,
InternalName *name, const TransformState *transform,
const Lens *lens) {
VisColumn column;
column._source = source;
column._target = target;
column._name = name;
column._transform = transform;
if (transform == NULL) {
column._transform = TransformState::make_identity();
}
column._lens = lens;
vis_columns.push_back(column);
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::build_auto_vis_columns
// Access: Private
// Description: This function is called internally to construct the
// list of vis_columns automatically from the high-level
// interfaces such as set_vis_inverse(),
// set_flat_texcoord_name(), and set_vis_2d(). It's not
// called if the list has been build explicitly.
////////////////////////////////////////////////////////////////////
void PfmVizzer::
build_auto_vis_columns(VisColumns &vis_columns, bool for_points) const {
vis_columns.clear();
if (_vis_2d) {
// No normals needed if we're just generating a 2-d mesh.
if (_vis_inverse) {
add_vis_column(vis_columns, CT_texcoord2, CT_vertex2, InternalName::get_vertex());
add_vis_column(vis_columns, CT_vertex2, CT_texcoord2, InternalName::get_texcoord());
} else {
add_vis_column(vis_columns, CT_vertex2, CT_vertex2, InternalName::get_vertex());
add_vis_column(vis_columns, CT_texcoord2, CT_texcoord2, InternalName::get_texcoord());
}
} else {
if (_vis_inverse) {
// We need a 3-d texture coordinate if we're inverting the vis
// and it's 3-d. But we still don't need normals in that case.
add_vis_column(vis_columns, CT_texcoord3, CT_vertex3, InternalName::get_vertex());
add_vis_column(vis_columns, CT_vertex3, CT_texcoord3, InternalName::get_texcoord());
} else {
// Otherwise, we only need a 2-d texture coordinate, and we do
// want normals.
add_vis_column(vis_columns, CT_vertex3, CT_vertex3, InternalName::get_vertex());
add_vis_column(vis_columns, CT_normal3, CT_normal3, InternalName::get_normal());
add_vis_column(vis_columns, CT_texcoord2, CT_texcoord2, InternalName::get_texcoord());
}
}
if (_flat_texcoord_name != (InternalName *)NULL) {
// We need an additional texcoord column for the flat texcoords.
add_vis_column(vis_columns, CT_texcoord2, CT_texcoord2, _flat_texcoord_name);
}
if (_vis_blend != (PNMImage *)NULL) {
// The blend map, if specified, also gets applied to the vertices.
add_vis_column(vis_columns, CT_blend1, CT_blend1, InternalName::get_color());
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::make_array_format
// Access: Private
// Description: Constructs a GeomVertexFormat that corresponds to the
// vis_columns list.
////////////////////////////////////////////////////////////////////
CPT(GeomVertexFormat) PfmVizzer::
make_array_format(const VisColumns &vis_columns) const {
PT(GeomVertexArrayFormat) array_format = new GeomVertexArrayFormat;
for (VisColumns::const_iterator vci = vis_columns.begin();
vci != vis_columns.end();
++vci) {
const VisColumn &column = *vci;
InternalName *name = column._name;
int num_components = 0;
GeomEnums::NumericType numeric_type = GeomEnums::NT_float32;
GeomEnums::Contents contents = GeomEnums::C_point;
switch (column._target) {
case CT_texcoord2:
num_components = 2;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_texcoord;
break;
case CT_texcoord3:
num_components = 3;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_texcoord;
break;
case CT_vertex1:
case CT_vertex2:
case CT_vertex3:
num_components = 3;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_point;
break;
case CT_normal3:
num_components = 3;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_vector;
break;
case CT_blend1:
num_components = 4;
numeric_type = GeomEnums::NT_uint8;
contents = GeomEnums::C_color;
break;
}
nassertr(num_components != 0, NULL);
array_format->add_column(name, num_components, numeric_type, contents);
}
return GeomVertexFormat::register_format(array_format);
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::VisColumn::add_data
// Access: Public
// Description: Adds the data for this column to the appropriate
// column of the GeomVertexWriter.
////////////////////////////////////////////////////////////////////
void PfmVizzer::VisColumn::
add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, bool reverse_normals) const {
const PfmFile &pfm = vizzer.get_pfm();
switch (_source) {
case CT_texcoord2:
{
LPoint2f uv(PN_float32(xi) / PN_float32(pfm.get_x_size() - 1),
PN_float32(yi) / PN_float32(pfm.get_y_size() - 1));
transform_point(uv);
vwriter.set_data2f(uv);
}
break;
case CT_texcoord3:
{
LPoint3f uv(PN_float32(xi) / PN_float32(pfm.get_x_size() - 1),
PN_float32(yi) / PN_float32(pfm.get_y_size() - 1),
0.0f);
transform_point(uv);
vwriter.set_data3f(uv);
}
break;
case CT_vertex1:
{
PN_float32 p = pfm.get_point1(xi, yi);
LPoint2f point(p, 0.0);
transform_point(point);
vwriter.set_data2f(point);
}
break;
case CT_vertex2:
{
LPoint2f point = pfm.get_point2(xi, yi);
transform_point(point);
vwriter.set_data2f(point);
}
break;
case CT_vertex3:
{
LPoint3f point = pfm.get_point(xi, yi);
transform_point(point);
vwriter.set_data3f(point);
}
break;
case CT_normal3:
{
// Calculate the normal based on two neighboring vertices.
LPoint3f v[3];
v[0] = pfm.get_point(xi, yi);
if (xi + 1 < pfm.get_x_size()) {
v[1] = pfm.get_point(xi + 1, yi);
} else {
v[1] = v[0];
v[0] = pfm.get_point(xi - 1, yi);
}
if (yi + 1 < pfm.get_y_size()) {
v[2] = pfm.get_point(xi, yi + 1);
} else {
v[2] = v[0];
v[0] = pfm.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();
nassertv(!n.is_nan());
if (reverse_normals) {
n = -n;
}
transform_vector(n);
vwriter.set_data3f(n);
}
break;
case CT_blend1:
{
const PNMImage *vis_blend = vizzer.get_vis_blend();
if (vis_blend != NULL) {
double gray = vis_blend->get_gray(xi, yi);
vwriter.set_data3d(gray, gray, gray);
}
}
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::VisColumn::transform_point
// Access: Public
// Description: Transforms the indicated point as specified by the
// VisColumn.
////////////////////////////////////////////////////////////////////
void PfmVizzer::VisColumn::
transform_point(LPoint2f &point) const {
if (!_transform->is_identity()) {
LCAST(PN_float32, _transform->get_mat3()).xform_point_in_place(point);
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::VisColumn::transform_point
// Access: Public
// Description: Transforms the indicated point as specified by the
// VisColumn.
////////////////////////////////////////////////////////////////////
void PfmVizzer::VisColumn::
transform_point(LPoint3f &point) const {
if (!_transform->is_identity()) {
LCAST(PN_float32, _transform->get_mat()).xform_point_in_place(point);
}
if (_lens != (Lens *)NULL) {
static LMatrix4f to_uv(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.5, 0.5, 0.0, 1.0);
LPoint3 film;
_lens->project(LCAST(PN_stdfloat, point), film);
point = to_uv.xform_point(LCAST(PN_float32, film));
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmVizzer::VisColumn::transform_vector
// Access: Public
// Description: Transforms the indicated vector as specified by the
// VisColumn.
////////////////////////////////////////////////////////////////////
void PfmVizzer::VisColumn::
transform_vector(LVector3f &vec) const {
if (!_transform->is_identity()) {
LCAST(PN_float32, _transform->get_mat()).xform_vec_in_place(vec);
}
}

View File

@ -0,0 +1,120 @@
// Filename: pfmVizzer.h
// Created by: drose (30Sep12)
//
////////////////////////////////////////////////////////////////////
//
// 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 PFMVIZZER_H
#define PFMVIZZER_H
#include "pandabase.h"
#include "nodePath.h"
#include "internalName.h"
#include "lens.h"
#include "pfmFile.h"
class GeomNode;
class Lens;
class GeomVertexWriter;
////////////////////////////////////////////////////////////////////
// Class : PfmVizzer
// Description : This class aids in the visualization and manipulation
// of PfmFile objects.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_GRUTIL PfmVizzer {
PUBLISHED:
PfmVizzer(PfmFile &pfm);
INLINE PfmFile &get_pfm();
INLINE const PfmFile &get_pfm() const;
BLOCKING void project(const Lens *lens);
BLOCKING void extrude(const Lens *lens);
INLINE void set_vis_inverse(bool vis_inverse);
INLINE bool get_vis_inverse() const;
INLINE void set_flat_texcoord_name(InternalName *flat_texcoord_name);
INLINE void clear_flat_texcoord_name();
INLINE InternalName *get_flat_texcoord_name() const;
INLINE void set_vis_2d(bool vis_2d);
INLINE bool get_vis_2d() const;
INLINE void set_vis_blend(const PNMImage *vis_blend);
INLINE void clear_vis_blend();
INLINE const PNMImage *get_vis_blend() const;
enum ColumnType {
CT_texcoord2,
CT_texcoord3,
CT_vertex1,
CT_vertex2,
CT_vertex3,
CT_normal3,
CT_blend1,
};
void clear_vis_columns();
void add_vis_column(ColumnType source, ColumnType target,
InternalName *name,
const TransformState *transform = NULL, const Lens *lens = NULL);
BLOCKING NodePath generate_vis_points() const;
enum MeshFace {
MF_front = 0x01,
MF_back = 0x02,
MF_both = 0x03,
};
BLOCKING NodePath generate_vis_mesh(MeshFace face = MF_front) const;
private:
void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
class VisColumn {
public:
void add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, bool reverse_normals) const;
void transform_point(LPoint2f &point) const;
void transform_point(LPoint3f &point) const;
void transform_vector(LVector3f &vec) const;
public:
ColumnType _source;
ColumnType _target;
PT(InternalName) _name;
CPT(TransformState) _transform;
CPT(Lens) _lens;
};
typedef pvector<VisColumn> VisColumns;
static void add_vis_column(VisColumns &vis_columns,
ColumnType source, ColumnType target,
InternalName *name,
const TransformState *transform = NULL, const Lens *lens = NULL);
void build_auto_vis_columns(VisColumns &vis_columns, bool for_points) const;
CPT(GeomVertexFormat) make_array_format(const VisColumns &vis_columns) const;
private:
PfmFile &_pfm;
bool _vis_inverse;
PT(InternalName) _flat_texcoord_name;
bool _vis_2d;
const PNMImage *_vis_blend;
VisColumns _vis_columns;
friend class VisColumn;
};
#include "pfmVizzer.I"
#endif

View File

@ -36,18 +36,6 @@ ConfigVariableBool pfm_reverse_dimensions
"backwards, in the form height width instead of width height, "
"on input. Does not affect output, which is always written width height."));
ConfigVariableInt pfm_vis_max_vertices
("pfm-vis-max-vertices", 65535,
PRC_DESC("Specifies the maximum number of vertex entries that may appear in "
"a single generated mesh. If the mesh would require more than that, "
"the mesh is subdivided into smaller pieces."));
ConfigVariableInt pfm_vis_max_indices
("pfm-vis-max-indices", 1048576,
PRC_DESC("Specifies the maximum number of vertex references that may appear in "
"a single generated mesh. If the mesh would require more than that, "
"the mesh is subdivided into smaller pieces."));
////////////////////////////////////////////////////////////////////
// Function: init_libpnmimage
// Description: Initializes the library. This must be called at

View File

@ -24,8 +24,6 @@ NotifyCategoryDecl(pnmimage, EXPCL_PANDA_PNMIMAGE, EXPTP_PANDA_PNMIMAGE);
extern ConfigVariableBool pfm_force_littleendian;
extern ConfigVariableBool pfm_reverse_dimensions;
extern ConfigVariableInt pfm_vis_max_vertices;
extern ConfigVariableInt pfm_vis_max_indices;
extern EXPCL_PANDA_PNMIMAGE void init_libpnmimage();

View File

@ -442,19 +442,6 @@ get_no_data_value() const {
return _no_data_value;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::xform
// Access: Published
// Description: Applies the indicated transform matrix to all points
// in-place.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
xform(const TransformState *transform) {
if (!transform->is_identity()) {
xform(transform->get_mat());
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::xform
// Access: Published
@ -465,6 +452,7 @@ INLINE void PfmFile::
xform(const LMatrix4d &transform) {
xform(LCAST(PN_float32, transform));
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::compute_planar_bounds
// Access: Published
@ -489,152 +477,6 @@ compute_planar_bounds(const LPoint2d &center, PN_float32 point_dist, PN_float32
return compute_planar_bounds(LCAST(PN_float32, center), point_dist, sample_radius, points_only);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_vis_inverse
// Access: Published
// 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.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_vis_inverse(bool vis_inverse) {
_vis_inverse = vis_inverse;
clear_vis_columns();
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_vis_inverse
// Access: Published
// Description: Returns the vis_inverse flag. See set_vis_inverse().
////////////////////////////////////////////////////////////////////
INLINE bool PfmFile::
get_vis_inverse() const {
return _vis_inverse;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_flat_texcoord_name
// Access: Published
// Description: If the flat_texcoord_name is specified, it is the
// name of an additional vertex column that will be
// created for the "flat" texture coordinates, i.e. the
// original 0..1 values that correspond to the 2-D index
// position of each point in the original pfm file.
//
// These are the same values that will be assigned to
// the default texture coordinates if the vis_inverse
// flag is *not* true.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_flat_texcoord_name(InternalName *flat_texcoord_name) {
_flat_texcoord_name = flat_texcoord_name;
clear_vis_columns();
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::clear_flat_texcoord_name
// Access: Published
// Description: Resets the flat_texcoord_name to empty, so that
// additional texture coordinates are not created.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
clear_flat_texcoord_name() {
_flat_texcoord_name = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_flat_texcoord_name
// Access: Published
// Description: Returns the flat_texcoord_name. See set_flat_texcoord_name().
////////////////////////////////////////////////////////////////////
INLINE InternalName *PfmFile::
get_flat_texcoord_name() const {
return _flat_texcoord_name;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_vis_2d
// Access: Published
// Description: Sets the vis_2d flag. When this flag is true,
// only the first two (x, y) value of each depth point
// is considered meaningful; the z component is ignored.
// This is only relevant for generating visualizations.
//
// This may be used in lieu of the lower-level
// add_vis_column().
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_vis_2d(bool vis_2d) {
_vis_2d = vis_2d;
clear_vis_columns();
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_vis_2d
// Access: Published
// Description: Returns the vis_2d flag. See set_vis_2d().
////////////////////////////////////////////////////////////////////
INLINE bool PfmFile::
get_vis_2d() const {
return _vis_2d;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_vis_blend
// Access: Published
// Description: Specifies a blending map--a grayscale image--that
// will be applied to the vertex color during
// generate_vis_mesh() and generate_vis_points(). The
// image size must exactly match the mesh size of the
// PfmFile.
//
// Ownership of the pointer is not kept by the PfmFile;
// it is your responsibility to ensure it does not
// destruct during the lifetime of the PfmFile (or at
// least not before your subsequent call to
// generate_vis_mesh()).
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_vis_blend(const PNMImage *vis_blend) {
_vis_blend = vis_blend;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_vis_blend
// Access: Published
// Description: Removes the blending map set by a prior call to
// set_vis_blend().
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
clear_vis_blend() {
_vis_blend = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_vis_blend
// Access: Published
// Description: Returns the blending map set by the most recent call
// to set_vis_blend(), or NULL if there is no blending
// map in effect.
////////////////////////////////////////////////////////////////////
INLINE const PNMImage *PfmFile::
get_vis_blend() const {
return _vis_blend;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_table
// Access: Public

View File

@ -19,18 +19,10 @@
#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 "pnmImage.h"
#include "pnmReader.h"
#include "pnmWriter.h"
#include "string_utils.h"
#include "lens.h"
#include "look_at.h"
////////////////////////////////////////////////////////////////////
@ -43,9 +35,6 @@ PfmFile() {
_has_no_data_value = false;
_no_data_value = LPoint4f::zero();
_has_point = has_point_noop;
_vis_inverse = false;
_vis_2d = false;
_vis_blend = NULL;
clear();
}
@ -61,10 +50,7 @@ PfmFile(const PfmFile &copy) :
_scale(copy._scale),
_has_no_data_value(copy._has_no_data_value),
_no_data_value(copy._no_data_value),
_has_point(copy._has_point),
_vis_inverse(copy._vis_inverse),
_vis_2d(copy._vis_2d),
_vis_blend(copy._vis_blend)
_has_point(copy._has_point)
{
}
@ -81,9 +67,6 @@ operator = (const PfmFile &copy) {
_has_no_data_value = copy._has_no_data_value;
_no_data_value = copy._no_data_value;
_has_point = copy._has_point;
_vis_inverse = copy._vis_inverse;
_vis_2d = copy._vis_2d;
_vis_blend = copy._vis_blend;
}
////////////////////////////////////////////////////////////////////
@ -97,7 +80,6 @@ clear() {
_y_size = 0;
_scale = 1.0;
_num_channels = 3;
_vis_blend = NULL;
_table.clear();
clear_no_data_value();
}
@ -114,7 +96,6 @@ clear(int x_size, int y_size, int num_channels) {
_y_size = y_size;
_scale = 1.0;
_num_channels = num_channels;
_vis_blend = NULL;
_table.clear();
int size = _x_size * _y_size * _num_channels;
@ -948,112 +929,6 @@ xform(const LMatrix4f &transform) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::project
// Access: Published
// Description: Adjusts each (x, y, z) point of the Pfm file by
// projecting it through the indicated lens, converting
// each point to a (u, v, w) texture coordinate. The
// resulting file can be generated to a mesh (with
// set_vis_inverse(true) and generate_vis_mesh())
// that will apply the lens distortion to an arbitrary
// texture image.
////////////////////////////////////////////////////////////////////
void PfmFile::
project(const Lens *lens) {
nassertv(is_valid());
static LMatrix4f to_uv(0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f);
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
if (!has_point(xi, yi)) {
continue;
}
LPoint3f &p = modify_point(xi, yi);
LPoint3 film;
lens->project(LCAST(PN_stdfloat, p), film);
p = to_uv.xform_point(LCAST(PN_float32, film));
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::extrude
// Access: Published
// Description: Converts each (u, v, depth) point of the Pfm file to
// an (x, y, z) point, by reversing project(). If the
// original file is only a 1-d file, assumes that it is
// a depth map with implicit (u, v) coordinates.
//
// This method is only valid for a linear lens (e.g. a
// PerspectiveLens or OrthographicLens). Non-linear
// lenses don't necessarily compute a sensible depth
// coordinate.
////////////////////////////////////////////////////////////////////
void PfmFile::
extrude(const Lens *lens) {
nassertv(is_valid());
nassertv(lens->is_linear());
static LMatrix4 from_uv(2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, -1.0, 1.0);
const LMatrix4 &proj_mat_inv = lens->get_projection_mat_inv();
PfmFile result;
result.clear(_x_size, _y_size, 3);
result.set_zero_special(true);
if (_num_channels == 1) {
// Create an implicit UV coordinate for each point.
LPoint2 uv_scale(1.0, 1.0);
if (_x_size > 1) {
uv_scale[0] = 1.0 / PN_stdfloat(_x_size - 1);
}
if (_y_size > 1) {
uv_scale[1] = 1.0 / PN_stdfloat(_y_size - 1);
}
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
if (!has_point(xi, yi)) {
continue;
}
LPoint3 p;
p.set((PN_stdfloat)xi * uv_scale[0],
(PN_stdfloat)yi * uv_scale[1],
(PN_stdfloat)get_point1(xi, yi));
from_uv.xform_point_in_place(p);
proj_mat_inv.xform_point_general_in_place(p);
result.set_point(xi, yi, p);
}
}
} else {
// Use the existing UV coordinate for each point.
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
if (!has_point(xi, yi)) {
continue;
}
LPoint3 p;
p = LCAST(PN_stdfloat, get_point(xi, yi));
from_uv.xform_point_in_place(p);
proj_mat_inv.xform_point_general_in_place(p);
result.set_point(xi, yi, p);
}
}
}
(*this) = result;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::forward_distort
// Access: Published
@ -1490,163 +1365,6 @@ compute_sample_point(LPoint3f &result,
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::clear_vis_columns
// Access: Published
// Description: Removes all of the previously-added vis columns in
// preparation for building a new list. See
// add_vis_column().
////////////////////////////////////////////////////////////////////
void PfmFile::
clear_vis_columns() {
_vis_columns.clear();
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::add_vis_column
// Access: Published
// Description: Adds a new vis column specification to the list of
// vertex data columns that will be generated at the
// next call to generate_vis_points() or
// generate_vis_mesh(). This advanced interface
// supercedes the higher-level set_vis_inverse(),
// set_flat_texcoord_name(), and set_vis_2d().
//
// If you use this advanced interface, you must specify
// explicitly the complete list of data columns to be
// created in the resulting GeomVertexData, by calling
// add_vis_column() each time. For each column, you
// specify the source of the column in the PFMFile, the
// target column and name in the GeomVertexData, and an
// optional transform matrix and/or lens to transform
// and project the point before generating it.
////////////////////////////////////////////////////////////////////
void PfmFile::
add_vis_column(ColumnType source, ColumnType target,
InternalName *name, const TransformState *transform,
const Lens *lens) {
add_vis_column(_vis_columns, source, target, name, transform, lens);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::generate_vis_points
// Access: Published
// 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) {
if (_vis_2d) {
format = GeomVertexFormat::get_v3t2();
} else {
// We need a 3-d texture coordinate if we're inverting the vis
// and it's 3-d.
GeomVertexArrayFormat *v3t3 = new GeomVertexArrayFormat
(InternalName::get_vertex(), 3,
Geom::NT_stdfloat, Geom::C_point,
InternalName::get_texcoord(), 3,
Geom::NT_stdfloat, 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());
LPoint2f uv_scale(1.0, 1.0);
if (_x_size > 1) {
uv_scale[0] = 1.0f / PN_float32(_x_size - 1);
}
if (_y_size > 1) {
uv_scale[1] = 1.0f / PN_float32(_y_size - 1);
}
int num_points = 0;
for (int yi = 0; yi < _y_size; ++yi) {
for (int xi = 0; xi < _x_size; ++xi) {
if (!has_point(xi, yi)) {
continue;
}
const LPoint3f &point = get_point(xi, yi);
LPoint2f uv(PN_float32(xi) * uv_scale[0],
PN_float32(yi) * uv_scale[1]);
if (_vis_inverse) {
vertex.add_data2f(uv);
texcoord.add_data3f(point);
} else if (_vis_2d) {
vertex.add_data2f(point[0], point[1]);
texcoord.add_data2f(uv);
} else {
vertex.add_data3f(point);
texcoord.add_data2f(uv);
}
++num_points;
}
}
PT(Geom) geom = new Geom(vdata);
PT(GeomPoints) points = new GeomPoints(Geom::UH_static);
points->add_next_vertices(num_points);
geom->add_primitive(points);
PT(GeomNode) gnode = new GeomNode("");
gnode->add_geom(geom);
return NodePath(gnode);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::generate_vis_mesh
// Access: Published
// 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(MeshFace face) const {
nassertr(is_valid(), NodePath());
nassertr(face != 0, NodePath());
if (_num_channels == 1 && _vis_columns.empty()) {
// If we're generating a default mesh from a one-channel pfm file,
// expand it to a three-channel pfm file to make the visualization
// useful.
PfmFile expanded;
expanded.clear_to_texcoords(_x_size, _y_size);
expanded.copy_channel(2, *this, 0);
return expanded.generate_vis_mesh(face);
}
if (_x_size == 1 || _y_size == 1) {
// Can't generate a 1-d mesh, so generate points in this case.
return generate_vis_points();
}
PT(GeomNode) gnode = new GeomNode("");
if (face & MF_front) {
make_vis_mesh_geom(gnode, false);
}
if (face & MF_back) {
make_vis_mesh_geom(gnode, true);
}
return NodePath(gnode);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::output
// Access: Published
@ -1658,161 +1376,6 @@ output(ostream &out) const {
<< _num_channels << " channels.";
}
////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////
void PfmFile::
make_vis_mesh_geom(GeomNode *gnode, bool inverted) const {
int num_x_cells = 1;
int num_y_cells = 1;
int x_size = _x_size;
int y_size = _y_size;
// This is the number of independent vertices we will require.
int num_vertices = x_size * y_size;
if (num_vertices == 0) {
// Trivial no-op.
return;
}
bool reverse_normals = inverted;
bool reverse_faces = inverted;
if (!is_right_handed(get_default_coordinate_system())) {
reverse_faces = !reverse_faces;
}
// This is the max number of vertex indices we might add to the
// GeomTriangles. (We might actually add fewer than this due to
// omitting the occasional missing data point.)
int max_indices = (x_size - 1) * (y_size - 1) * 6;
while (num_vertices > pfm_vis_max_vertices || max_indices > pfm_vis_max_indices) {
// Too many vertices in one mesh. Subdivide the mesh into smaller
// pieces.
if (num_x_cells > num_y_cells) {
++num_y_cells;
} else {
++num_x_cells;
}
x_size = (_x_size + num_x_cells - 1) / num_x_cells + 1;
y_size = (_y_size + num_y_cells - 1) / num_y_cells + 1;
num_vertices = x_size * y_size;
max_indices = (x_size - 1) * (y_size - 1) * 6;
}
// OK, now we know how many cells we need.
if (pnmimage_cat.is_debug()) {
pnmimage_cat.debug()
<< "Generating mesh with " << num_x_cells << " x " << num_y_cells
<< " pieces.\n";
}
VisColumns vis_columns = _vis_columns;
if (vis_columns.empty()) {
build_auto_vis_columns(vis_columns, true);
}
CPT(GeomVertexFormat) format = make_array_format(vis_columns);
for (int yci = 0; yci < num_y_cells; ++yci) {
int y_begin = (yci * _y_size) / num_y_cells;
int y_end = ((yci + 1) * _y_size) / num_y_cells;
// Include the first vertex from the next strip in this strip's
// vertices, so we are connected.
y_end = min(y_end + 1, _y_size);
y_size = y_end - y_begin;
if (y_size == 0) {
continue;
}
for (int xci = 0; xci < num_x_cells; ++xci) {
int x_begin = (xci * _x_size) / num_x_cells;
int x_end = ((xci + 1) * _x_size) / num_x_cells;
x_end = min(x_end + 1, _x_size);
x_size = x_end - x_begin;
if (x_size == 0) {
continue;
}
num_vertices = x_size * y_size;
max_indices = (x_size - 1) * (y_size - 1) * 6;
ostringstream mesh_name;
mesh_name << "mesh_" << xci << "_" << yci;
PT(GeomVertexData) vdata = new GeomVertexData
(mesh_name.str(), format, Geom::UH_static);
vdata->set_num_rows(num_vertices);
// Fill in all of the vertices.
for (VisColumns::const_iterator vci = vis_columns.begin();
vci != vis_columns.end();
++vci) {
const VisColumn &column = *vci;
GeomVertexWriter vwriter(vdata, column._name);
vwriter.set_row(0);
for (int yi = y_begin; yi < y_end; ++yi) {
for (int xi = x_begin; xi < x_end; ++xi) {
column.add_data(*this, vwriter, xi, yi, reverse_normals);
}
}
}
PT(Geom) geom = new Geom(vdata);
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
tris->reserve_num_vertices(max_indices);
for (int yi = y_begin; yi < y_end - 1; ++yi) {
for (int xi = x_begin; xi < x_end - 1; ++xi) {
if (_has_no_data_value) {
if (!has_point(xi, yi) ||
!has_point(xi, yi + 1) ||
!has_point(xi + 1, yi + 1) ||
!has_point(xi + 1, yi)) {
continue;
}
}
int xi0 = xi - x_begin;
int yi0 = yi - y_begin;
int vi0 = ((xi0) + (yi0) * x_size);
int vi1 = ((xi0) + (yi0 + 1) * x_size);
int vi2 = ((xi0 + 1) + (yi0 + 1) * x_size);
int vi3 = ((xi0 + 1) + (yi0) * x_size);
if (reverse_faces) {
tris->add_vertices(vi2, vi0, vi1);
tris->close_primitive();
tris->add_vertices(vi3, vi0, vi2);
tris->close_primitive();
} else {
tris->add_vertices(vi2, vi1, vi0);
tris->close_primitive();
tris->add_vertices(vi3, vi2, vi0);
tris->close_primitive();
}
}
}
geom->add_primitive(tris);
gnode->add_geom(geom);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_region
// Access: Private
@ -2089,138 +1652,6 @@ box_filter_point(LPoint4f &result, PN_float32 &coverage,
coverage += contrib;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::add_vis_column
// Access: Private, Static
// Description: The private implementation of the public
// add_vis_column(), this adds the column to the
// indicated specific vector.
////////////////////////////////////////////////////////////////////
void PfmFile::
add_vis_column(VisColumns &vis_columns, ColumnType source, ColumnType target,
InternalName *name, const TransformState *transform,
const Lens *lens) {
VisColumn column;
column._source = source;
column._target = target;
column._name = name;
column._transform = transform;
if (transform == NULL) {
column._transform = TransformState::make_identity();
}
column._lens = lens;
vis_columns.push_back(column);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::build_auto_vis_columns
// Access: Private
// Description: This function is called internally to construct the
// list of vis_columns automatically from the high-level
// interfaces such as set_vis_inverse(),
// set_flat_texcoord_name(), and set_vis_2d(). It's not
// called if the list has been build explicitly.
////////////////////////////////////////////////////////////////////
void PfmFile::
build_auto_vis_columns(VisColumns &vis_columns, bool for_points) const {
vis_columns.clear();
if (_vis_2d) {
// No normals needed if we're just generating a 2-d mesh.
if (_vis_inverse) {
add_vis_column(vis_columns, CT_texcoord2, CT_vertex2, InternalName::get_vertex());
add_vis_column(vis_columns, CT_vertex2, CT_texcoord2, InternalName::get_texcoord());
} else {
add_vis_column(vis_columns, CT_vertex2, CT_vertex2, InternalName::get_vertex());
add_vis_column(vis_columns, CT_texcoord2, CT_texcoord2, InternalName::get_texcoord());
}
} else {
if (_vis_inverse) {
// We need a 3-d texture coordinate if we're inverting the vis
// and it's 3-d. But we still don't need normals in that case.
add_vis_column(vis_columns, CT_texcoord3, CT_vertex3, InternalName::get_vertex());
add_vis_column(vis_columns, CT_vertex3, CT_texcoord3, InternalName::get_texcoord());
} else {
// Otherwise, we only need a 2-d texture coordinate, and we do
// want normals.
add_vis_column(vis_columns, CT_vertex3, CT_vertex3, InternalName::get_vertex());
add_vis_column(vis_columns, CT_normal3, CT_normal3, InternalName::get_normal());
add_vis_column(vis_columns, CT_texcoord2, CT_texcoord2, InternalName::get_texcoord());
}
}
if (_flat_texcoord_name != (InternalName *)NULL) {
// We need an additional texcoord column for the flat texcoords.
add_vis_column(vis_columns, CT_texcoord2, CT_texcoord2, _flat_texcoord_name);
}
if (_vis_blend != (PNMImage *)NULL) {
// The blend map, if specified, also gets applied to the vertices.
add_vis_column(vis_columns, CT_blend1, CT_blend1, InternalName::get_color());
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::make_array_format
// Access: Private
// Description: Constructs a GeomVertexFormat that corresponds to the
// vis_columns list.
////////////////////////////////////////////////////////////////////
CPT(GeomVertexFormat) PfmFile::
make_array_format(const VisColumns &vis_columns) const {
PT(GeomVertexArrayFormat) array_format = new GeomVertexArrayFormat;
for (VisColumns::const_iterator vci = vis_columns.begin();
vci != vis_columns.end();
++vci) {
const VisColumn &column = *vci;
InternalName *name = column._name;
int num_components = 0;
GeomEnums::NumericType numeric_type = GeomEnums::NT_float32;
GeomEnums::Contents contents = GeomEnums::C_point;
switch (column._target) {
case CT_texcoord2:
num_components = 2;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_texcoord;
break;
case CT_texcoord3:
num_components = 3;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_texcoord;
break;
case CT_vertex1:
case CT_vertex2:
case CT_vertex3:
num_components = 3;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_point;
break;
case CT_normal3:
num_components = 3;
numeric_type = GeomEnums::NT_float32;
contents = GeomEnums::C_vector;
break;
case CT_blend1:
num_components = 4;
numeric_type = GeomEnums::NT_uint8;
contents = GeomEnums::C_color;
break;
}
nassertr(num_components != 0, NULL);
array_format->add_column(name, num_components, numeric_type, contents);
}
return GeomVertexFormat::register_format(array_format);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::fill_mini_grid
// Access: Private
@ -2320,153 +1751,3 @@ has_point_chan4(const PfmFile *self, int x, int y) {
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::VisColumn::add_data
// Access: Public
// Description: Adds the data for this column to the appropriate
// column of the GeomVertexWriter.
////////////////////////////////////////////////////////////////////
void PfmFile::VisColumn::
add_data(const PfmFile &file, GeomVertexWriter &vwriter, int xi, int yi, bool reverse_normals) const {
switch (_source) {
case CT_texcoord2:
{
LPoint2f uv(PN_float32(xi) / PN_float32(file._x_size - 1),
PN_float32(yi) / PN_float32(file._y_size - 1));
transform_point(uv);
vwriter.set_data2f(uv);
}
break;
case CT_texcoord3:
{
LPoint3f uv(PN_float32(xi) / PN_float32(file._x_size - 1),
PN_float32(yi) / PN_float32(file._y_size - 1),
0.0f);
transform_point(uv);
vwriter.set_data3f(uv);
}
break;
case CT_vertex1:
{
PN_float32 p = file.get_point1(xi, yi);
LPoint2f point(p, 0.0);
transform_point(point);
vwriter.set_data2f(point);
}
break;
case CT_vertex2:
{
LPoint2f point = file.get_point2(xi, yi);
transform_point(point);
vwriter.set_data2f(point);
}
break;
case CT_vertex3:
{
LPoint3f point = file.get_point(xi, yi);
transform_point(point);
vwriter.set_data3f(point);
}
break;
case CT_normal3:
{
// Calculate the normal based on two neighboring vertices.
LPoint3f v[3];
v[0] = file.get_point(xi, yi);
if (xi + 1 < file._x_size) {
v[1] = file.get_point(xi + 1, yi);
} else {
v[1] = v[0];
v[0] = file.get_point(xi - 1, yi);
}
if (yi + 1 < file._y_size) {
v[2] = file.get_point(xi, yi + 1);
} else {
v[2] = v[0];
v[0] = file.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();
nassertv(!n.is_nan());
if (reverse_normals) {
n = -n;
}
transform_vector(n);
vwriter.set_data3f(n);
}
break;
case CT_blend1:
{
const PNMImage *vis_blend = file.get_vis_blend();
if (vis_blend != NULL) {
double gray = vis_blend->get_gray(xi, yi);
vwriter.set_data3d(gray, gray, gray);
}
}
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::VisColumn::transform_point
// Access: Public
// Description: Transforms the indicated point as specified by the
// VisColumn.
////////////////////////////////////////////////////////////////////
void PfmFile::VisColumn::
transform_point(LPoint2f &point) const {
if (!_transform->is_identity()) {
LCAST(PN_float32, _transform->get_mat3()).xform_point_in_place(point);
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::VisColumn::transform_point
// Access: Public
// Description: Transforms the indicated point as specified by the
// VisColumn.
////////////////////////////////////////////////////////////////////
void PfmFile::VisColumn::
transform_point(LPoint3f &point) const {
if (!_transform->is_identity()) {
LCAST(PN_float32, _transform->get_mat()).xform_point_in_place(point);
}
if (_lens != (Lens *)NULL) {
static LMatrix4f to_uv(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.5, 0.5, 0.0, 1.0);
LPoint3 film;
_lens->project(LCAST(PN_stdfloat, point), film);
point = to_uv.xform_point(LCAST(PN_float32, film));
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::VisColumn::transform_vector
// Access: Public
// Description: Transforms the indicated vector as specified by the
// VisColumn.
////////////////////////////////////////////////////////////////////
void PfmFile::VisColumn::
transform_vector(LVector3f &vec) const {
if (!_transform->is_identity()) {
LCAST(PN_float32, _transform->get_mat()).xform_vec_in_place(vec);
}
}

View File

@ -18,17 +18,11 @@
#include "pandabase.h"
#include "pnmImageHeader.h"
#include "luse.h"
#include "nodePath.h"
#include "boundingHexahedron.h"
#include "internalName.h"
#include "lens.h"
class GeomNode;
class Lens;
class PNMImage;
class PNMReader;
class PNMWriter;
class GeomVertexWriter;
////////////////////////////////////////////////////////////////////
// Class : PfmFile
@ -98,11 +92,8 @@ PUBLISHED:
BLOCKING void resize(int new_x_size, int new_y_size);
BLOCKING void reverse_rows();
BLOCKING void flip(bool flip_x, bool flip_y, bool transpose);
INLINE BLOCKING void xform(const TransformState *transform);
BLOCKING void xform(const LMatrix4f &transform);
INLINE BLOCKING void xform(const LMatrix4d &transform);
BLOCKING void project(const Lens *lens);
BLOCKING void extrude(const Lens *lens);
BLOCKING void forward_distort(const PfmFile &dist);
BLOCKING void reverse_distort(const PfmFile &dist);
BLOCKING void merge(const PfmFile &other);
@ -115,41 +106,6 @@ PUBLISHED:
void compute_sample_point(LPoint3f &result,
PN_float32 x, PN_float32 y, PN_float32 sample_radius) const;
INLINE void set_vis_inverse(bool vis_inverse);
INLINE bool get_vis_inverse() const;
INLINE void set_flat_texcoord_name(InternalName *flat_texcoord_name);
INLINE void clear_flat_texcoord_name();
INLINE InternalName *get_flat_texcoord_name() const;
INLINE void set_vis_2d(bool vis_2d);
INLINE bool get_vis_2d() const;
INLINE void set_vis_blend(const PNMImage *vis_blend);
INLINE void clear_vis_blend();
INLINE const PNMImage *get_vis_blend() const;
enum ColumnType {
CT_texcoord2,
CT_texcoord3,
CT_vertex1,
CT_vertex2,
CT_vertex3,
CT_normal3,
CT_blend1,
};
void clear_vis_columns();
void add_vis_column(ColumnType source, ColumnType target,
InternalName *name,
const TransformState *transform = NULL, const Lens *lens = NULL);
BLOCKING NodePath generate_vis_points() const;
enum MeshFace {
MF_front = 0x01,
MF_back = 0x02,
MF_both = 0x03,
};
BLOCKING NodePath generate_vis_mesh(MeshFace face = MF_front) const;
void output(ostream &out) const;
public:
@ -157,8 +113,6 @@ public:
INLINE void swap_table(pvector<PN_float32> &table);
private:
void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
void box_filter_region(PN_float32 &result,
PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
void box_filter_region(LPoint3f &result,
@ -178,29 +132,6 @@ private:
void box_filter_point(LPoint4f &result, PN_float32 &coverage,
int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
class VisColumn {
public:
void add_data(const PfmFile &file, GeomVertexWriter &vwriter, int xi, int yi, bool reverse_normals) const;
void transform_point(LPoint2f &point) const;
void transform_point(LPoint3f &point) const;
void transform_vector(LVector3f &vec) const;
public:
ColumnType _source;
ColumnType _target;
PT(InternalName) _name;
CPT(TransformState) _transform;
CPT(Lens) _lens;
};
typedef pvector<VisColumn> VisColumns;
static void add_vis_column(VisColumns &vis_columns,
ColumnType source, ColumnType target,
InternalName *name,
const TransformState *transform = NULL, const Lens *lens = NULL);
void build_auto_vis_columns(VisColumns &vis_columns, bool for_points) const;
CPT(GeomVertexFormat) make_array_format(const VisColumns &vis_columns) const;
class MiniGridCell {
public:
MiniGridCell() : _sxi(-1), _syi(-1), _dist(-1) { }
@ -225,17 +156,11 @@ private:
bool _has_no_data_value;
LPoint4f _no_data_value;
bool _vis_inverse;
PT(InternalName) _flat_texcoord_name;
bool _vis_2d;
const PNMImage *_vis_blend;
VisColumns _vis_columns;
typedef bool HasPointFunc(const PfmFile *file, int x, int y);
HasPointFunc *_has_point;
friend class VisColumn;
friend class PfmVizzer;
};
#include "pfmFile.I"