1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
#include "cellborder.hpp"
#include <osg/Array>
#include <osg/GL>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <osg/PrimitiveSet>
#include <osg/StateAttribute>
#include <osg/StateSet>
#include <osg/Vec3f>
#include <osg/Vec4f>
#include <components/esm3/loadland.hpp>
#include "mask.hpp"
#include "../../model/world/cellcoordinates.hpp"
const int CSVRender::CellBorder::CellSize = ESM::Land::REAL_SIZE;
/*
The number of vertices per cell border is equal to the number of vertices per edge
minus the duplicated corner vertices. An additional vertex to close the loop is NOT needed.
*/
const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 4;
CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords)
: mParentNode(cellNode)
{
mBorderGeometry = new osg::Geometry();
mBaseNode = new osg::PositionAttitudeTransform();
mBaseNode->setNodeMask(Mask_CellBorder);
mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10));
mBaseNode->addChild(mBorderGeometry);
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);
mBaseNode->removeChild(mBorderGeometry);
mBorderGeometry = new osg::Geometry();
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array();
int x = 0;
int y = 0;
/*
Traverse the cell border counter-clockwise starting at the SW corner vertex (0, 0).
Each loop starts at a corner vertex and ends right before the next corner vertex.
*/
if (landData)
{
for (; x < ESM::Land::LAND_SIZE - 1; ++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 - 1; ++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)]));
}
else
{
for (; x < ESM::Land::LAND_SIZE - 1; ++x)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
x = ESM::Land::LAND_SIZE - 1;
for (; y < ESM::Land::LAND_SIZE - 1; ++y)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
y = ESM::Land::LAND_SIZE - 1;
for (; x > 0; --x)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
x = 0;
for (; y > 0; --y)
vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), ESM::Land::DEFAULT_HEIGHT));
}
mBorderGeometry->setVertexArray(vertices);
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array();
colors->push_back(osg::Vec4f(0.f, 0.5f, 0.f, 1.f));
mBorderGeometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET);
osg::ref_ptr<osg::DrawElementsUShort> primitives
= new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount + 1);
// Assign one primitive to each vertex.
for (size_t i = 0; i < VertexCount; ++i)
primitives->setElement(i, i);
// Assign the last primitive to the first vertex to close the loop.
primitives->setElement(VertexCount, 0);
mBorderGeometry->addPrimitiveSet(primitives);
mBorderGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
mBaseNode->addChild(mBorderGeometry);
}
size_t CSVRender::CellBorder::landIndex(int x, int y)
{
return static_cast<size_t>(y) * ESM::Land::LAND_SIZE + x;
}
float CSVRender::CellBorder::scaleToWorld(int value)
{
return (CellSize + 128) * (float)value / ESM::Land::LAND_SIZE;
}
|