From 2fe2def64c0822e6ac7992484cb7de859a61d03b Mon Sep 17 00:00:00 2001
From: Marc Zinnschlag <marc@zpages.de>
Date: Sun, 29 Jun 2014 16:00:06 +0200
Subject: [PATCH] added cell rendering in paged worldspaces

---
 .../view/render/pagedworldspacewidget.cpp     | 134 +++++++++++++++++-
 .../view/render/pagedworldspacewidget.hpp     |  25 ++++
 apps/opencs/view/render/scenewidget.cpp       |   7 +-
 apps/opencs/view/render/scenewidget.hpp       |   2 +
 apps/opencs/view/render/worldspacewidget.hpp  |  12 +-
 5 files changed, 171 insertions(+), 9 deletions(-)

diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp
index a3f34d218..20cd6abb5 100644
--- a/apps/opencs/view/render/pagedworldspacewidget.cpp
+++ b/apps/opencs/view/render/pagedworldspacewidget.cpp
@@ -3,14 +3,137 @@
 
 #include <sstream>
 
+#include <OgreCamera.h>
+
 #include <QtGui/qevent.h>
 
-#include <apps/opencs/model/world/tablemimedata.hpp>
+#include "../../model/world/tablemimedata.hpp"
+#include "../../model/world/idtable.hpp"
+
+bool CSVRender::PagedWorldspaceWidget::adjustCells()
+{
+    bool modified = false;
+    bool setCamera = false;
+
+    {
+        // remove
+        std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+
+        while (iter!=mCells.end())
+        {
+            if (!mSelection.has (iter->first))
+            {
+                delete iter->second;
+                mCells.erase (iter++);
+                modified = true;
+            }
+            else
+                ++iter;
+        }
+    }
+
+    if (mCells.begin()==mCells.end())
+        setCamera = true;
+
+    // add
+    for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end();
+        ++iter)
+    {
+        if (mCells.find (*iter)==mCells.end())
+        {
+            if (setCamera)
+            {
+                setCamera = false;
+                getCamera()->setPosition (8192*iter->getX()+4096, 8192*iter->getY()+4096, 0);
+            }
+
+            mCells.insert (std::make_pair (*iter,
+                new Cell (mDocument.getData(), getSceneManager(),
+                iter->getId ("std::default"))));
+
+            modified = true;
+        }
+    }
+
+    return modified;
+}
+
+void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
+    const QModelIndex& bottomRight)
+{
+    for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+        iter!=mCells.end(); ++iter)
+        if (iter->second->referenceableDataChanged (topLeft, bottomRight))
+            flagAsModified();
+}
+
+void CSVRender::PagedWorldspaceWidget::referenceableAboutToBeRemoved (
+    const QModelIndex& parent, int start, int end)
+{
+    for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+        iter!=mCells.end(); ++iter)
+        if (iter->second->referenceableAboutToBeRemoved (parent, start, end))
+            flagAsModified();
+}
+
+void CSVRender::PagedWorldspaceWidget::referenceableAdded (const QModelIndex& parent,
+    int start, int end)
+{
+    CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
+        *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_Referenceables));
+
+    for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+        iter!=mCells.end(); ++iter)
+    {
+        QModelIndex topLeft = referenceables.index (start, 0);
+        QModelIndex bottomRight =
+            referenceables.index (end, referenceables.columnCount());
+
+        if (iter->second->referenceableDataChanged (topLeft, bottomRight))
+            flagAsModified();
+    }
+}
+
+void CSVRender::PagedWorldspaceWidget::referenceDataChanged (const QModelIndex& topLeft,
+    const QModelIndex& bottomRight)
+{
+    for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+        iter!=mCells.end(); ++iter)
+        if (iter->second->referenceDataChanged (topLeft, bottomRight))
+            flagAsModified();
+}
+
+void CSVRender::PagedWorldspaceWidget::referenceAboutToBeRemoved (const QModelIndex& parent,
+    int start, int end)
+{
+    for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+        iter!=mCells.end(); ++iter)
+        if (iter->second->referenceAboutToBeRemoved (parent, start, end))
+            flagAsModified();
+}
+
+void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent, int start,
+    int end)
+{
+    for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+        iter!=mCells.end(); ++iter)
+        if (iter->second->referenceAdded (parent, start, end))
+            flagAsModified();
+}
+
+
 
 CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
-: WorldspaceWidget (document, parent)
+: WorldspaceWidget (document, parent), mDocument (document)
 {}
 
+CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget()
+{
+    for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
+        iter!=mCells.end(); ++iter)
+        delete iter->second;
+}
+
 void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
 {
     if (!hint.empty())
@@ -47,6 +170,10 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
 void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSelection& selection)
 {
     mSelection = selection;
+
+    if (adjustCells())
+        flagAsModified();
+
     emit cellSelectionChanged (mSelection);
 }
 
@@ -72,6 +199,9 @@ void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::
     }
     if (selectionChanged)
     {
+        if (adjustCells())
+            flagAsModified();
+
         emit cellSelectionChanged(mSelection);
     }
 }
diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp
index 0a73c791c..7f9a66f82 100644
--- a/apps/opencs/view/render/pagedworldspacewidget.hpp
+++ b/apps/opencs/view/render/pagedworldspacewidget.hpp
@@ -1,9 +1,12 @@
 #ifndef OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
 #define OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
 
+#include <map>
+
 #include "../../model/world/cellselection.hpp"
 
 #include "worldspacewidget.hpp"
+#include "cell.hpp"
 
 namespace CSVRender
 {
@@ -11,12 +14,32 @@ namespace CSVRender
     {
             Q_OBJECT
 
+            CSMDoc::Document& mDocument;
             CSMWorld::CellSelection mSelection;
+            std::map<CSMWorld::CellCoordinates, Cell *> mCells;
 
         private:
 
             std::pair<int, int> getCoordinatesFromId(const std::string& record) const;
 
+            /// Bring mCells into sync with mSelection again.
+            ///
+            /// \return Any cells added or removed?
+            bool adjustCells();
+
+            virtual void referenceableDataChanged (const QModelIndex& topLeft,
+                const QModelIndex& bottomRight);
+
+            virtual void referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
+
+            virtual void referenceableAdded (const QModelIndex& index, int start, int end);
+
+            virtual void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
+
+            virtual void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
+
+            virtual void referenceAdded (const QModelIndex& index, int start, int end);
+
         public:
 
             PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
@@ -24,6 +47,8 @@ namespace CSVRender
             /// no cells are displayed. The cells to be displayed will be specified later through
             /// hint system.
 
+            virtual ~PagedWorldspaceWidget();
+
             void useViewHint (const std::string& hint);
 
             void setCellSelection (const CSMWorld::CellSelection& selection);
diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp
index eccaebd00..76f6db385 100644
--- a/apps/opencs/view/render/scenewidget.cpp
+++ b/apps/opencs/view/render/scenewidget.cpp
@@ -43,7 +43,7 @@ namespace CSVRender
         mCamera->setPosition (300, 0, 0);
         mCamera->lookAt (0, 0, 0);
         mCamera->setNearClipDistance (0.1);
-        mCamera->setFarClipDistance (30000);
+        mCamera->setFarClipDistance (300000); ///< \todo make this configurable
         mCamera->roll (Ogre::Degree (90));
 
         setLighting (&mLightingDay);
@@ -137,6 +137,11 @@ namespace CSVRender
         return mSceneMgr;
     }
 
+    Ogre::Camera *SceneWidget::getCamera()
+    {
+        return mCamera;
+    }
+
     void SceneWidget::flagAsModified()
     {
         mUpdate = true;
diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp
index 7f8f104f1..f6b41942f 100644
--- a/apps/opencs/view/render/scenewidget.hpp
+++ b/apps/opencs/view/render/scenewidget.hpp
@@ -49,6 +49,8 @@ namespace CSVRender
 
             Ogre::SceneManager *getSceneManager();
 
+            Ogre::Camera *getCamera();
+
             void flagAsModified();
 
             void setDefaultAmbient (const Ogre::ColourValue& colour);
diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp
index 280f9436d..2af90b0fe 100644
--- a/apps/opencs/view/render/worldspacewidget.hpp
+++ b/apps/opencs/view/render/worldspacewidget.hpp
@@ -80,17 +80,17 @@ namespace CSVRender
             void selectNavigationMode (const std::string& mode);
 
             virtual void referenceableDataChanged (const QModelIndex& topLeft,
-                const QModelIndex& bottomRight) {}
+                const QModelIndex& bottomRight) = 0;
 
-            virtual void referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) {}
+            virtual void referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0;
 
-            virtual void referenceableAdded (const QModelIndex& index, int start, int end) {}
+            virtual void referenceableAdded (const QModelIndex& index, int start, int end) = 0;
 
-            virtual void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) {}
+            virtual void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 0;
 
-            virtual void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) {}
+            virtual void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0;
 
-            virtual void referenceAdded (const QModelIndex& index, int start, int end) {}
+            virtual void referenceAdded (const QModelIndex& index, int start, int end) = 0;
 
         signals: