open_toontown_panda3d/panda/src/bullet/bulletDebugNode.cxx

477 lines
13 KiB
C++

/**
* 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."
*
* @file bulletDebugNode.cxx
* @author enn0x
* @date 2010-01-23
*/
#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) : PandaNode(name) {
_debug_stale = false;
_debug_world = nullptr;
_wireframe = true;
_constraints = true;
_bounds = false;
_drawer._normals = true;
CPT (BoundingVolume) bounds = new OmniBoundingVolume();
set_bounds(bounds);
set_final(true);
set_overall_hidden(true);
}
/**
* Returns true if it is generally safe to flatten out this particular kind of
* Node by duplicating instances, false otherwise (for instance, a Camera
* cannot be safely flattened, because the Camera pointer itself is
* meaningful).
*/
bool BulletDebugNode::
safe_to_flatten() const {
return false;
}
/**
* Returns true if it is generally safe to transform this particular kind of
* Node by calling the xform() method, false otherwise. For instance, it's
* usually a bad idea to attempt to xform a Character.
*/
bool BulletDebugNode::
safe_to_transform() const {
return false;
}
/**
* Returns true if it is safe to automatically adjust the transform on this
* kind of node. Usually, this is only a bad idea if the user expects to find
* a particular transform on the node.
*
* ModelNodes with the preserve_transform flag set are presently the only
* kinds of nodes that should not have their transform even adjusted.
*/
bool BulletDebugNode::
safe_to_modify_transform() const {
return false;
}
/**
* Returns true if it is generally safe to combine this particular kind of
* PandaNode with other kinds of PandaNodes of compatible type, adding
* children or whatever. For instance, an LODNode should not be combined with
* any other PandaNode, because its set of children is meaningful.
*/
bool BulletDebugNode::
safe_to_combine() const {
return false;
}
/**
* Returns true if it is generally safe to combine the children of this
* PandaNode with each other. For instance, an LODNode's children should not
* be combined with each other, because the set of children is meaningful.
*/
bool BulletDebugNode::
safe_to_combine_children() const {
return false;
}
/**
* Returns true if a flatten operation may safely continue past this node, or
* false if nodes below this node may not be molested.
*/
bool BulletDebugNode::
safe_to_flatten_below() const {
return false;
}
/**
*
*/
void BulletDebugNode::
draw_mask_changed() {
if (is_overall_hidden()) {
_drawer.setDebugMode(DebugDraw::DBG_NoDebug);
}
else {
int mode = DebugDraw::DBG_DrawText |
DebugDraw::DBG_DrawFeaturesText |
DebugDraw::DBG_DrawContactPoints;
if (_wireframe) {
mode |= DebugDraw::DBG_DrawWireframe;
}
if (_constraints) {
mode |= DebugDraw::DBG_DrawConstraints;
mode |= DebugDraw::DBG_DrawConstraintLimits;
}
if (_bounds) {
mode |= DebugDraw::DBG_DrawAabb;
}
_drawer.setDebugMode(mode);
}
}
/**
* 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(BulletWorld::get_global_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<Line>::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<Triangle>::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::
do_sync_b2p(btDynamicsWorld *world) {
_debug_world = world;
_debug_stale = true;
}
/**
*
*/
void BulletDebugNode::DebugDraw::
setDebugMode(int mode) {
_mode = mode;
}
/**
*
*/
int BulletDebugNode::DebugDraw::
getDebugMode() const {
return _mode;
}
/**
*
*/
void BulletDebugNode::DebugDraw::
reportErrorWarning(const char *warning) {
bullet_cat.error() << warning << endl;
}
/**
*
*/
void BulletDebugNode::DebugDraw::
drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) {
PN_stdfloat r = color.getX();
PN_stdfloat g = color.getY();
PN_stdfloat b = color.getZ();
// Hack to get rid of triangle normals. The hack is based on the assumption
// that only normals are drawn in yellow.
if (_normals==false && r==1.0f && g==1.0f && b==0.0f) return;
Line line;
line._p0 = LVecBase3((PN_stdfloat)from.getX(),
(PN_stdfloat)from.getY(),
(PN_stdfloat)from.getZ());
line._p1 = LVecBase3((PN_stdfloat)to.getX(),
(PN_stdfloat)to.getY(),
(PN_stdfloat)to.getZ());
line._color = UnalignedLVecBase4((PN_stdfloat)r,
(PN_stdfloat)g,
(PN_stdfloat)b, 1.0f);
_lines.push_back(line);
}
/**
*
*/
void BulletDebugNode::DebugDraw::
drawTriangle(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &color, btScalar) {
btScalar r = color.getX();
btScalar g = color.getY();
btScalar b = color.getZ();
Triangle tri;
tri._p0 = LVecBase3((PN_stdfloat)v0.getX(),
(PN_stdfloat)v0.getY(),
(PN_stdfloat)v0.getZ());
tri._p1 = LVecBase3((PN_stdfloat)v1.getX(),
(PN_stdfloat)v1.getY(),
(PN_stdfloat)v1.getZ());
tri._p2 = LVecBase3((PN_stdfloat)v2.getX(),
(PN_stdfloat)v2.getY(),
(PN_stdfloat)v2.getZ());
tri._color = UnalignedLVecBase4((PN_stdfloat)r,
(PN_stdfloat)g,
(PN_stdfloat)b, 1.0f);
_triangles.push_back(tri);
// Draw the triangle's normal
/*
btVector3 x1 = v1 - v0;
btVector3 x2 = v2 - v0;
btVector3 normal = v1.cross(v2).normalize();
btVector3 from = (v0 + v1 + v2) * 0.3333;
btVector3 to = from + normal;
drawLine(from, to, color);
*/
}
/**
*
*/
void BulletDebugNode::DebugDraw::
drawTriangle(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, const btVector3 &n0, const btVector3 &n1, const btVector3 &n2, const btVector3 &color, btScalar alpha) {
bullet_cat.debug() << "drawTriangle(2) - not yet implemented!" << endl;
}
/**
*
*/
void BulletDebugNode::DebugDraw::
drawContactPoint(const btVector3 &point, const btVector3 &normal, btScalar distance, int lifetime, const btVector3 &color) {
const btVector3 to = point + normal * distance;
const btVector3 &from = point;
drawLine(from, to, color);
}
/**
*
*/
void BulletDebugNode::DebugDraw::
draw3dText(const btVector3 &location, const char *text) {
bullet_cat.debug() << "draw3dText - not yet implemented!" << endl;
}
/**
*
*/
void BulletDebugNode::DebugDraw::
drawSphere(btScalar radius, const btTransform &transform, const btVector3 &color) {
btVector3 center = transform.getOrigin();
const btVector3 xoffs = transform.getBasis() * btVector3(1, 0, 0);
const btVector3 yoffs = transform.getBasis() * btVector3(0, 1, 0);
const btVector3 zoffs = transform.getBasis() * btVector3(0, 0, 1);
drawArc(center, xoffs, yoffs, radius, radius, 0, SIMD_2_PI, color, false, 10.0);
drawArc(center, yoffs, zoffs, radius, radius, 0, SIMD_2_PI, color, false, 10.0);
drawArc(center, zoffs, xoffs, radius, radius, 0, SIMD_2_PI, color, false, 10.0);
}
/**
* Tells the BamReader how to create objects of type BulletDebugNode.
*/
void BulletDebugNode::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
/**
* Writes the contents of this object to the datagram for shipping out to a
* Bam file.
*/
void BulletDebugNode::
write_datagram(BamWriter *manager, Datagram &dg) {
PandaNode::write_datagram(manager, dg);
dg.add_bool(_wireframe);
dg.add_bool(_constraints);
dg.add_bool(_bounds);
dg.add_bool(_drawer._normals);
}
/**
* This function is called by the BamReader's factory when a new object of
* this type is encountered in the Bam file. It should create the rigid body
* and extract its information from the file.
*/
TypedWritable *BulletDebugNode::
make_from_bam(const FactoryParams &params) {
BulletDebugNode *param = new BulletDebugNode;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
param->fillin(scan, manager);
return param;
}
/**
* This internal function is called by make_from_bam to read in all of the
* relevant data from the BamFile for the new BulletDebugNode.
*/
void BulletDebugNode::
fillin(DatagramIterator &scan, BamReader *manager) {
PandaNode::fillin(scan, manager);
_wireframe = scan.get_bool();
_constraints = scan.get_bool();
_bounds = scan.get_bool();
_drawer._normals = scan.get_bool();
}