#include "brushdraw.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../model/world/cellcoordinates.hpp" #include "../widget/brushshapes.hpp" #include "mask.hpp" CSVRender::BrushDraw::BrushDraw(osg::ref_ptr 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(ESM::Land::REAL_SIZE) / static_cast(ESM::Land::LAND_TEXTURE_SIZE); else mLandSizeFactor = static_cast(ESM::Land::REAL_SIZE) / static_cast(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::max(); end.z() = std::numeric_limits::lowest(); osg::Vec3d direction = end - start; // Get intersection osg::ref_ptr 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 geom(new osg::Geometry()); osg::ref_ptr vertices(new osg::Vec3Array()); osg::ref_ptr 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 geom(new osg::Geometry()); osg::ref_ptr vertices(new osg::Vec3Array()); osg::ref_ptr colors(new osg::Vec4Array()); const float brushOutlineHeight(1.0f); float diameter = radius * 2; int resolution = static_cast(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 geom(new osg::Geometry()); osg::ref_ptr vertices(new osg::Vec3Array()); osg::ref_ptr colors(new osg::Vec4Array()); const int amountOfPoints = 128; const float step((osg::PI * 2.0f) / static_cast(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(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 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 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); }