You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/apps/opencs/view/render/cellborder.cpp

129 lines
4.2 KiB
C++

#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;
}