diff --git a/panda/src/bullet/bulletDebugNode.cxx b/panda/src/bullet/bulletDebugNode.cxx index 196a9af09f..b4575dd3cf 100644 --- a/panda/src/bullet/bulletDebugNode.cxx +++ b/panda/src/bullet/bulletDebugNode.cxx @@ -13,20 +13,25 @@ #include "bulletDebugNode.h" +#include "cullHandler.h" +#include "cullTraverser.h" +#include "cullableObject.h" #include "geomLines.h" #include "geomVertexData.h" #include "geomTriangles.h" #include "geomVertexFormat.h" #include "geomVertexWriter.h" #include "omniBoundingVolume.h" +#include "pStatTimer.h" TypeHandle BulletDebugNode::_type_handle; +PStatCollector BulletDebugNode::_pstat_debug("App:Bullet:DoPhysics:Debug"); /** * */ BulletDebugNode:: -BulletDebugNode(const char *name) : GeomNode(name) { +BulletDebugNode(const char *name) : PandaNode(name), _debug_stale(true) { _wireframe = true; _constraints = true; @@ -37,40 +42,6 @@ BulletDebugNode(const char *name) : GeomNode(name) { set_bounds(bounds); set_final(true); set_overall_hidden(true); - - // Lines - { - PT(GeomVertexData) vdata; - PT(Geom) geom; - PT(GeomLines) prim; - - vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream); - - prim = new GeomLines(Geom::UH_stream); - prim->set_shade_model(Geom::SM_uniform); - - geom = new Geom(vdata); - geom->add_primitive(prim); - - add_geom(geom); - } - - // Triangles - { - PT(GeomVertexData) vdata; - PT(Geom) geom; - PT(GeomTriangles) prim; - - vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream); - - prim = new GeomTriangles(Geom::UH_stream); - prim->set_shade_model(Geom::SM_uniform); - - geom = new Geom(vdata); - geom->add_primitive(prim); - - add_geom(geom); - } } /** @@ -174,101 +145,134 @@ draw_mask_changed() { } } +/** + * Returns true if there is some value to visiting this particular node during + * the cull traversal for any camera, false otherwise. This will be used to + * optimize the result of get_net_draw_show_mask(), so that any subtrees that + * contain only nodes for which is_renderable() is false need not be visited. + */ +bool BulletDebugNode:: +is_renderable() const { + return true; +} + +/** + * Adds the node's contents to the CullResult we are building up during the + * cull traversal, so that it will be drawn at render time. For most nodes + * other than GeomNodes, this is a do-nothing operation. + */ +void BulletDebugNode:: +add_for_draw(CullTraverser *trav, CullTraverserData &data) { + PT(Geom) debug_lines; + PT(Geom) debug_triangles; + + { + LightMutexHolder holder(_lock); + if (_debug_world == nullptr) { + return; + } + if (_debug_stale) { + nassertv(_debug_world != nullptr); + PStatTimer timer(_pstat_debug); + + // Collect debug geometry data + _drawer._lines.clear(); + _drawer._triangles.clear(); + + _debug_world->debugDrawWorld(); + + // Render lines + { + PT(GeomVertexData) vdata = + new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream); + vdata->unclean_set_num_rows(_drawer._lines.size() * 2); + + GeomVertexWriter vwriter(vdata, InternalName::get_vertex()); + GeomVertexWriter cwriter(vdata, InternalName::get_color()); + + pvector::const_iterator lit; + for (lit = _drawer._lines.begin(); lit != _drawer._lines.end(); lit++) { + const Line &line = *lit; + + vwriter.set_data3(line._p0); + vwriter.set_data3(line._p1); + cwriter.set_data4(LVecBase4(line._color)); + cwriter.set_data4(LVecBase4(line._color)); + } + + PT(GeomPrimitive) prim = new GeomLines(Geom::UH_stream); + prim->set_shade_model(Geom::SM_uniform); + prim->add_next_vertices(_drawer._lines.size() * 2); + + debug_lines = new Geom(vdata); + debug_lines->add_primitive(prim); + _debug_lines = debug_lines; + } + + // Render triangles + { + PT(GeomVertexData) vdata = + new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream); + vdata->unclean_set_num_rows(_drawer._triangles.size() * 3); + + GeomVertexWriter vwriter(vdata, InternalName::get_vertex()); + GeomVertexWriter cwriter(vdata, InternalName::get_color()); + + pvector::const_iterator tit; + for (tit = _drawer._triangles.begin(); tit != _drawer._triangles.end(); tit++) { + const Triangle &tri = *tit; + + vwriter.set_data3(tri._p0); + vwriter.set_data3(tri._p1); + vwriter.set_data3(tri._p2); + cwriter.set_data4(LVecBase4(tri._color)); + cwriter.set_data4(LVecBase4(tri._color)); + cwriter.set_data4(LVecBase4(tri._color)); + } + + PT(GeomPrimitive) prim = new GeomTriangles(Geom::UH_stream); + prim->set_shade_model(Geom::SM_uniform); + prim->add_next_vertices(_drawer._triangles.size() * 3); + + debug_triangles = new Geom(vdata); + debug_triangles->add_primitive(prim); + _debug_triangles = debug_triangles; + } + + // Clear collected data. + _drawer._lines.clear(); + _drawer._triangles.clear(); + + _debug_stale = false; + } else { + debug_lines = _debug_lines; + debug_triangles = _debug_triangles; + } + } + + // Record them without any state or transform. + trav->_geoms_pcollector.add_level(2); + { + CullableObject *object = + new CullableObject(move(debug_lines), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()); + trav->get_cull_handler()->record_object(object, trav); + } + { + CullableObject *object = + new CullableObject(move(debug_triangles), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()); + trav->get_cull_handler()->record_object(object, trav); + } +} + /** * */ void BulletDebugNode:: sync_b2p(btDynamicsWorld *world) { + LightMutexHolder holder(_lock); - if (is_overall_hidden()) return; - - nassertv(get_num_geoms() == 2); - - // Collect debug geometry data - _drawer._lines.clear(); - _drawer._triangles.clear(); - - world->debugDrawWorld(); - - // Get inverse of this node's net transform - NodePath np = NodePath::any_path((PandaNode *)this); - LMatrix4 m = np.get_net_transform()->get_mat(); - m.invert_in_place(); - - // Render lines - { - PT(GeomVertexData) vdata; - PT(Geom) geom; - PT(GeomLines) prim; - - vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream); - - prim = new GeomLines(Geom::UH_stream); - prim->set_shade_model(Geom::SM_uniform); - - GeomVertexWriter vwriter = GeomVertexWriter(vdata, InternalName::get_vertex()); - GeomVertexWriter cwriter = GeomVertexWriter(vdata, InternalName::get_color()); - - int v = 0; - - pvector::const_iterator lit; - for (lit = _drawer._lines.begin(); lit != _drawer._lines.end(); lit++) { - Line line = *lit; - - vwriter.add_data3(m.xform_point(line._p0)); - vwriter.add_data3(m.xform_point(line._p1)); - cwriter.add_data4(LVecBase4(line._color)); - cwriter.add_data4(LVecBase4(line._color)); - - prim->add_vertex(v++); - prim->add_vertex(v++); - prim->close_primitive(); - } - - geom = new Geom(vdata); - geom->add_primitive(prim); - - set_geom(0, geom); - } - - // Render triangles - { - PT(GeomVertexData) vdata; - PT(Geom) geom; - PT(GeomTriangles) prim; - - vdata = new GeomVertexData("", GeomVertexFormat::get_v3c4(), Geom::UH_stream); - - prim = new GeomTriangles(Geom::UH_stream); - prim->set_shade_model(Geom::SM_uniform); - - GeomVertexWriter vwriter = GeomVertexWriter(vdata, InternalName::get_vertex()); - GeomVertexWriter cwriter = GeomVertexWriter(vdata, InternalName::get_color()); - - int v = 0; - - pvector::const_iterator tit; - for (tit = _drawer._triangles.begin(); tit != _drawer._triangles.end(); tit++) { - Triangle tri = *tit; - - vwriter.add_data3(m.xform_point(tri._p0)); - vwriter.add_data3(m.xform_point(tri._p1)); - vwriter.add_data3(m.xform_point(tri._p2)); - cwriter.add_data4(LVecBase4(tri._color)); - cwriter.add_data4(LVecBase4(tri._color)); - cwriter.add_data4(LVecBase4(tri._color)); - - prim->add_vertex(v++); - prim->add_vertex(v++); - prim->add_vertex(v++); - prim->close_primitive(); - } - - geom = new Geom(vdata); - geom->add_primitive(prim); - - set_geom(1, geom); - } + _debug_world = world; + _debug_stale = true; } /** @@ -431,8 +435,6 @@ register_with_read_factory() { */ void BulletDebugNode:: write_datagram(BamWriter *manager, Datagram &dg) { - // Don't upcall to GeomNode since we're not interested in storing the actual - // debug Geoms in the .bam file. PandaNode::write_datagram(manager, dg); dg.add_bool(_wireframe); @@ -464,8 +466,6 @@ make_from_bam(const FactoryParams ¶ms) { */ void BulletDebugNode:: fillin(DatagramIterator &scan, BamReader *manager) { - // Don't upcall to GeomNode since we're not interested in storing the actual - // debug Geoms in the .bam file. PandaNode::fillin(scan, manager); _wireframe = scan.get_bool(); diff --git a/panda/src/bullet/bulletDebugNode.h b/panda/src/bullet/bulletDebugNode.h index 987e1a7450..34943865f1 100644 --- a/panda/src/bullet/bulletDebugNode.h +++ b/panda/src/bullet/bulletDebugNode.h @@ -17,13 +17,12 @@ #include "pandabase.h" #include "bullet_includes.h" - -#include "geomNode.h" +#include "lightMutex.h" /** * */ -class EXPCL_PANDABULLET BulletDebugNode : public GeomNode { +class EXPCL_PANDABULLET BulletDebugNode : public PandaNode { PUBLISHED: BulletDebugNode(const char *name="debug"); @@ -53,6 +52,9 @@ public: virtual bool safe_to_combine_children() const; virtual bool safe_to_flatten_below() const; + virtual bool is_renderable() const; + virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data); + private: void sync_b2p(btDynamicsWorld *world); @@ -100,14 +102,22 @@ private: int _mode; }; + LightMutex _lock; DebugDraw _drawer; + bool _debug_stale; + btDynamicsWorld *_debug_world; + PT(Geom) _debug_lines; + PT(Geom) _debug_triangles; + bool _wireframe; bool _constraints; bool _bounds; friend class BulletWorld; + static PStatCollector _pstat_debug; + public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); @@ -121,9 +131,9 @@ public: return _type_handle; } static void init_type() { - GeomNode::init_type(); + PandaNode::init_type(); register_type(_type_handle, "BulletDebugNode", - GeomNode::get_class_type()); + PandaNode::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/bullet/bulletWorld.I b/panda/src/bullet/bulletWorld.I index 958376ec60..c2ecd2cec3 100644 --- a/panda/src/bullet/bulletWorld.I +++ b/panda/src/bullet/bulletWorld.I @@ -55,21 +55,12 @@ INLINE BulletWorld:: */ INLINE void BulletWorld:: set_debug_node(BulletDebugNode *node) { - nassertv(node); - - _debug = node; - _world->setDebugDrawer(&(_debug->_drawer)); -} - -/** - * - */ -INLINE void BulletWorld:: -clear_debug_node() { - - _debug = NULL; - _world->setDebugDrawer(NULL); + if (node != _debug) { + clear_debug_node(); + _debug = node; + _world->setDebugDrawer(&(_debug->_drawer)); + } } /** diff --git a/panda/src/bullet/bulletWorld.cxx b/panda/src/bullet/bulletWorld.cxx index e7f6f3e267..a7942aee02 100644 --- a/panda/src/bullet/bulletWorld.cxx +++ b/panda/src/bullet/bulletWorld.cxx @@ -17,6 +17,7 @@ #include "bulletSoftBodyWorldInfo.h" #include "collideMask.h" +#include "lightMutexHolder.h" #define clamp(x, x_min, x_max) max(min(x, x_max), x_min) @@ -24,7 +25,6 @@ TypeHandle BulletWorld::_type_handle; PStatCollector BulletWorld::_pstat_physics("App:Bullet:DoPhysics"); PStatCollector BulletWorld::_pstat_simulation("App:Bullet:DoPhysics:Simulation"); -PStatCollector BulletWorld::_pstat_debug("App:Bullet:DoPhysics:Debug"); PStatCollector BulletWorld::_pstat_p2b("App:Bullet:DoPhysics:SyncP2B"); PStatCollector BulletWorld::_pstat_b2p("App:Bullet:DoPhysics:SyncB2P"); @@ -127,6 +127,19 @@ get_world_info() { return BulletSoftBodyWorldInfo(_info); } +/** + * Removes a debug node that has been assigned to this BulletWorld. + */ +void BulletWorld:: +clear_debug_node() { + if (_debug != nullptr) { + LightMutexHolder holder(_debug->_lock); + _debug->_debug_world = nullptr; + _world->setDebugDrawer(nullptr); + _debug = nullptr; + } +} + /** * */ @@ -184,9 +197,7 @@ do_physics(PN_stdfloat dt, int max_substeps, PN_stdfloat stepsize) { // Render debug if (_debug) { - _pstat_debug.start(); _debug->sync_b2p(_world); - _pstat_debug.stop(); } _pstat_physics.stop(); diff --git a/panda/src/bullet/bulletWorld.h b/panda/src/bullet/bulletWorld.h index b077e05f7a..558d086b37 100644 --- a/panda/src/bullet/bulletWorld.h +++ b/panda/src/bullet/bulletWorld.h @@ -63,7 +63,7 @@ PUBLISHED: // Debug INLINE void set_debug_node(BulletDebugNode *node); - INLINE void clear_debug_node(); + void clear_debug_node(); INLINE BulletDebugNode *get_debug_node() const; INLINE bool has_debug_node() const; @@ -208,7 +208,6 @@ private: static PStatCollector _pstat_physics; static PStatCollector _pstat_simulation; - static PStatCollector _pstat_debug; static PStatCollector _pstat_p2b; static PStatCollector _pstat_b2p;