diff --git a/panda/src/mathutil/plane_src.I b/panda/src/mathutil/plane_src.I index b45886d801..cd74ad131f 100644 --- a/panda/src/mathutil/plane_src.I +++ b/panda/src/mathutil/plane_src.I @@ -171,6 +171,17 @@ dist_to_plane(const FLOATNAME(LPoint3) &point) const { return (_v.v._0 * point[0] + _v.v._1 * point[1] + _v.v._2 * point[2] + _v.v._3); } +//////////////////////////////////////////////////////////////////// +// Function: Plane::project +// Access: Published +// Description: Returns the point within the plane nearest to the +// indicated point in space. +//////////////////////////////////////////////////////////////////// +INLINE_MATHUTIL FLOATNAME(LPoint3) FLOATNAME(Plane):: +project(const FLOATNAME(LPoint3) &point) const { + return point - get_normal() * dist_to_plane(point); +} + //////////////////////////////////////////////////////////////////// // Function: Plane::intersects_line // Access: Published diff --git a/panda/src/mathutil/plane_src.h b/panda/src/mathutil/plane_src.h index 1f0237f5e4..7741ea85b0 100644 --- a/panda/src/mathutil/plane_src.h +++ b/panda/src/mathutil/plane_src.h @@ -45,6 +45,9 @@ PUBLISHED: FLOATNAME(LPoint3) get_point() const; INLINE_MATHUTIL FLOATTYPE dist_to_plane(const FLOATNAME(LPoint3) &point) const; + INLINE_MATHUTIL FLOATNAME(LPoint3) project(const FLOATNAME(LPoint3) &point) const; + + INLINE_MATHUTIL bool intersects_line(FLOATNAME(LPoint3) &intersection_point, const FLOATNAME(LPoint3) &p1, const FLOATNAME(LPoint3) &p2) const; diff --git a/panda/src/pgraph/planeNode.I b/panda/src/pgraph/planeNode.I index 97b33af95f..b401cd916a 100644 --- a/panda/src/pgraph/planeNode.I +++ b/panda/src/pgraph/planeNode.I @@ -23,7 +23,9 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE PlaneNode::CData:: -CData() { +CData() : + _viz_scale(100.0f) +{ // The default plane (perpendicular to the Z-axis) is used until // another one is specified explicitly. } @@ -35,12 +37,15 @@ CData() { //////////////////////////////////////////////////////////////////// INLINE PlaneNode::CData:: CData(const PlaneNode::CData ©) : - _plane(copy._plane) + _plane(copy._plane), + _front_viz(copy._front_viz), + _back_viz(copy._back_viz), + _viz_scale(copy._viz_scale) { } //////////////////////////////////////////////////////////////////// -// Function: set_plane +// Function: PlaneNode::set_plane // Access: Public // Description: Sets the particular plane represented by the // PlaneNode. @@ -48,11 +53,15 @@ CData(const PlaneNode::CData ©) : INLINE void PlaneNode:: set_plane(const Planef &plane) { CDWriter cdata(_cycler); - cdata->_plane = plane; + if (cdata->_plane != plane) { + cdata->_plane = plane; + cdata->_front_viz = NULL; + cdata->_back_viz = NULL; + } } //////////////////////////////////////////////////////////////////// -// Function: get_plane +// Function: PlaneNode::get_plane // Access: Public // Description: Returns the plane represented by the PlaneNode. //////////////////////////////////////////////////////////////////// @@ -61,6 +70,34 @@ get_plane() const { CDReader cdata(_cycler); return cdata->_plane; } + +//////////////////////////////////////////////////////////////////// +// Function: PlaneNode::set_viz_scale +// Access: Public +// Description: Specifies the size of the visual representation of +// the plane that is drawn if the PlaneNode is shown. +//////////////////////////////////////////////////////////////////// +INLINE void PlaneNode:: +set_viz_scale(float viz_scale) { + CDWriter cdata(_cycler); + if (cdata->_viz_scale != viz_scale) { + cdata->_viz_scale = viz_scale; + cdata->_front_viz = NULL; + cdata->_back_viz = NULL; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PlaneNode::get_viz_scale +// Access: Public +// Description: Returns the size of the visual representation of +// the plane that is drawn if the PlaneNode is shown. +//////////////////////////////////////////////////////////////////// +INLINE float PlaneNode:: +get_viz_scale() const { + CDReader cdata(_cycler); + return cdata->_viz_scale; +} //////////////////////////////////////////////////////////////////// // Function: PlaneNode::set_priority diff --git a/panda/src/pgraph/planeNode.cxx b/panda/src/pgraph/planeNode.cxx index c9bed08e42..38b662030f 100644 --- a/panda/src/pgraph/planeNode.cxx +++ b/panda/src/pgraph/planeNode.cxx @@ -22,6 +22,13 @@ #include "bamReader.h" #include "datagram.h" #include "datagramIterator.h" +#include "geomVertexWriter.h" +#include "geomVertexData.h" +#include "geomLines.h" +#include "geom.h" +#include "cullableObject.h" +#include "cullHandler.h" +#include "boundingPlane.h" UpdateSeq PlaneNode::_sort_seq; @@ -70,6 +77,9 @@ PlaneNode(const string &name, const Planef &plane) : PandaNode(name), _priority(0) { + // PlaneNodes are hidden by default. + set_draw_mask(DrawMask::all_off()); + set_plane(plane); } @@ -86,6 +96,17 @@ PlaneNode(const PlaneNode ©) : { } +//////////////////////////////////////////////////////////////////// +// Function: PlaneNode::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void PlaneNode:: +output(ostream &out) const { + PandaNode::output(out); + out << " " << get_plane(); +} + //////////////////////////////////////////////////////////////////// // Function: PlaneNode::make_copy // Access: Public, Virtual @@ -111,28 +132,155 @@ xform(const LMatrix4f &mat) { PandaNode::xform(mat); CDWriter cdata(_cycler); cdata->_plane = cdata->_plane * mat; + cdata->_front_viz = NULL; + cdata->_back_viz = NULL; } //////////////////////////////////////////////////////////////////// -// Function: PlaneNode::output +// Function: PlaneNode::has_cull_callback // Access: Public, Virtual -// Description: +// Description: Should be overridden by derived classes to return +// true if cull_callback() has been defined. Otherwise, +// returns false to indicate cull_callback() does not +// need to be called for this node during the cull +// traversal. //////////////////////////////////////////////////////////////////// -void PlaneNode:: -output(ostream &out) const { - PandaNode::output(out); - out << " " << get_plane(); +bool PlaneNode:: +has_cull_callback() const { + return true; } //////////////////////////////////////////////////////////////////// -// Function: PlaneNode::write +// Function: PlaneNode::cull_callback // Access: Public, Virtual -// Description: +// Description: If has_cull_callback() returns true, this function +// will be called during the cull traversal to perform +// any additional operations that should be performed at +// cull time. This may include additional manipulation +// of render state or additional visible/invisible +// decisions, or any other arbitrary operation. +// +// By the time this function is called, the node has +// already passed the bounding-volume test for the +// viewing frustum, and the node's transform and state +// have already been applied to the indicated +// CullTraverserData object. +// +// The return value is true if this node should be +// visible, or false if it should be culled. //////////////////////////////////////////////////////////////////// -void PlaneNode:: -write(ostream &out, int indent_level) const { - PandaNode::write(out, indent_level); - get_plane().write(out, indent_level + 2); +bool PlaneNode:: +cull_callback(CullTraverser *trav, CullTraverserData &data) { + // Normally, a PlaneNode is invisible. But if someone shows it, we + // will draw a visualization, a nice yellow wireframe. + + CullableObject *plane_viz = + new CullableObject(get_viz(trav, data), data._state, + data._modelview_transform); + trav->get_cull_handler()->record_object(plane_viz, trav); + + // Now carry on to render our child nodes. + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PlaneNode::compute_internal_bounds +// Access: Protected, Virtual +// Description: Returns a newly-allocated BoundingVolume that +// represents the internal contents of the node. Should +// be overridden by PandaNode classes that contain +// something internally. +//////////////////////////////////////////////////////////////////// +PT(BoundingVolume) PlaneNode:: +compute_internal_bounds(int pipeline_stage) const { + CDStageReader cdata(_cycler, pipeline_stage); + return new BoundingPlane(cdata->_plane); +} + +//////////////////////////////////////////////////////////////////// +// Function: PlaneNode::get_viz +// Access: Protected +// Description: Returns a Geom that represents the visualization of +// the PlaneNode. +//////////////////////////////////////////////////////////////////// +PT(Geom) PlaneNode:: +get_viz(CullTraverser *trav, CullTraverserData &data) { + CDReader cdata(_cycler); + + // Figure out whether we are looking at the front or the back of the + // plane. + const Lens *lens = trav->get_scene()->get_lens(); + Planef eye_plane = cdata->_plane * data._modelview_transform->get_mat(); + bool front = (eye_plane.dist_to_plane(lens->get_nodal_point()) >= 0.0f); + + if (cdata->_front_viz != (Geom *)NULL) { + return front ? cdata->_front_viz : cdata->_back_viz; + } + + if (pgraph_cat.is_debug()) { + pgraph_cat.debug() + << "Recomputing viz for " << *this << "\n"; + } + + CDWriter cdataw(_cycler, cdata, false); + const Planef &plane = cdataw->_plane; + + PT(GeomVertexData) vdata = new GeomVertexData + (get_name(), GeomVertexFormat::get_v3cp(), Geom::UH_static); + + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + PT(GeomLines) lines = new GeomLines(Geom::UH_static); + + LVector3f a, b; + + if (fabs(plane[0]) > fabs(plane[1])) { + // X > Y + if (fabs(plane[0]) > fabs(plane[2])) { + // X > Y && X > Z. X is the largest. + a.set(0, 1, 0); + b.set(0, 0, 1); + } else { + // X > Y && Z > X. Z is the largest. + a.set(1, 0, 0); + b.set(0, 1, 0); + } + } else { + // Y > X + if (fabs(plane[1]) > fabs(plane[2])) { + // Y > X && Y > Z. Y is the largest. + a.set(1, 0, 0); + b.set(0, 0, 1); + } else { + // Y > X && Z > Y. Z is the largest. + a.set(1, 0, 0); + b.set(0, 1, 0); + } + } + + static const int num_segs = 10; + a *= cdataw->_viz_scale / (num_segs * 2); + b *= cdataw->_viz_scale / (num_segs * 2); + + for (int x = -num_segs; x <= num_segs; ++x) { + vertex.add_data3f(plane.project(a * x - b * num_segs)); + vertex.add_data3f(plane.project(a * x + b * num_segs)); + lines->add_next_vertices(2); + lines->close_primitive(); + } + for (int y = -num_segs; y <= num_segs; ++y) { + vertex.add_data3f(plane.project(b * y - a * num_segs)); + vertex.add_data3f(plane.project(b * y + a * num_segs)); + lines->add_next_vertices(2); + lines->close_primitive(); + } + + cdataw->_front_viz = new Geom(vdata->set_color(Colorf(1.0f, 1.0f, 0.0f, 1.0f))); + cdataw->_front_viz->add_primitive(lines); + + cdataw->_back_viz = new Geom(vdata->set_color(Colorf(0.4f, 0.4f, 0.0f, 1.0f))); + cdataw->_back_viz->add_primitive(lines); + + return front ? cdataw->_front_viz : cdataw->_back_viz; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/planeNode.h b/panda/src/pgraph/planeNode.h index 4d72097252..f62e6776f1 100644 --- a/panda/src/pgraph/planeNode.h +++ b/panda/src/pgraph/planeNode.h @@ -24,6 +24,13 @@ #include "plane.h" #include "pandaNode.h" #include "updateSeq.h" +#include "geom.h" +#include "cycleData.h" +#include "cycleDataReader.h" +#include "cycleDataWriter.h" +#include "cycleDataStageReader.h" +#include "cycleDataStageWriter.h" +#include "pipelineCycler.h" //////////////////////////////////////////////////////////////////// // Class : PlaneNode @@ -40,20 +47,29 @@ protected: PlaneNode(const PlaneNode ©); public: virtual void output(ostream &out) const; - virtual void write(ostream &out, int indent_level = 0) const; virtual PandaNode *make_copy() const; virtual void xform(const LMatrix4f &mat); + virtual bool has_cull_callback() const; + virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + PUBLISHED: INLINE void set_plane(const Planef &plane); INLINE const Planef &get_plane() const; + INLINE void set_viz_scale(float viz_scale); + INLINE float get_viz_scale() const; + INLINE void set_priority(int priority); INLINE int get_priority() const; public: INLINE static UpdateSeq get_sort_seq(); + +protected: + virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const; + PT(Geom) get_viz(CullTraverser *trav, CullTraverserData &data); private: // The priority is not cycled, because there's no real reason to do @@ -75,11 +91,15 @@ private: } Planef _plane; + PT(Geom) _front_viz, _back_viz; + float _viz_scale; }; PipelineCycler _cycler; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; + typedef CycleDataStageReader CDStageReader; + typedef CycleDataStageWriter CDStageWriter; public: static void register_with_read_factory();