From 7fb6807e653a8d1258bb8104791ffbc29b17482a Mon Sep 17 00:00:00 2001
From: Aesylwinn <kyleacooley@gmail.com>
Date: Wed, 2 Mar 2016 15:02:06 -0500
Subject: [PATCH] cell border markers

---
 apps/opencs/CMakeLists.txt             |  2 +-
 apps/opencs/view/render/cell.cpp       |  3 +
 apps/opencs/view/render/cell.hpp       |  2 +
 apps/opencs/view/render/cellborder.cpp | 97 ++++++++++++++++++++++++++
 apps/opencs/view/render/cellborder.hpp | 54 ++++++++++++++
 5 files changed, 157 insertions(+), 1 deletion(-)
 create mode 100644 apps/opencs/view/render/cellborder.cpp
 create mode 100644 apps/opencs/view/render/cellborder.hpp

diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt
index 74f311c5fe..f78c411d20 100644
--- a/apps/opencs/CMakeLists.txt
+++ b/apps/opencs/CMakeLists.txt
@@ -90,7 +90,7 @@ opencs_units (view/render
 
 opencs_units_noqt (view/render
     lighting lightingday lightingnight
-    lightingbright object cell terrainstorage tagbase cellarrow cellmarker
+    lightingbright object cell terrainstorage tagbase cellarrow cellmarker cellborder
     )
 
 opencs_hdrs_noqt (view/render
diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp
index 641aeb0883..5348f4683c 100644
--- a/apps/opencs/view/render/cell.cpp
+++ b/apps/opencs/view/render/cell.cpp
@@ -93,6 +93,9 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
                 mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Mask_Terrain));
                 mTerrain->loadCell(esmLand.mX,
                                    esmLand.mY);
+
+                mCellBorder.reset(new CellBorder(mCellNode, mCoordinates));
+                mCellBorder->buildShape(esmLand);
             }
         }
     }
diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp
index 22f9872e3d..54f5bea1ed 100644
--- a/apps/opencs/view/render/cell.hpp
+++ b/apps/opencs/view/render/cell.hpp
@@ -16,6 +16,7 @@
 #include "object.hpp"
 #include "cellarrow.hpp"
 #include "cellmarker.hpp"
+#include "cellborder.hpp"
 
 class QModelIndex;
 
@@ -44,6 +45,7 @@ namespace CSVRender
             CSMWorld::CellCoordinates mCoordinates;
             std::auto_ptr<CellArrow> mCellArrows[4];
             std::auto_ptr<CellMarker> mCellMarker;
+            std::auto_ptr<CellBorder> mCellBorder;
             bool mDeleted;
 
             /// Ignored if cell does not have an object with the given ID.
diff --git a/apps/opencs/view/render/cellborder.cpp b/apps/opencs/view/render/cellborder.cpp
new file mode 100644
index 0000000000..fd0492e5d9
--- /dev/null
+++ b/apps/opencs/view/render/cellborder.cpp
@@ -0,0 +1,97 @@
+#include "cellborder.hpp"
+
+#include <osg/Group>
+#include <osg/PositionAttitudeTransform>
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/PrimitiveSet>
+
+#include <components/esm/loadland.hpp>
+
+#include "mask.hpp"
+
+#include "../../model/world/cellcoordinates.hpp"
+
+const int CSVRender::CellBorder::CellSize = ESM::Land::REAL_SIZE;
+const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 3;
+
+
+CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords)
+    : mParentNode(cellNode)
+{
+    mBaseNode = new osg::PositionAttitudeTransform();
+    mBaseNode->setNodeMask(Mask_CellBorder);
+    mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10));
+
+    mParentNode->addChild(mBaseNode);
+}
+
+CSVRender::CellBorder::~CellBorder()
+{
+    mParentNode->removeChild(mBaseNode);
+}
+
+void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand)
+{
+    const ESM::Land::LandData* landData = esmLand.getLandData(ESM::Land::DATA_VHGT);
+
+    if (!landData)
+        return;
+
+    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
+
+    // Vertices
+    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array();
+
+    int x = 0, y = 0;
+    for (; x < ESM::Land::LAND_SIZE; ++x)
+        vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
+
+    x = ESM::Land::LAND_SIZE - 1;
+    for (; y < ESM::Land::LAND_SIZE; ++y)
+        vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
+
+    y = ESM::Land::LAND_SIZE - 1;
+    for (; x >= 0; --x)
+        vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
+
+    x = 0;
+    for (; y >= 0; --y)
+        vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)]));
+
+    geometry->setVertexArray(vertices);
+
+    // Color
+    osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array();
+    colors->push_back(osg::Vec4f(0.f, 0.5f, 0.f, 1.f));
+
+    geometry->setColorArray(colors);
+    geometry->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE_SET);
+
+    // Primitive
+    osg::ref_ptr<osg::DrawElementsUShort> primitives =
+        new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount+1);
+
+    for (size_t i = 0; i < VertexCount; ++i)
+        primitives->setElement(i, i);
+
+    primitives->setElement(VertexCount, 0);
+
+    geometry->addPrimitiveSet(primitives);
+    geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+
+
+    osg::ref_ptr<osg::Geode> geode = new osg::Geode();
+    geode->addDrawable(geometry);
+    mBaseNode->addChild(geode);
+}
+
+size_t CSVRender::CellBorder::landIndex(int x, int y)
+{
+    return y * ESM::Land::LAND_SIZE + x;
+}
+
+float CSVRender::CellBorder::scaleToWorld(int value)
+{
+    return (CellSize + 128) * (float)value / ESM::Land::LAND_SIZE;
+}
diff --git a/apps/opencs/view/render/cellborder.hpp b/apps/opencs/view/render/cellborder.hpp
new file mode 100644
index 0000000000..c91aa46c69
--- /dev/null
+++ b/apps/opencs/view/render/cellborder.hpp
@@ -0,0 +1,54 @@
+#ifndef OPENCS_VIEW_CELLBORDER_H
+#define OPENCS_VIEW_CELLBORDER_H
+
+#include <cstddef>
+
+#include <osg/ref_ptr>
+
+namespace osg
+{
+    class Group;
+    class PositionAttitudeTransform;
+}
+
+namespace ESM
+{
+    struct Land;
+}
+
+namespace CSMWorld
+{
+    class CellCoordinates;
+}
+
+namespace CSVRender
+{
+
+    class CellBorder
+    {
+    public:
+
+        CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords);
+        ~CellBorder();
+
+        void buildShape(const ESM::Land& esmLand);
+
+    private:
+
+        static const int CellSize;
+        static const int VertexCount;
+
+        size_t landIndex(int x, int y);
+        float scaleToWorld(int val);
+
+        // unimplemented
+        CellBorder(const CellBorder&);
+        CellBorder& operator=(const CellBorder&);
+
+        osg::Group* mParentNode;
+        osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
+
+    };
+}
+
+#endif