#include #include #include #include #include #include #include #include #include #include #include #include #include "bulletdebugdraw.hpp" #include "vismask.hpp" #include #include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" namespace MWRender { DebugDrawer::DebugDrawer(osg::ref_ptr parentNode, btCollisionWorld *world, int debugMode) : mParentNode(parentNode), mWorld(world) { DebugDrawer::setDebugMode(debugMode); } void DebugDrawer::createGeometry() { if (!mLinesGeometry) { mLinesGeometry = new osg::Geometry; mTrisGeometry = new osg::Geometry; mLinesGeometry->setNodeMask(Mask_Debug); mTrisGeometry->setNodeMask(Mask_Debug); mLinesVertices = new osg::Vec3Array; mTrisVertices = new osg::Vec3Array; mLinesColors = new osg::Vec4Array; mLinesDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES); mTrisDrawArrays = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES); mLinesGeometry->setUseDisplayList(false); mLinesGeometry->setVertexArray(mLinesVertices); mLinesGeometry->setColorArray(mLinesColors); mLinesGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); mLinesGeometry->setDataVariance(osg::Object::DYNAMIC); mLinesGeometry->addPrimitiveSet(mLinesDrawArrays); mTrisGeometry->setUseDisplayList(false); mTrisGeometry->setVertexArray(mTrisVertices); mTrisGeometry->setDataVariance(osg::Object::DYNAMIC); mTrisGeometry->addPrimitiveSet(mTrisDrawArrays); mParentNode->addChild(mLinesGeometry); mParentNode->addChild(mTrisGeometry); auto* stateSet = new osg::StateSet; stateSet->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE), osg::StateAttribute::ON); stateSet->setAttributeAndModes(new osg::PolygonOffset(SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0, SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0)); osg::ref_ptr material = new osg::Material; material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); stateSet->setAttribute(material); mLinesGeometry->setStateSet(stateSet); mTrisGeometry->setStateSet(stateSet); mShapesRoot = new osg::Group; mShapesRoot->setStateSet(stateSet); mShapesRoot->setDataVariance(osg::Object::DYNAMIC); mShapesRoot->setNodeMask(Mask_Debug); mParentNode->addChild(mShapesRoot); MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(mLinesGeometry, "debug"); MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(mTrisGeometry, "debug"); MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(mShapesRoot, "debug"); } } void DebugDrawer::destroyGeometry() { if (mLinesGeometry) { mParentNode->removeChild(mLinesGeometry); mParentNode->removeChild(mTrisGeometry); mParentNode->removeChild(mShapesRoot); mLinesGeometry = nullptr; mLinesVertices = nullptr; mLinesColors = nullptr; mLinesDrawArrays = nullptr; mTrisGeometry = nullptr; mTrisVertices = nullptr; mTrisDrawArrays = nullptr; } } DebugDrawer::~DebugDrawer() { destroyGeometry(); } void DebugDrawer::step() { if (mDebugOn) { mLinesVertices->clear(); mTrisVertices->clear(); mLinesColors->clear(); mShapesRoot->removeChildren(0, mShapesRoot->getNumChildren()); mWorld->debugDrawWorld(); showCollisions(); mLinesDrawArrays->setCount(mLinesVertices->size()); mTrisDrawArrays->setCount(mTrisVertices->size()); mLinesVertices->dirty(); mTrisVertices->dirty(); mLinesColors->dirty(); mLinesGeometry->dirtyBound(); mTrisGeometry->dirtyBound(); } } void DebugDrawer::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color) { mLinesVertices->push_back(Misc::Convert::toOsg(from)); mLinesVertices->push_back(Misc::Convert::toOsg(to)); mLinesColors->push_back({1,1,1,1}); mLinesColors->push_back({1,1,1,1}); #if BT_BULLET_VERSION < 317 size_t size = mLinesVertices->size(); if (size >= 6 && (*mLinesVertices)[size - 1] == (*mLinesVertices)[size - 6] && (*mLinesVertices)[size - 2] == (*mLinesVertices)[size - 3] && (*mLinesVertices)[size - 4] == (*mLinesVertices)[size - 5]) { mTrisVertices->push_back(mLinesVertices->back()); mLinesVertices->pop_back(); mLinesColors->pop_back(); mTrisVertices->push_back(mLinesVertices->back()); mLinesVertices->pop_back(); mLinesColors->pop_back(); mLinesVertices->pop_back(); mLinesColors->pop_back(); mTrisVertices->push_back(mLinesVertices->back()); mLinesVertices->pop_back(); mLinesColors->pop_back(); mLinesVertices->pop_back(); mLinesColors->pop_back(); mLinesVertices->pop_back(); mLinesColors->pop_back(); } #endif } void DebugDrawer::drawTriangle(const btVector3& v0, const btVector3& v1, const btVector3& v2, const btVector3& color, btScalar) { mTrisVertices->push_back(Misc::Convert::toOsg(v0)); mTrisVertices->push_back(Misc::Convert::toOsg(v1)); mTrisVertices->push_back(Misc::Convert::toOsg(v2)); } void DebugDrawer::addCollision(const btVector3& orig, const btVector3& normal) { mCollisionViews.emplace_back(orig, normal); } void DebugDrawer::showCollisions() { const auto now = std::chrono::steady_clock::now(); for (auto& [from, to , created] : mCollisionViews) { if (now - created < std::chrono::seconds(2)) { mLinesVertices->push_back(Misc::Convert::toOsg(from)); mLinesVertices->push_back(Misc::Convert::toOsg(to)); mLinesColors->push_back({1,0,0,1}); mLinesColors->push_back({1,0,0,1}); } } mCollisionViews.erase(std::remove_if(mCollisionViews.begin(), mCollisionViews.end(), [&now](const CollisionView& view) { return now - view.mCreated >= std::chrono::seconds(2); }), mCollisionViews.end()); } void DebugDrawer::drawSphere(btScalar radius, const btTransform& transform, const btVector3& color) { auto* geom = new osg::ShapeDrawable(new osg::Sphere(Misc::Convert::toOsg(transform.getOrigin()), radius)); geom->setColor(osg::Vec4(1, 1, 1, 1)); mShapesRoot->addChild(geom); } void DebugDrawer::reportErrorWarning(const char *warningString) { Log(Debug::Warning) << warningString; } void DebugDrawer::setDebugMode(int isOn) { mDebugOn = (isOn != 0); if (!mDebugOn) destroyGeometry(); else createGeometry(); } int DebugDrawer::getDebugMode() const { return mDebugOn; } }