mirror of https://github.com/OpenMW/openmw.git
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.
272 lines
11 KiB
C++
272 lines
11 KiB
C++
#include "brushdraw.hpp"
|
|
|
|
#include <limits>
|
|
#include <set>
|
|
#include <utility>
|
|
|
|
#include <osg/Array>
|
|
#include <osg/GL>
|
|
#include <osg/Geometry>
|
|
#include <osg/Group>
|
|
#include <osg/Math>
|
|
#include <osg/PrimitiveSet>
|
|
#include <osg/StateAttribute>
|
|
#include <osg/StateSet>
|
|
#include <osg/Vec4f>
|
|
|
|
#include <osgUtil/IntersectionVisitor>
|
|
#include <osgUtil/LineSegmentIntersector>
|
|
|
|
#include <components/esm3/loadland.hpp>
|
|
|
|
#include "../../model/world/cellcoordinates.hpp"
|
|
#include "../widget/brushshapes.hpp"
|
|
#include "mask.hpp"
|
|
|
|
CSVRender::BrushDraw::BrushDraw(osg::ref_ptr<osg::Group> parentNode, bool textureMode)
|
|
: mParentNode(std::move(parentNode))
|
|
, mTextureMode(textureMode)
|
|
{
|
|
mBrushDrawNode = new osg::Group();
|
|
mGeometry = new osg::Geometry();
|
|
mBrushDrawNode->addChild(mGeometry);
|
|
mBrushDrawNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
|
mBrushDrawNode->getOrCreateStateSet()->setRenderBinDetails(11, "RenderBin");
|
|
mParentNode->addChild(mBrushDrawNode);
|
|
if (mTextureMode)
|
|
mLandSizeFactor = static_cast<float>(ESM::Land::REAL_SIZE) / static_cast<float>(ESM::Land::LAND_TEXTURE_SIZE);
|
|
else
|
|
mLandSizeFactor = static_cast<float>(ESM::Land::REAL_SIZE) / static_cast<float>(ESM::Land::LAND_SIZE - 1);
|
|
}
|
|
|
|
CSVRender::BrushDraw::~BrushDraw()
|
|
{
|
|
mBrushDrawNode->removeChild(mGeometry);
|
|
mParentNode->removeChild(mBrushDrawNode);
|
|
}
|
|
|
|
float CSVRender::BrushDraw::getIntersectionHeight(const osg::Vec3d& point)
|
|
{
|
|
osg::Vec3d start = point;
|
|
osg::Vec3d end = point;
|
|
start.z() = std::numeric_limits<int>::max();
|
|
end.z() = std::numeric_limits<int>::lowest();
|
|
osg::Vec3d direction = end - start;
|
|
|
|
// Get intersection
|
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector(
|
|
new osgUtil::LineSegmentIntersector(osgUtil::Intersector::MODEL, start, end));
|
|
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
|
|
osgUtil::IntersectionVisitor visitor(intersector);
|
|
|
|
visitor.setTraversalMask(Mask_Terrain);
|
|
|
|
mParentNode->accept(visitor);
|
|
|
|
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
|
|
it != intersector->getIntersections().end(); ++it)
|
|
{
|
|
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
|
|
|
|
// reject back-facing polygons
|
|
if (direction * intersection.getWorldIntersectNormal() > 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return intersection.getWorldIntersectPoint().z();
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
void CSVRender::BrushDraw::buildPointGeometry(const osg::Vec3d& point)
|
|
{
|
|
osg::ref_ptr<osg::Geometry> geom(new osg::Geometry());
|
|
osg::ref_ptr<osg::Vec3Array> vertices(new osg::Vec3Array());
|
|
osg::ref_ptr<osg::Vec4Array> colors(new osg::Vec4Array());
|
|
const float brushOutlineHeight(1.0f);
|
|
const float crossHeadSize(8.0f);
|
|
osg::Vec4f lineColor(1.0f, 1.0f, 1.0f, 0.6f);
|
|
|
|
vertices->push_back(osg::Vec3d(point.x() - crossHeadSize, point.y() - crossHeadSize,
|
|
getIntersectionHeight(osg::Vec3d(point.x() - crossHeadSize, point.y() - crossHeadSize, point.z()))
|
|
+ brushOutlineHeight));
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(osg::Vec3d(point.x() + crossHeadSize, point.y() + crossHeadSize,
|
|
getIntersectionHeight(osg::Vec3d(point.x() + crossHeadSize, point.y() + crossHeadSize, point.z()))
|
|
+ brushOutlineHeight));
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(osg::Vec3d(point.x() + crossHeadSize, point.y() - crossHeadSize,
|
|
getIntersectionHeight(osg::Vec3d(point.x() + crossHeadSize, point.y() - crossHeadSize, point.z()))
|
|
+ brushOutlineHeight));
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(osg::Vec3d(point.x() - crossHeadSize, point.y() + crossHeadSize,
|
|
getIntersectionHeight(osg::Vec3d(point.x() - crossHeadSize, point.y() + crossHeadSize, point.z()))
|
|
+ brushOutlineHeight));
|
|
colors->push_back(lineColor);
|
|
|
|
geom->setVertexArray(vertices);
|
|
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
|
|
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 4));
|
|
mGeometry = geom;
|
|
}
|
|
|
|
void CSVRender::BrushDraw::buildSquareGeometry(const float& radius, const osg::Vec3d& point)
|
|
{
|
|
osg::ref_ptr<osg::Geometry> geom(new osg::Geometry());
|
|
osg::ref_ptr<osg::Vec3Array> vertices(new osg::Vec3Array());
|
|
osg::ref_ptr<osg::Vec4Array> colors(new osg::Vec4Array());
|
|
|
|
const float brushOutlineHeight(1.0f);
|
|
float diameter = radius * 2;
|
|
int resolution = static_cast<int>(2.f * diameter / mLandSizeFactor); // half a vertex resolution
|
|
float resAdjustedLandSizeFactor = mLandSizeFactor / 2; // 128
|
|
|
|
if (resolution > 128) // limit accuracy for performance
|
|
{
|
|
resolution = 128;
|
|
resAdjustedLandSizeFactor = diameter / resolution;
|
|
}
|
|
|
|
osg::Vec4f lineColor(1.0f, 1.0f, 1.0f, 0.6f);
|
|
|
|
for (int i = 0; i < resolution; i++)
|
|
{
|
|
int step = i * resAdjustedLandSizeFactor;
|
|
int step2 = (i + 1) * resAdjustedLandSizeFactor;
|
|
|
|
osg::Vec3d upHorizontalLinePoint1(point.x() - radius + step, point.y() - radius,
|
|
getIntersectionHeight(osg::Vec3d(point.x() - radius + step, point.y() - radius, point.z()))
|
|
+ brushOutlineHeight);
|
|
osg::Vec3d upHorizontalLinePoint2(point.x() - radius + step2, point.y() - radius,
|
|
getIntersectionHeight(osg::Vec3d(point.x() - radius + step2, point.y() - radius, point.z()))
|
|
+ brushOutlineHeight);
|
|
osg::Vec3d upVerticalLinePoint1(point.x() - radius, point.y() - radius + step,
|
|
getIntersectionHeight(osg::Vec3d(point.x() - radius, point.y() - radius + step, point.z()))
|
|
+ brushOutlineHeight);
|
|
osg::Vec3d upVerticalLinePoint2(point.x() - radius, point.y() - radius + step2,
|
|
getIntersectionHeight(osg::Vec3d(point.x() - radius, point.y() - radius + step2, point.z()))
|
|
+ brushOutlineHeight);
|
|
osg::Vec3d downHorizontalLinePoint1(point.x() + radius - step, point.y() + radius,
|
|
getIntersectionHeight(osg::Vec3d(point.x() + radius - step, point.y() + radius, point.z()))
|
|
+ brushOutlineHeight);
|
|
osg::Vec3d downHorizontalLinePoint2(point.x() + radius - step2, point.y() + radius,
|
|
getIntersectionHeight(osg::Vec3d(point.x() + radius - step2, point.y() + radius, point.z()))
|
|
+ brushOutlineHeight);
|
|
osg::Vec3d downVerticalLinePoint1(point.x() + radius, point.y() + radius - step,
|
|
getIntersectionHeight(osg::Vec3d(point.x() + radius, point.y() + radius - step, point.z()))
|
|
+ brushOutlineHeight);
|
|
osg::Vec3d downVerticalLinePoint2(point.x() + radius, point.y() + radius - step2,
|
|
getIntersectionHeight(osg::Vec3d(point.x() + radius, point.y() + radius - step2, point.z()))
|
|
+ brushOutlineHeight);
|
|
vertices->push_back(upHorizontalLinePoint1);
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(upHorizontalLinePoint2);
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(upVerticalLinePoint1);
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(upVerticalLinePoint2);
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(downHorizontalLinePoint1);
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(downHorizontalLinePoint2);
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(downVerticalLinePoint1);
|
|
colors->push_back(lineColor);
|
|
vertices->push_back(downVerticalLinePoint2);
|
|
colors->push_back(lineColor);
|
|
}
|
|
|
|
geom->setVertexArray(vertices);
|
|
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
|
|
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, resolution * 8));
|
|
mGeometry = geom;
|
|
}
|
|
|
|
void CSVRender::BrushDraw::buildCircleGeometry(const float& radius, const osg::Vec3d& point)
|
|
{
|
|
osg::ref_ptr<osg::Geometry> geom(new osg::Geometry());
|
|
osg::ref_ptr<osg::Vec3Array> vertices(new osg::Vec3Array());
|
|
osg::ref_ptr<osg::Vec4Array> colors(new osg::Vec4Array());
|
|
|
|
const int amountOfPoints = 128;
|
|
const float step((osg::PI * 2.0f) / static_cast<float>(amountOfPoints));
|
|
const float brushOutlineHeight(1.0f);
|
|
osg::Vec4f lineColor(1.0f, 1.0f, 1.0f, 0.6f);
|
|
|
|
for (int i = 0; i < amountOfPoints + 2; i++)
|
|
{
|
|
float angle(i * step);
|
|
vertices->push_back(osg::Vec3d(point.x() + radius * cosf(angle), point.y() + radius * sinf(angle),
|
|
getIntersectionHeight(
|
|
osg::Vec3d(point.x() + radius * cosf(angle), point.y() + radius * sinf(angle), point.z()))
|
|
+ brushOutlineHeight));
|
|
colors->push_back(lineColor);
|
|
angle = static_cast<float>(i + 1) * step;
|
|
vertices->push_back(osg::Vec3d(point.x() + radius * cosf(angle), point.y() + radius * sinf(angle),
|
|
getIntersectionHeight(
|
|
osg::Vec3d(point.x() + radius * cosf(angle), point.y() + radius * sinf(angle), point.z()))
|
|
+ brushOutlineHeight));
|
|
colors->push_back(lineColor);
|
|
}
|
|
|
|
geom->setVertexArray(vertices);
|
|
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
|
|
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, amountOfPoints * 2));
|
|
mGeometry = geom;
|
|
}
|
|
|
|
void CSVRender::BrushDraw::buildCustomGeometry(const float& radius, const osg::Vec3d& point)
|
|
{
|
|
// Not implemented
|
|
}
|
|
|
|
void CSVRender::BrushDraw::update(osg::Vec3d point, int brushSize, CSVWidget::BrushShape toolShape)
|
|
{
|
|
if (mBrushDrawNode->containsNode(mGeometry))
|
|
mBrushDrawNode->removeChild(mGeometry);
|
|
float radius = (mLandSizeFactor * brushSize) / 2;
|
|
osg::Vec3d snapToGridPoint = point;
|
|
if (mTextureMode)
|
|
{
|
|
std::pair<int, int> snapToGridXY = CSMWorld::CellCoordinates::toTextureCoords(point);
|
|
float offsetToMiddle = mLandSizeFactor * 0.5f;
|
|
snapToGridPoint = osg::Vec3d(
|
|
CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(snapToGridXY.first) + offsetToMiddle,
|
|
CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(snapToGridXY.second) + offsetToMiddle, point.z());
|
|
}
|
|
else
|
|
{
|
|
std::pair<int, int> snapToGridXY = CSMWorld::CellCoordinates::toVertexCoords(point);
|
|
snapToGridPoint = osg::Vec3d(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(snapToGridXY.first),
|
|
CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(snapToGridXY.second), point.z());
|
|
}
|
|
|
|
switch (toolShape)
|
|
{
|
|
case (CSVWidget::BrushShape_Point):
|
|
buildPointGeometry(snapToGridPoint);
|
|
break;
|
|
case (CSVWidget::BrushShape_Square):
|
|
buildSquareGeometry(radius, snapToGridPoint);
|
|
break;
|
|
case (CSVWidget::BrushShape_Circle):
|
|
buildCircleGeometry(radius, snapToGridPoint);
|
|
break;
|
|
case (CSVWidget::BrushShape_Custom):
|
|
buildSquareGeometry(1, snapToGridPoint);
|
|
// buildCustomGeometry
|
|
break;
|
|
}
|
|
|
|
mGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
|
|
mBrushDrawNode->addChild(mGeometry);
|
|
}
|
|
|
|
void CSVRender::BrushDraw::hide()
|
|
{
|
|
if (mBrushDrawNode->containsNode(mGeometry))
|
|
mBrushDrawNode->removeChild(mGeometry);
|
|
}
|