From 7dd7be7f0ec646a8691877ad0e51defd103f00a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Jan 2016 08:56:15 +0100 Subject: [PATCH] make scenes drop target for referenceables --- apps/opencs/view/render/instancemode.cpp | 84 +++++++++++++++++++ apps/opencs/view/render/instancemode.hpp | 4 + .../view/render/pagedworldspacewidget.cpp | 11 +++ .../view/render/pagedworldspacewidget.hpp | 2 + .../view/render/unpagedworldspacewidget.cpp | 5 ++ .../view/render/unpagedworldspacewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 48 +++++++++++ apps/opencs/view/render/worldspacewidget.hpp | 13 +++ 8 files changed, 169 insertions(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index a4d147bb4..6c3593369 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,8 +1,13 @@ #include "instancemode.hpp" +#include + #include "../../model/prefs/state.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/commands.hpp" + #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" @@ -55,3 +60,82 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) } } } + +void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event) +{ + if (const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData())) + { + if (!mime->fromDocument (getWorldspaceWidget().getDocument())) + return; + + /// \todo document check + if (mime->holdsType (CSMWorld::UniversalId::Type_Referenceable)) + event->accept(); + } +} + +void CSVRender::InstanceMode::dropEvent (QDropEvent* event) +{ + if (const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData())) + { + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + + if (!mime->fromDocument (document)) + return; + + osg::Vec3f insertPoint = getWorldspaceWidget().getIntersectionPoint (event->pos()); + + std::string cellId = getWorldspaceWidget().getCellId (insertPoint); + + bool dropped = false; + + std::vector ids = mime->getData(); + + CSMWorld::IdTable& referencesTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_References)); + + CSMWorld::IdTable& cellTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + + for (std::vector::const_iterator iter (ids.begin()); + iter!=ids.end(); ++iter) + if (mime->isReferencable (iter->getType())) + { + // create reference + std::auto_ptr createCommand ( + new CSMWorld::CreateCommand ( + referencesTable, document.getData().getReferences().getNewId())); + + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_Cell), QString::fromUtf8 (cellId.c_str())); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionXPos), insertPoint.x()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionYPos), insertPoint.y()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionZPos), insertPoint.z()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_ReferenceableId), + QString::fromUtf8 (iter->getId().c_str())); + + // increase reference count in cell + QModelIndex countIndex = cellTable.getModelIndex (cellId, + cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter)); + + int count = cellTable.data (countIndex).toInt(); + + std::auto_ptr incrementCommand ( + new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + + document.getUndoStack().beginMacro (createCommand->text()); + document.getUndoStack().push (createCommand.release()); + document.getUndoStack().push (incrementCommand.release()); + document.getUndoStack().endMacro(); + + dropped = true; + } + + if (dropped) + event->accept(); + } +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 66451bd99..7649c241c 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -20,6 +20,10 @@ namespace CSVRender virtual void primarySelectPressed (osg::ref_ptr tag); virtual void secondarySelectPressed (osg::ref_ptr tag); + + virtual void dragEnterEvent (QDragEnterEvent *event); + + virtual void dropEvent (QDropEvent* event); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index dae5990e6..e30f238a2 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -504,6 +504,17 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const +{ + const int cellSize = 8192; + + CSMWorld::CellCoordinates cellCoordinates ( + static_cast (std::floor (point.x()/cellSize)), + static_cast (std::floor (point.y()/cellSize))); + + return cellCoordinates.getId (mWorldspace); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index e983fddd5..bc8e0da64 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -96,6 +96,8 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 68f068dac..701f50825 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -108,6 +108,11 @@ void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const +{ + return mCellId; +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 9e6fa97f4..70a20c216 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -46,6 +46,8 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f0d398641..0383b0bcf 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -315,6 +315,54 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() return mDocument; } +osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& localPos, + unsigned int interactionMask, bool ignoreHidden) const +{ + // (0,0) is considered the lower left corner of an OpenGL window + int x = localPos.x(); + int y = height() - localPos.y(); + + osg::ref_ptr intersector ( + new osgUtil::LineSegmentIntersector (osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit (osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor (intersector); + + unsigned int mask = interactionMask; + + if (ignoreHidden) + mask &= getVisibilityMask(); + + visitor.setTraversalMask (mask << 1); + + mView->getCamera()->accept (visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersector->getIntersections().begin(); + iter!=intersector->getIntersections().end(); ++iter) + { + // reject back-facing polygons + osg::Vec3f normal = osg::Matrix::transform3x3 ( + iter->getWorldIntersectNormal(), mView->getCamera()->getViewMatrix()); + + if (normal.z()>=0) + return iter->getWorldIntersectPoint(); + } + + osg::Matrixd matrix; + matrix.preMult (mView->getCamera()->getViewport()->computeWindowMatrix()); + matrix.preMult (mView->getCamera()->getProjectionMatrix()); + matrix.preMult (mView->getCamera()->getViewMatrix()); + matrix = osg::Matrixd::inverse (matrix); + + osg::Vec3d start = matrix.preMult (intersector->getStart()); + osg::Vec3d end = matrix.preMult (intersector->getEnd()); + + osg::Vec3d direction = end-start; + direction.normalize(); + + return start+direction * 50; +} + void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 54376cee4..0edf9f0b2 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -127,6 +127,19 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask) = 0; + /// Return the next intersection point with scene elements matched by + /// \a interactionMask based on \a localPos and the camera vector. + /// If there is no such point, instead a point "in front" of \a localPos will be + /// returned. + /// + /// \param ignoreHidden ignore elements specified in interactionMask that are + /// flagged as not visible. + osg::Vec3f getIntersectionPoint (const QPoint& localPos, + unsigned int interactionMask = Element_Reference | Element_Terrain, + bool ignoreHidden = false) const; + + virtual std::string getCellId (const osg::Vec3f& point) const = 0; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool);