From e2066b62ffe592e94d14f5c7109d8a1ad97b80e2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 26 Jul 2012 02:23:26 +0000 Subject: [PATCH] wip: add_vis_column() --- panda/src/grutil/pfmFile.I | 28 +++ panda/src/grutil/pfmFile.cxx | 377 +++++++++++++++++++++++++++-------- panda/src/grutil/pfmFile.h | 43 +++- 3 files changed, 365 insertions(+), 83 deletions(-) diff --git a/panda/src/grutil/pfmFile.I b/panda/src/grutil/pfmFile.I index 2c0674475c..c673f17e8e 100755 --- a/panda/src/grutil/pfmFile.I +++ b/panda/src/grutil/pfmFile.I @@ -368,6 +368,19 @@ 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 @@ -412,10 +425,14 @@ compute_planar_bounds(const LPoint2d ¢er, PN_float32 point_dist, PN_float32 // 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(); } //////////////////////////////////////////////////////////////////// @@ -440,10 +457,14 @@ get_vis_inverse() const { // 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(); } //////////////////////////////////////////////////////////////////// @@ -451,6 +472,9 @@ set_flat_texcoord_name(InternalName *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() { @@ -474,10 +498,14 @@ get_flat_texcoord_name() const { // 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(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/grutil/pfmFile.cxx b/panda/src/grutil/pfmFile.cxx index b126dd8591..2e4b517c87 100755 --- a/panda/src/grutil/pfmFile.cxx +++ b/panda/src/grutil/pfmFile.cxx @@ -1289,6 +1289,43 @@ 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 @@ -1454,38 +1491,12 @@ make_vis_mesh_geom(GeomNode *gnode, bool inverted) const { << " pieces.\n"; } - PT(GeomVertexArrayFormat) array_format; - - if (_vis_2d) { - // No normals needed if we're just generating a 2-d mesh. - array_format = new GeomVertexArrayFormat - (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point, - InternalName::get_texcoord(), 2, Geom::NT_stdfloat, Geom::C_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. - array_format = new GeomVertexArrayFormat - (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point, - InternalName::get_texcoord(), 3, Geom::NT_stdfloat, Geom::C_texcoord); - } else { - // Otherwise, we only need a 2-d texture coordinate, and we do - // want normals. - array_format = new GeomVertexArrayFormat - (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point, - InternalName::get_normal(), 3, Geom::NT_stdfloat, Geom::C_vector, - InternalName::get_texcoord(), 2, Geom::NT_stdfloat, Geom::C_texcoord); - } + VisColumns vis_columns = _vis_columns; + if (vis_columns.empty()) { + build_auto_vis_columns(vis_columns, true); } - if (_flat_texcoord_name != (InternalName *)NULL) { - // We need an additional texcoord column for the flat texcoords. - array_format->add_column(_flat_texcoord_name, 2, - Geom::NT_stdfloat, Geom::C_texcoord); - } - - CPT(GeomVertexFormat) format = GeomVertexFormat::register_format(array_format); + 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; @@ -1518,62 +1529,19 @@ make_vis_mesh_geom(GeomNode *gnode, bool inverted) const { (mesh_name.str(), format, Geom::UH_static); vdata->set_num_rows(num_vertices); - GeomVertexWriter vertex(vdata, InternalName::get_vertex()); - GeomVertexWriter normal(vdata, InternalName::get_normal()); - GeomVertexWriter texcoord(vdata, InternalName::get_texcoord()); - GeomVertexWriter texcoord2(vdata, _flat_texcoord_name); + GeomVertexWriter vwriter(vdata); + int vi = 0; for (int yi = y_begin; yi < y_end; ++yi) { for (int xi = x_begin; xi < x_end; ++xi) { - const LPoint3f &point = get_point(xi, yi); - LPoint2f uv(PN_float32(xi) / PN_float32(_x_size - 1), - PN_float32(yi) / PN_float32(_y_size - 1)); + vwriter.set_row(vi); + ++vi; - 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); - - // Calculate the normal based on two neighboring vertices. - LPoint3f v[3]; - v[0] = get_point(xi, yi); - if (xi + 1 < _x_size) { - v[1] = get_point(xi + 1, yi); - } else { - v[1] = v[0]; - v[0] = get_point(xi - 1, yi); - } - - if (yi + 1 < _y_size) { - v[2] = get_point(xi, yi + 1); - } else { - v[2] = v[0]; - v[0] = get_point(xi, yi - 1); - } - - LVector3f n = LVector3f::zero(); - for (int i = 0; i < 3; ++i) { - const LPoint3f &v0 = v[i]; - const LPoint3f &v1 = v[(i + 1) % 3]; - n[0] += v0[1] * v1[2] - v0[2] * v1[1]; - n[1] += v0[2] * v1[0] - v0[0] * v1[2]; - n[2] += v0[0] * v1[1] - v0[1] * v1[0]; - } - n.normalize(); - nassertv(!n.is_nan()); - if (reverse_normals) { - n = -n; - } - normal.add_data3f(n); - } - - if (_flat_texcoord_name != (InternalName *)NULL) { - texcoord2.add_data2f(uv); + for (VisColumns::const_iterator vci = vis_columns.begin(); + vci != vis_columns.end(); + ++vci) { + const VisColumn &column = *vci; + column.add_data(*this, vwriter, xi, yi, reverse_normals); } } } @@ -1901,6 +1869,121 @@ 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. + add_vis_column(vis_columns, CT_vertex3, CT_vertex3, 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); + } +} + +//////////////////////////////////////////////////////////////////// +// 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_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; + } + 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 @@ -2000,3 +2083,133 @@ 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 { + vwriter.set_column(_name); + + 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.add_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.add_data3f(uv); + } + break; + + case CT_vertex2: + { + const LPoint3f &point3 = file.get_point(xi, yi); + LPoint2f point(point3[0], point3[1]); + transform_point(point); + vwriter.add_data2f(point); + } + break; + + case CT_vertex3: + { + LPoint3f point = file.get_point(xi, yi); + transform_point(point); + vwriter.add_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.add_data3f(n); + } + 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) { + LPoint3 film; + _lens->project(LCAST(PN_stdfloat, point), film); + 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); + } +} diff --git a/panda/src/grutil/pfmFile.h b/panda/src/grutil/pfmFile.h index 42bbff179d..a6cb4ecf2e 100755 --- a/panda/src/grutil/pfmFile.h +++ b/panda/src/grutil/pfmFile.h @@ -20,10 +20,12 @@ #include "nodePath.h" #include "boundingHexahedron.h" #include "internalName.h" +#include "lens.h" class GeomNode; class Lens; class PNMImage; +class GeomVertexWriter; //////////////////////////////////////////////////////////////////// // Class : PfmFile @@ -88,6 +90,7 @@ 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); @@ -107,6 +110,18 @@ PUBLISHED: INLINE void set_vis_2d(bool vis_2d); INLINE bool get_vis_2d() const; + enum ColumnType { + CT_texcoord2, + CT_texcoord3, + CT_vertex2, + CT_vertex3, + CT_normal3, + }; + 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 { @@ -138,6 +153,29 @@ 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 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) { } @@ -169,9 +207,12 @@ private: PT(InternalName) _flat_texcoord_name; bool _vis_2d; + VisColumns _vis_columns; + typedef bool HasPointFunc(const PfmFile *file, int x, int y); HasPointFunc *_has_point; - + + friend class VisColumn; }; #include "pfmFile.I"