From 0b63ba572770c2431f360a0484839f65629bd4b4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 27 Oct 2014 08:08:33 +1100 Subject: [PATCH] Move debug rendering code out of PhysicsSystem. --- .../view/render/pagedworldspacewidget.cpp | 319 ++++++++++++++---- .../view/render/pagedworldspacewidget.hpp | 4 + apps/opencs/view/world/physicssystem.cpp | 179 +--------- apps/opencs/view/world/physicssystem.hpp | 3 +- 4 files changed, 263 insertions(+), 242 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 631b9be8a..241ac2b49 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -13,6 +13,10 @@ #include #include +#include // FIXME: visual highlight, clone +#include // FIXME: visual highlight, material +#include // FIXME: visual highlight, texture + #include #include "textoverlay.hpp" #include "overlaymask.hpp" @@ -26,6 +30,89 @@ #include "elements.hpp" +namespace +{ + // FIXME: this section should be removed once the debugging is completed + void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + manual-> position(point.x, point.y, point.z-100); + manual-> position(point.x, point.y, point.z+100); + manual-> position(point.x, point.y-100, point.z); + manual-> position(point.x, point.y+100, point.z); + manual-> position(point.x-100, point.y, point.z); + manual-> position(point.x+100, point.y, point.z); + manual->end(); + sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); + } + + void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + } + + void initDebug() + { + // material for visual cue on selected objects + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); + if(texture.isNull()) + { + texture = Ogre::TextureManager::getSingleton().createManual( + "DynamicTrans", // name + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, // type + 8, 8, // width & height + 0, // number of mipmaps + Ogre::PF_BYTE_BGRA, // pixel format + Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + uint8_t* pDest = static_cast(pixelBox.data); + + // Fill in some pixel data. This will give a semi-transparent colour, + // but this is of course dependent on the chosen pixel format. + for (size_t j = 0; j < 8; j++) + { + for(size_t i = 0; i < 8; i++) + { + *pDest++ = 255; // B + *pDest++ = 255; // G + *pDest++ = 127; // R + *pDest++ = 63; // A + } + + pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); + } + pixelBuffer->unlock(); + } + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( + "TransMaterial"); + if(material.isNull()) + { + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( + "TransMaterial", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); + Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); + pass->setLightingEnabled( false ); + pass->setDepthWriteEnabled( false ); + pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); + + Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); + tex->setTextureName("DynamicTrans"); + tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); + material->load(); + } + } +} + bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; @@ -189,66 +276,11 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) // mouse picking // FIXME: need to virtualise mouse buttons - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!debug || !getCamera()->getViewport()) + if(!getCamera()->getViewport()) return; - int viewportWidth = getCamera()->getViewport()->getActualWidth(); - int viewportHeight = getCamera()->getViewport()->getActualHeight(); - - float mouseX = (float) event->x()/viewportWidth; - float mouseY = (float) event->y()/viewportHeight; - - // Need to set scene manager each time in case there are multiple subviews - CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera()); - if(result.first != "") - { - // FIXME: is there a better way to distinguish terrain from objects? - QString name = QString(result.first.c_str()); - if(name.contains(QRegExp("^HeightField"))) - { - // terrain - std::cout << "terrain: " << result.first << std::endl; - std::cout << " hit pos "+ QString::number(result.second.x).toStdString() - + ", " + QString::number(result.second.y).toStdString() - + ", " + QString::number(result.second.z).toStdString() - << std::endl; - - } - else - { - std::cout << "ReferenceId: " << result.first << std::endl; - const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); - //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId - std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; - - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.first); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() << std::endl; - } - - std::map::iterator iter (mCells.begin()); - while (iter!=mCells.end()) - { - if(iter->first.getId("dummy") == cellref.mCell) - { - //std::cout << "Cell found" << std::endl; - break; - } - ++iter; - } - flagAsModified(); - } - } + debugMousePicking((float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); } } @@ -259,17 +291,16 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event std::cout << "double clicked" << std::endl; CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!debug) - return; - - // FIXME: OEngine::PhysicEngine creates only one child scene node for the - // debug drawer. Hence only the first subview that creates the debug drawer - // can view the debug lines. Will need to keep a map in OEngine if multiple - // subviews are to be supported. - //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); - flagAsModified(); + if(userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false) + { + // FIXME: OEngine::PhysicEngine creates only one child scene node for the + // debug drawer. Hence only the first subview that creates the debug drawer + // can view the debug lines. Will need to keep a map in OEngine if multiple + // subviews are to be supported. + //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); + flagAsModified(); + } } } @@ -385,6 +416,8 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc this, SLOT (cellRemoved (const QModelIndex&, int, int))); connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); + + initDebug(); } CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() @@ -405,6 +438,19 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() removeRenderTargetListener(mOverlayMask); delete mOverlayMask; + + // For debugging only + std::map >::iterator iter = mSelectedEntities.begin(); + for(;iter != mSelectedEntities.end(); ++iter) + { + removeHitPoint(getSceneManager(), iter->first); + Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); + if(scene) + { + scene->removeAndDestroyAllChildren(); + getSceneManager()->destroySceneNode(iter->first); + } + } } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) @@ -555,3 +601,138 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int if (adjustCells()) flagAsModified(); } + + +void CSVRender::PagedWorldspaceWidget::debugMousePicking(float mouseX, float mouseY) +{ + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; + + // Need to set scene manager each time in case there are multiple subviews + CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( + mouseX, mouseY, NULL, NULL, getCamera()); + if(debug && result.first != "") + { + // FIXME: is there a better way to distinguish terrain from objects? + QString name = QString(result.first.c_str()); + if(name.contains(QRegExp("^HeightField"))) + { + // terrain + std::cout << "terrain: " << result.first << std::endl; + std::cout << " hit pos "+ QString::number(result.second.x).toStdString() + + ", " + QString::number(result.second.y).toStdString() + + ", " + QString::number(result.second.z).toStdString() + << std::endl; + } + else + { + std::string sceneNode = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + { + if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) + updateSelectionHighlight(sceneNode, result.second); + } + + std::cout << "ReferenceId: " << result.first << std::endl; + const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); + //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId + std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; + + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(result.first); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() << std::endl; + } + + std::map::iterator iter (mCells.begin()); + while (iter!=mCells.end()) + { + if(iter->first.getId("dummy") == cellref.mCell) + { + //std::cout << "Cell found" << std::endl; + break; + } + ++iter; + } + flagAsModified(); + } + } +} + +// FIXME: for debugging only +void CSVRender::PagedWorldspaceWidget::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) +{ + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debugCursor = userSettings.setting( + "debug/mouse-position", QString("false")) == "true" ? true : false; + + //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character + Ogre::SceneNode *scene = getSceneManager()->getSceneNode(sceneNode); + std::map >::iterator iter = + mSelectedEntities.find(sceneNode); + if(iter != mSelectedEntities.end()) // currently selected + { + std::vector clonedEntities = mSelectedEntities[sceneNode]; + while(!clonedEntities.empty()) + { + if(getSceneManager()->hasEntity(clonedEntities.back())) + { + scene->detachObject(clonedEntities.back()); + getSceneManager()->destroyEntity(clonedEntities.back()); + } + clonedEntities.pop_back(); + } + mSelectedEntities.erase(iter); + + if(debugCursor) + removeHitPoint(getSceneManager(), sceneNode); + } + else + { + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(!element) + break; + + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * entity = dynamic_cast(element); + if(getSceneManager()->hasEntity(entity->getName()+"cover")) + { + // FIXME: this shouldn't really happen... but does :( + scene->detachObject(entity->getName()+"cover"); + getSceneManager()->destroyEntity(entity->getName()+"cover"); + } + Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(entity->getName()+"cover"); + } + } + mSelectedEntities[sceneNode] = clonedEntities; + + if(debugCursor) + showHitPoint(getSceneManager(), sceneNode, position); + } +} diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 17b6d10c5..2c46729a8 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -26,6 +26,7 @@ namespace CSVRender bool mDisplayCellCoord; std::map mTextOverlays; OverlayMask *mOverlayMask; + std::map > mSelectedEntities; private: @@ -51,6 +52,9 @@ namespace CSVRender virtual std::string getStartupInstruction(); + void debugMousePicking(float mouseX, float mouseY); + void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index a65842bc2..154cc6273 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -5,40 +5,12 @@ #include #include #include -#include // FIXME: debug cursor position -#include // FIXME: visual highlight, clone -#include // FIXME: visual highlight, material -#include // FIXME: visual highlight, texture #include #include #include "../../model/settings/usersettings.hpp" #include "../render/elements.hpp" -namespace -{ - // FIXME: this section should be removed once the debugging is completed - void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) - { - sceneMgr->destroyManualObject("manual" + name); - Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - manual-> position(point.x, point.y, point.z-100); - manual-> position(point.x, point.y, point.z+100); - manual-> position(point.x, point.y-100, point.z); - manual-> position(point.x, point.y+100, point.z); - manual-> position(point.x-100, point.y, point.z); - manual-> position(point.x+100, point.y, point.z); - manual->end(); - sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - } - - void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) - { - sceneMgr->destroyManualObject("manual" + name); - } -} - namespace CSVWorld { PhysicsSystem *PhysicsSystem::mPhysicsSystemInstance = 0; @@ -55,15 +27,6 @@ namespace CSVWorld PhysicsSystem::~PhysicsSystem() { - std::map >::iterator iter = mSelectedEntities.begin(); - for(;iter != mSelectedEntities.end(); ++iter) - { - removeHitPoint(mSceneMgr, iter->first); - Ogre::SceneNode *scene = mSceneMgr->getSceneNode(iter->first); - scene->removeAndDestroyAllChildren(); - mSceneMgr->destroySceneNode(iter->first); - } - delete mEngine; } @@ -134,25 +97,20 @@ namespace CSVWorld mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); if(result.first == "") - return std::make_pair("", Ogre::Vector3(0,0,0)); // rayTest found nothing + return std::make_pair("", Ogre::Vector3(0,0,0)); + else + return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); + } - Ogre::Vector3 position = ray.getPoint(farClipDist*result.second); - std::string sceneNode = mRefToSceneNode[result.first]; - if(!ignoreObjects && mSceneMgr->hasSceneNode(sceneNode)) - { - if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) - updateSelectionHighlight(sceneNode, position); - } - // else terrain - return std::make_pair(result.first, position); + std::string PhysicsSystem::referenceToSceneNode(std::string reference) + { + return mRefToSceneNode[reference]; } void PhysicsSystem::setSceneManager(Ogre::SceneManager *sceneMgr) { mSceneMgr = sceneMgr; mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() - - initDebug(); } void PhysicsSystem::toggleDebugRendering() @@ -170,127 +128,4 @@ namespace CSVWorld mEngine->toggleDebugRendering(); mEngine->stepSimulation(0.0167); // DebugDrawer::step() not directly accessible } - - void PhysicsSystem::initDebug() - { - // material for visual cue on selected objects - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); - if(texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual( - "DynamicTrans", // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, // type - 8, 8, // width & height - 0, // number of mipmaps - Ogre::PF_BYTE_BGRA, // pixel format - Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); - const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - uint8_t* pDest = static_cast(pixelBox.data); - - // Fill in some pixel data. This will give a semi-transparent colour, - // but this is of course dependent on the chosen pixel format. - for (size_t j = 0; j < 8; j++) - { - for(size_t i = 0; i < 8; i++) - { - *pDest++ = 255; // B - *pDest++ = 255; // G - *pDest++ = 127; // R - *pDest++ = 63; // A - } - - pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); - } - pixelBuffer->unlock(); - } - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( - "TransMaterial"); - if(material.isNull()) - { - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( - "TransMaterial", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); - Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); - pass->setLightingEnabled( false ); - pass->setDepthWriteEnabled( false ); - pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); - - Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); - tex->setTextureName("DynamicTrans"); - tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); - material->load(); - } - } - - void PhysicsSystem::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) - { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debugCursor = userSettings.setting( - "debug/mouse-position", QString("false")) == "true" ? true : false; - - //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = mSceneMgr->getSceneNode(sceneNode); - std::map >::iterator iter = - mSelectedEntities.find(sceneNode); - if(iter != mSelectedEntities.end()) // currently selected - { - std::vector clonedEntities = mSelectedEntities[sceneNode]; - while(!clonedEntities.empty()) - { - if(mSceneMgr->hasEntity(clonedEntities.back())) - { - scene->detachObject(clonedEntities.back()); - mSceneMgr->destroyEntity(clonedEntities.back()); - } - clonedEntities.pop_back(); - } - mSelectedEntities.erase(iter); - - if(debugCursor) - removeHitPoint(mSceneMgr, sceneNode); - } - else - { - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(!element) - break; - - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * entity = dynamic_cast(element); - if(mSceneMgr->hasEntity(entity->getName()+"cover")) - { - // FIXME: this shouldn't really happen... but does :( - scene->detachObject(entity->getName()+"cover"); - mSceneMgr->destroyEntity(entity->getName()+"cover"); - } - Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(entity->getName()+"cover"); - } - } - mSelectedEntities[sceneNode] = clonedEntities; - - if(debugCursor) - showHitPoint(mSceneMgr, sceneNode, position); - } - } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 7a84a7b18..eb0028253 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -30,7 +30,6 @@ namespace CSVWorld OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; - std::map > mSelectedEntities; public: @@ -58,6 +57,8 @@ namespace CSVWorld std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + std::string referenceToSceneNode(std::string reference); + private: void initDebug();