mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-30 12:32:36 +00:00
20da0892ef
Slowly moving through the open-cs errors Good progress in openCS Very good progress on openCS Getting closer with openCS OpenCS compiles and runs! Didn't have time to test it all though ix openMW everything compiles on windows?? Fix gcc Fix Clang
348 lines
14 KiB
C++
348 lines
14 KiB
C++
#include "terrainselection.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
#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 <apps/opencs/model/doc/document.hpp>
|
|
#include <apps/opencs/model/world/cellcoordinates.hpp>
|
|
#include <apps/opencs/model/world/data.hpp>
|
|
#include <apps/opencs/model/world/idcollection.hpp>
|
|
#include <apps/opencs/model/world/land.hpp>
|
|
#include <apps/opencs/model/world/record.hpp>
|
|
|
|
#include <components/esm3/loadland.hpp>
|
|
|
|
#include "cell.hpp"
|
|
#include "worldspacewidget.hpp"
|
|
|
|
namespace CSMWorld
|
|
{
|
|
struct Cell;
|
|
}
|
|
|
|
CSVRender::TerrainSelection::TerrainSelection(
|
|
osg::Group* parentNode, WorldspaceWidget* worldspaceWidget, TerrainSelectionType type)
|
|
: mParentNode(parentNode)
|
|
, mWorldspaceWidget(worldspaceWidget)
|
|
, mSelectionType(type)
|
|
{
|
|
mGeometry = new osg::Geometry();
|
|
|
|
mSelectionNode = new osg::Group();
|
|
mSelectionNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
|
mSelectionNode->getOrCreateStateSet()->setRenderBinDetails(11, "RenderBin");
|
|
mSelectionNode->addChild(mGeometry);
|
|
|
|
activate();
|
|
}
|
|
|
|
CSVRender::TerrainSelection::~TerrainSelection()
|
|
{
|
|
deactivate();
|
|
}
|
|
|
|
std::vector<std::pair<int, int>> CSVRender::TerrainSelection::getTerrainSelection() const
|
|
{
|
|
return mSelection;
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::onlySelect(const std::vector<std::pair<int, int>>& localPositions)
|
|
{
|
|
mSelection = localPositions;
|
|
|
|
update();
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::addSelect(const std::vector<std::pair<int, int>>& localPositions)
|
|
{
|
|
handleSelection(localPositions, SelectionMethod::AddSelect);
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::removeSelect(const std::vector<std::pair<int, int>>& localPositions)
|
|
{
|
|
handleSelection(localPositions, SelectionMethod::RemoveSelect);
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::toggleSelect(const std::vector<std::pair<int, int>>& localPositions)
|
|
{
|
|
handleSelection(localPositions, SelectionMethod::ToggleSelect);
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::clearTemporarySelection()
|
|
{
|
|
mTemporarySelection.clear();
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::activate()
|
|
{
|
|
if (!mParentNode->containsNode(mSelectionNode))
|
|
mParentNode->addChild(mSelectionNode);
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::deactivate()
|
|
{
|
|
mParentNode->removeChild(mSelectionNode);
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::update()
|
|
{
|
|
mSelectionNode->removeChild(mGeometry);
|
|
mGeometry = new osg::Geometry();
|
|
|
|
const osg::ref_ptr<osg::Vec3Array> vertices(new osg::Vec3Array);
|
|
|
|
switch (mSelectionType)
|
|
{
|
|
case TerrainSelectionType::Texture:
|
|
drawTextureSelection(vertices);
|
|
break;
|
|
case TerrainSelectionType::Shape:
|
|
drawShapeSelection(vertices);
|
|
break;
|
|
}
|
|
|
|
mGeometry->setVertexArray(vertices);
|
|
osg::ref_ptr<osg::DrawArrays> drawArrays = new osg::DrawArrays(osg::PrimitiveSet::LINES);
|
|
drawArrays->setCount(vertices->size());
|
|
if (vertices->size() != 0)
|
|
mGeometry->addPrimitiveSet(drawArrays);
|
|
mSelectionNode->addChild(mGeometry);
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::drawShapeSelection(const osg::ref_ptr<osg::Vec3Array> vertices)
|
|
{
|
|
if (!mSelection.empty())
|
|
{
|
|
for (std::pair<int, int>& localPos : mSelection)
|
|
{
|
|
int x(localPos.first);
|
|
int y(localPos.second);
|
|
|
|
float xWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x));
|
|
float yWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y));
|
|
|
|
osg::Vec3f pointXY(xWorldCoord, yWorldCoord, calculateLandHeight(x, y));
|
|
|
|
vertices->push_back(pointXY);
|
|
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y - 1),
|
|
calculateLandHeight(x, y - 1)));
|
|
vertices->push_back(pointXY);
|
|
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x - 1), yWorldCoord,
|
|
calculateLandHeight(x - 1, y)));
|
|
vertices->push_back(pointXY);
|
|
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y + 1),
|
|
calculateLandHeight(x, y + 1)));
|
|
vertices->push_back(pointXY);
|
|
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x + 1), yWorldCoord,
|
|
calculateLandHeight(x + 1, y)));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr<osg::Vec3Array> vertices)
|
|
{
|
|
if (!mSelection.empty())
|
|
{
|
|
const int landHeightsNudge = (ESM::Land::REAL_SIZE / ESM::Land::LAND_SIZE)
|
|
/ (ESM::Land::LAND_SIZE - 1); // Does this work with all land size configurations?
|
|
|
|
const int textureSizeToLandSizeModifier = (ESM::Land::LAND_SIZE - 1) / ESM::Land::LAND_TEXTURE_SIZE;
|
|
|
|
for (std::pair<int, int>& localPos : mSelection)
|
|
{
|
|
int x(localPos.first);
|
|
int y(localPos.second);
|
|
|
|
// convert texture selection to global vertex coordinates at selection box corners
|
|
int x1 = x * textureSizeToLandSizeModifier + landHeightsNudge;
|
|
int x2 = x * textureSizeToLandSizeModifier + textureSizeToLandSizeModifier + landHeightsNudge;
|
|
int y1 = y * textureSizeToLandSizeModifier - landHeightsNudge;
|
|
int y2 = y * textureSizeToLandSizeModifier + textureSizeToLandSizeModifier - landHeightsNudge;
|
|
|
|
// Draw edges (check all sides, draw lines between vertices, +1 height to keep lines above ground)
|
|
// Check adjancent selections, draw lines only to edges of the selection
|
|
const auto north = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y + 1));
|
|
if (north == mSelection.end())
|
|
{
|
|
for (int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
|
{
|
|
float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x)
|
|
+ (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x)
|
|
+ i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
vertices->push_back(
|
|
osg::Vec3f(drawPreviousX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y + 1),
|
|
calculateLandHeight(x1 + (i - 1), y2)));
|
|
vertices->push_back(
|
|
osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y + 1),
|
|
calculateLandHeight(x1 + i, y2)));
|
|
}
|
|
}
|
|
|
|
const auto south = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y - 1));
|
|
if (south == mSelection.end())
|
|
{
|
|
for (int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
|
{
|
|
float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x)
|
|
+ (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x)
|
|
+ i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
vertices->push_back(
|
|
osg::Vec3f(drawPreviousX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y),
|
|
calculateLandHeight(x1 + (i - 1), y1)));
|
|
vertices->push_back(osg::Vec3f(drawCurrentX,
|
|
CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1 + i, y1)));
|
|
}
|
|
}
|
|
|
|
const auto east = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x + 1, y));
|
|
if (east == mSelection.end())
|
|
{
|
|
for (int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
|
{
|
|
float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y)
|
|
+ (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y)
|
|
+ i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x + 1),
|
|
drawPreviousY, calculateLandHeight(x2, y1 + (i - 1))));
|
|
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x + 1),
|
|
drawCurrentY, calculateLandHeight(x2, y1 + i)));
|
|
}
|
|
}
|
|
|
|
const auto west = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x - 1, y));
|
|
if (west == mSelection.end())
|
|
{
|
|
for (int i = 1; i < (textureSizeToLandSizeModifier + 1); i++)
|
|
{
|
|
float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y)
|
|
+ (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y)
|
|
+ i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
|
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x),
|
|
drawPreviousY, calculateLandHeight(x1, y1 + (i - 1))));
|
|
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x),
|
|
drawCurrentY, calculateLandHeight(x1, y1 + i)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSVRender::TerrainSelection::handleSelection(
|
|
const std::vector<std::pair<int, int>>& localPositions, SelectionMethod selectionMethod)
|
|
{
|
|
for (auto const& localPos : localPositions)
|
|
{
|
|
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
|
|
|
switch (selectionMethod)
|
|
{
|
|
case SelectionMethod::OnlySelect:
|
|
break;
|
|
|
|
case SelectionMethod::AddSelect:
|
|
if (iter == mSelection.end())
|
|
{
|
|
mSelection.emplace_back(localPos);
|
|
}
|
|
break;
|
|
|
|
case SelectionMethod::RemoveSelect:
|
|
if (iter != mSelection.end())
|
|
{
|
|
mSelection.erase(iter);
|
|
}
|
|
break;
|
|
|
|
case SelectionMethod::ToggleSelect:
|
|
{
|
|
const auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos);
|
|
if (iterTemp == mTemporarySelection.end())
|
|
{
|
|
if (iter == mSelection.end())
|
|
{
|
|
mSelection.emplace_back(localPos);
|
|
}
|
|
else
|
|
{
|
|
mSelection.erase(iter);
|
|
}
|
|
}
|
|
mTemporarySelection.emplace_back(localPos);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
bool CSVRender::TerrainSelection::noCell(const std::string& cellId)
|
|
{
|
|
CSMDoc::Document& document = mWorldspaceWidget->getDocument();
|
|
const CSMWorld::IdCollection<CSMWorld::Cell>& cellCollection = document.getData().getCells();
|
|
return cellCollection.searchId(cellId) == -1;
|
|
}
|
|
|
|
bool CSVRender::TerrainSelection::noLand(const std::string& cellId)
|
|
{
|
|
CSMDoc::Document& document = mWorldspaceWidget->getDocument();
|
|
const CSMWorld::IdCollection<CSMWorld::Land>& landCollection = document.getData().getLand();
|
|
return landCollection.searchId(cellId) == -1;
|
|
}
|
|
|
|
bool CSVRender::TerrainSelection::noLandLoaded(const std::string& cellId)
|
|
{
|
|
CSMDoc::Document& document = mWorldspaceWidget->getDocument();
|
|
const CSMWorld::IdCollection<CSMWorld::Land>& landCollection = document.getData().getLand();
|
|
return !landCollection.getRecord(ESM::RefId::stringRefId(cellId)).get().isDataLoaded(ESM::Land::DATA_VNML);
|
|
}
|
|
|
|
bool CSVRender::TerrainSelection::isLandLoaded(const std::string& cellId)
|
|
{
|
|
if (!noCell(cellId) && !noLand(cellId) && !noLandLoaded(cellId))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
int CSVRender::TerrainSelection::calculateLandHeight(int x, int y) // global vertex coordinates
|
|
{
|
|
int cellX = std::floor(static_cast<float>(x) / (ESM::Land::LAND_SIZE - 1));
|
|
int cellY = std::floor(static_cast<float>(y) / (ESM::Land::LAND_SIZE - 1));
|
|
int localX = x - cellX * (ESM::Land::LAND_SIZE - 1);
|
|
int localY = y - cellY * (ESM::Land::LAND_SIZE - 1);
|
|
|
|
CSMWorld::CellCoordinates coords(cellX, cellY);
|
|
|
|
float landHeight = 0.f;
|
|
if (CSVRender::Cell* cell = dynamic_cast<CSVRender::Cell*>(mWorldspaceWidget->getCell(coords)))
|
|
{
|
|
landHeight = cell->getSumOfAlteredAndTrueHeight(cellX, cellY, localX, localY);
|
|
}
|
|
else if (isLandLoaded(CSMWorld::CellCoordinates::generateId(cellX, cellY)))
|
|
{
|
|
CSMDoc::Document& document = mWorldspaceWidget->getDocument();
|
|
std::string cellId = CSMWorld::CellCoordinates::generateId(cellX, cellY);
|
|
const ESM::Land::LandData* landData
|
|
= document.getData().getLand().getRecord(ESM::RefId::stringRefId(cellId)).get().getLandData(ESM::Land::DATA_VHGT);
|
|
return landData->mHeights[localY * ESM::Land::LAND_SIZE + localX];
|
|
}
|
|
|
|
return landHeight;
|
|
}
|