diff --git a/CHANGELOG.md b/CHANGELOG.md index f43c9f9d1..bc764da11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -270,6 +270,7 @@ Feature #5170: Editor: Land shape editing, land selection Feature #5172: Editor: Delete instances/references with keypress in scene window Feature #5193: Weapon sheathing + Feature #5201: Editor: Show tool outline in scene view, when using editmodes Feature #5219: Impelement TestCells console command Feature #5224: Handle NiKeyframeController for NiTriShape Feature #5274: Editor: Keyboard shortcut to drop objects to ground/obstacle in scene view diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index af8bf8d55..6d0f2ad9f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -89,7 +89,7 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller - cellwater terraintexturemode actor terrainselection terrainshapemode + cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw ) opencs_units_noqt (view/render diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 9f98c7b4c..af8c26d70 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -91,9 +91,14 @@ std::pair CSMWorld::CellCoordinates::toVertexCoords(const osg::Vec3d& return std::make_pair(x, y); } -float CSMWorld::CellCoordinates::textureGlobalToWorldCoords(int textureGlobal) +float CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(int textureGlobal) { - return ESM::Land::REAL_SIZE * static_cast(textureGlobal) / ESM::Land::LAND_TEXTURE_SIZE; + return ESM::Land::REAL_SIZE * (static_cast(textureGlobal) + 0.25f) / ESM::Land::LAND_TEXTURE_SIZE; +} + +float CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(int textureGlobal) +{ + return ESM::Land::REAL_SIZE * (static_cast(textureGlobal) - 0.25f) / ESM::Land::LAND_TEXTURE_SIZE; } float CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(int vertexGlobal) diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index 77d76f6ef..9317c28b2 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -54,8 +54,11 @@ namespace CSMWorld ///Converts worldspace coordinates to global vertex selection. static std::pair toVertexCoords(const osg::Vec3d& worldPos); - ///Converts global texture coordinate to worldspace coordinate that is at the upper left corner of the selected texture. - static float textureGlobalToWorldCoords(int textureGlobal); + ///Converts global texture coordinate X to worldspace coordinate, offset by 0.25f. + static float textureGlobalXToWorldCoords(int textureGlobal); + + ///Converts global texture coordinate Y to worldspace coordinate, offset by 0.25f. + static float textureGlobalYToWorldCoords(int textureGlobal); ///Converts global vertex coordinate to worldspace coordinate static float vertexGlobalToWorldCoords(int vertexGlobal); diff --git a/apps/opencs/view/render/brushdraw.cpp b/apps/opencs/view/render/brushdraw.cpp new file mode 100644 index 000000000..9a648336e --- /dev/null +++ b/apps/opencs/view/render/brushdraw.cpp @@ -0,0 +1,308 @@ +#include "brushdraw.hpp" + +#include + +#include +#include +#include + +#include + +#include + +#include "../../model/world/cellcoordinates.hpp" +#include "../widget/brushshapes.hpp" + +CSVRender::BrushDraw::BrushDraw(osg::ref_ptr parentNode, bool textureMode) : + mParentNode(parentNode), mTextureMode(textureMode) +{ + mBrushDrawNode = new osg::Group(); + mGeometry = new osg::Geometry(); + mBrushDrawNode->addChild(mGeometry); + mParentNode->addChild(mBrushDrawNode); + if (mTextureMode) + mLandSizeFactor = ESM::Land::REAL_SIZE / ESM::Land::LAND_TEXTURE_SIZE; + else mLandSizeFactor = ESM::Land::REAL_SIZE / ESM::Land::LAND_SIZE; +} + +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(SceneUtil::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 = (diameter / mLandSizeFactor) * 2; //half a vertex resolution + float resAdjustedLandSizeFactor = mLandSizeFactor / 2; + 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 = (osg::PI * 2.0f) * radius / 20; + 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); + mBrushDrawNode->setNodeMask (SceneUtil::Mask_GUI); + 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); +} diff --git a/apps/opencs/view/render/brushdraw.hpp b/apps/opencs/view/render/brushdraw.hpp new file mode 100644 index 000000000..0551631cd --- /dev/null +++ b/apps/opencs/view/render/brushdraw.hpp @@ -0,0 +1,36 @@ +#ifndef CSV_RENDER_BRUSHDRAW_H +#define CSV_RENDER_BRUSHDRAW_H + +#include +#include + +#include +#include "../widget/brushshapes.hpp" + +namespace CSVRender +{ + class BrushDraw + { + public: + BrushDraw(osg::ref_ptr parentNode, bool textureMode = false); + ~BrushDraw(); + + void update(osg::Vec3d point, int brushSize, CSVWidget::BrushShape toolShape); + void hide(); + + private: + void buildPointGeometry(const osg::Vec3d& point); + void buildSquareGeometry(const float& radius, const osg::Vec3d& point); + void buildCircleGeometry(const float& radius, const osg::Vec3d& point); + void buildCustomGeometry(const float& radius, const osg::Vec3d& point); + float getIntersectionHeight (const osg::Vec3d& point); + + osg::ref_ptr mParentNode; + osg::ref_ptr mBrushDrawNode; + osg::ref_ptr mGeometry; + bool mTextureMode; + float mLandSizeFactor; + }; +} + +#endif diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 03451bc1b..ca4aa0fd5 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -73,6 +73,8 @@ void CSVRender::EditMode::dropEvent (QDropEvent *event) {} void CSVRender::EditMode::dragMoveEvent (QDragMoveEvent *event) {} +void CSVRender::EditMode::mouseMoveEvent (QMouseEvent *event) {} + int CSVRender::EditMode::getSubMode() const { return -1; diff --git a/apps/opencs/view/render/editmode.hpp b/apps/opencs/view/render/editmode.hpp index 9f3b28957..911594327 100644 --- a/apps/opencs/view/render/editmode.hpp +++ b/apps/opencs/view/render/editmode.hpp @@ -98,6 +98,8 @@ namespace CSVRender /// Default-implementation: ignored virtual void dragMoveEvent (QDragMoveEvent *event); + virtual void mouseMoveEvent (QMouseEvent *event); + /// Default: return -1 virtual int getSubMode() const; }; diff --git a/apps/opencs/view/render/terrainselection.cpp b/apps/opencs/view/render/terrainselection.cpp index e16a69048..4e209af57 100644 --- a/apps/opencs/view/render/terrainselection.cpp +++ b/apps/opencs/view/render/terrainselection.cpp @@ -171,9 +171,6 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+(i-1), y2)+2)); - vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y + 1) - nudgeOffset, calculateLandHeight(x1+i, y2)+2)); + 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)+2)); + vertices->push_back(osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y + 1), calculateLandHeight(x1+i, y2)+2)); } } @@ -208,10 +205,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(drawPreviousX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+(i-1), y1)+2)); - vertices->push_back(osg::Vec3f(drawCurrentX + nudgeOffset, CSMWorld::CellCoordinates::textureGlobalToWorldCoords(y) - nudgeOffset, calculateLandHeight(x1+i, y1)+2)); + 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)+2)); + vertices->push_back(osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1+i, y1)+2)); } } @@ -220,10 +217,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x + 1) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x2, y1+(i-1))+2)); - vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x + 1) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x2, y1+i)+2)); + 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))+2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x + 1), drawCurrentY, calculateLandHeight(x2, y1+i)+2)); } } @@ -232,10 +229,10 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptrpush_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + nudgeOffset, drawPreviousY - nudgeOffset, calculateLandHeight(x1, y1+(i-1))+2)); - vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalToWorldCoords(x) + nudgeOffset, drawCurrentY - nudgeOffset, calculateLandHeight(x1, y1+i)+2)); + 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))+2)); + vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x), drawCurrentY, calculateLandHeight(x1, y1+i)+2)); } } } diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index 2a6d7f33f..6df5ee836 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -37,6 +37,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/universalid.hpp" +#include "brushdraw.hpp" #include "editmode.hpp" #include "pagedworldspacewidget.hpp" #include "tagbase.hpp" @@ -67,6 +68,9 @@ void CSVRender::TerrainShapeMode::activate(CSVWidget::SceneToolbar* toolbar) connect(mShapeBrushScenetool->mShapeBrushWindow->mToolStrengthSlider, SIGNAL(valueChanged(int)), this, SLOT(setShapeEditToolStrength(int))); } + if (!mBrushDraw) + mBrushDraw.reset(new BrushDraw(mParentNode)); + EditMode::activate(toolbar); toolbar->addTool (mShapeBrushScenetool); } @@ -83,6 +87,9 @@ void CSVRender::TerrainShapeMode::deactivate(CSVWidget::SceneToolbar* toolbar) mTerrainShapeSelection.reset(); } + if (mBrushDraw) + mBrushDraw.reset(); + EditMode::deactivate(toolbar); } @@ -1382,6 +1389,15 @@ void CSVRender::TerrainShapeMode::dragMoveEvent (QDragMoveEvent *event) { } +void CSVRender::TerrainShapeMode::mouseMoveEvent (QMouseEvent *event) +{ + WorldspaceHitResult hit = getWorldspaceWidget().mousePick(event->pos(), getInteractionMask()); + if (hit.hit && mBrushDraw && !(mShapeEditTool == ShapeEditTool_Drag && mIsEditing)) + mBrushDraw->update(hit.worldPos, mBrushSize, mBrushShape); + if (!hit.hit && mBrushDraw && !(mShapeEditTool == ShapeEditTool_Drag && mIsEditing)) + mBrushDraw->hide(); +} + void CSVRender::TerrainShapeMode::setBrushSize(int brushSize) { mBrushSize = brushSize; diff --git a/apps/opencs/view/render/terrainshapemode.hpp b/apps/opencs/view/render/terrainshapemode.hpp index 68f2fbf9d..d0fec764f 100644 --- a/apps/opencs/view/render/terrainshapemode.hpp +++ b/apps/opencs/view/render/terrainshapemode.hpp @@ -19,6 +19,7 @@ #include "../widget/brushshapes.hpp" #endif +#include "brushdraw.hpp" #include "terrainselection.hpp" namespace CSVWidget @@ -89,6 +90,7 @@ namespace CSVRender void dragWheel (int diff, double speedFactor) final; void dragMoveEvent (QDragMoveEvent *event) final; + void mouseMoveEvent (QMouseEvent *event) final; private: @@ -168,6 +170,7 @@ namespace CSVRender std::string mBrushTexture; int mBrushSize = 1; CSVWidget::BrushShape mBrushShape = CSVWidget::BrushShape_Point; + std::unique_ptr mBrushDraw; std::vector> mCustomBrushShape; CSVWidget::SceneToolShapeBrush *mShapeBrushScenetool = nullptr; int mDragMode = InteractionType_None; diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index efdb600b8..d4656b578 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -32,7 +32,9 @@ #include "../../model/world/resourcetable.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/universalid.hpp" +#include "../widget/brushshapes.hpp" +#include "brushdraw.hpp" #include "editmode.hpp" #include "pagedworldspacewidget.hpp" #include "object.hpp" // Something small needed regarding pointers from here () @@ -42,7 +44,7 @@ CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceW : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference, "Terrain texture editing", parent), mBrushTexture("L0#0"), mBrushSize(1), - mBrushShape(0), + mBrushShape(CSVWidget::BrushShape_Point), mTextureBrushScenetool(nullptr), mDragMode(InteractionType_None), mParentNode(parentNode), @@ -57,7 +59,7 @@ void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) mTextureBrushScenetool = new CSVWidget::SceneToolTextureBrush (toolbar, "scenetooltexturebrush", getWorldspaceWidget().getDocument()); connect(mTextureBrushScenetool, SIGNAL (clicked()), mTextureBrushScenetool, SLOT (activate())); connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushSize(int)), this, SLOT(setBrushSize(int))); - connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setBrushShape(int))); + connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passBrushShape(CSVWidget::BrushShape)), this, SLOT(setBrushShape(CSVWidget::BrushShape))); connect(mTextureBrushScenetool->mTextureBrushWindow->mSizeSliders->mBrushSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrushSize(int))); connect(mTextureBrushScenetool, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string))); connect(mTextureBrushScenetool->mTextureBrushWindow, SIGNAL(passTextureId(std::string)), this, SLOT(setBrushTexture(std::string))); @@ -72,6 +74,9 @@ void CSVRender::TerrainTextureMode::activate(CSVWidget::SceneToolbar* toolbar) mTerrainTextureSelection.reset(new TerrainSelection(mParentNode, &getWorldspaceWidget(), TerrainSelectionType::Texture)); } + if (!mBrushDraw) + mBrushDraw.reset(new BrushDraw(mParentNode, true)); + EditMode::activate(toolbar); toolbar->addTool (mTextureBrushScenetool); } @@ -90,6 +95,9 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar) mTerrainTextureSelection.reset(); } + if (mBrushDraw) + mBrushDraw.reset(); + EditMode::deactivate(toolbar); } @@ -328,11 +336,9 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe std::string mBrushTextureInt = mBrushTexture.substr (hashlocation+1); int brushInt = stoi(mBrushTexture.substr (hashlocation+1))+1; // All indices are offset by +1 - int rf = mBrushSize / 2; - int r = mBrushSize / 2 + 1; - int distance = 0; + int r = static_cast(mBrushSize) / 2; - if (mBrushShape == 0) + if (mBrushShape == CSVWidget::BrushShape_Point) { CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); @@ -344,7 +350,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } - if (mBrushShape == 1) + if (mBrushShape == CSVWidget::BrushShape_Square) { int upperLeftCellX = cellX - std::floor(r / landTextureSize); int upperLeftCellY = cellY - std::floor(r / landTextureSize); @@ -394,7 +400,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } - if (mBrushShape == 2) + if (mBrushShape == CSVWidget::BrushShape_Circle) { int upperLeftCellX = cellX - std::floor(r / landTextureSize); int upperLeftCellY = cellY - std::floor(r / landTextureSize); @@ -419,7 +425,6 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe { for(int j = 0; j < landTextureSize; j++) { - if (i_cell == cellX && j_cell == cellY && abs(i-xHitInCell) < r && abs(j-yHitInCell) < r) { int distanceX(0); @@ -430,7 +435,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); - distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + float distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + float rf = static_cast(mBrushSize) / 2; if (distance < rf) newTerrain[j*landTextureSize+i] = brushInt; } else @@ -443,7 +449,8 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe if (j_cell > cellY) distanceY = -yHitInCell + landTextureSize * abs(j_cell-cellY) + j; if (i_cell == cellX) distanceX = abs(i-xHitInCell); if (j_cell == cellY) distanceY = abs(j-yHitInCell); - distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + float distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); + float rf = static_cast(mBrushSize) / 2; if (distance < rf) newTerrain[j*landTextureSize+i] = brushInt; } } @@ -454,7 +461,7 @@ void CSVRender::TerrainTextureMode::editTerrainTextureGrid(const WorldspaceHitRe } } - if (mBrushShape == 3) + if (mBrushShape == CSVWidget::BrushShape_Custom) { CSMWorld::LandTexturesColumn::DataType newTerrainPointer = landTable.data(landTable.getModelIndex(mCellId, textureColumn)).value(); CSMWorld::LandTexturesColumn::DataType newTerrain(newTerrainPointer); @@ -506,12 +513,12 @@ void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair> selections; - if (mBrushShape == 0) + if (mBrushShape == CSVWidget::BrushShape_Point) { if (isInCellSelection(texCoords.first, texCoords.second)) selections.emplace_back(texCoords); } - if (mBrushShape == 1) + if (mBrushShape == CSVWidget::BrushShape_Square) { for (int i = -r; i <= r; i++) { @@ -527,14 +534,15 @@ void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair(mBrushSize) / 2; + if (std::round(coords.length()) < rf) { int x = i + texCoords.first; int y = j + texCoords.second; @@ -547,7 +555,7 @@ void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pairpos(), getInteractionMask()); + if (hit.hit && mBrushDraw) + mBrushDraw->update(hit.worldPos, mBrushSize, mBrushShape); + if (!hit.hit && mBrushDraw) + mBrushDraw->hide(); +} + + void CSVRender::TerrainTextureMode::setBrushSize(int brushSize) { mBrushSize = brushSize; } -void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) +void CSVRender::TerrainTextureMode::setBrushShape(CSVWidget::BrushShape brushShape) { mBrushShape = brushShape; //Set custom brush shape - if (mBrushShape == 3 && !mTerrainTextureSelection->getTerrainSelection().empty()) + if (mBrushShape == CSVWidget::BrushShape_Custom && !mTerrainTextureSelection->getTerrainSelection().empty()) { auto terrainSelection = mTerrainTextureSelection->getTerrainSelection(); int selectionCenterX = 0; diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 4176abefe..0d8c4a94a 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -17,6 +17,8 @@ #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/landtexture.hpp" +#include "../widget/brushshapes.hpp" +#include "brushdraw.hpp" #endif #include "terrainselection.hpp" @@ -81,6 +83,8 @@ namespace CSVRender void dragWheel (int diff, double speedFactor) final; void dragMoveEvent (QDragMoveEvent *event) final; + void mouseMoveEvent (QMouseEvent *event) final; + private: /// \brief Handle brush mechanics, maths regarding worldspace hit etc. void editTerrainTextureGrid (const WorldspaceHitResult& hit); @@ -104,7 +108,8 @@ namespace CSVRender std::string mCellId; std::string mBrushTexture; int mBrushSize; - int mBrushShape; + CSVWidget::BrushShape mBrushShape; + std::unique_ptr mBrushDraw; std::vector> mCustomBrushShape; CSVWidget::SceneToolTextureBrush *mTextureBrushScenetool; int mDragMode; @@ -121,7 +126,7 @@ namespace CSVRender public slots: void handleDropEvent(QDropEvent *event); void setBrushSize(int brushSize); - void setBrushShape(int brushShape); + void setBrushShape(CSVWidget::BrushShape brushShape); void setBrushTexture(std::string brushShape); }; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 6ab4b041b..4755de97b 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -613,6 +613,8 @@ void CSVRender::WorldspaceWidget::updateOverlay() void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { + dynamic_cast (*mEditMode->getCurrent()).mouseMoveEvent (event); + if (mDragging) { int diffX = event->x() - mDragX; diff --git a/apps/opencs/view/widget/scenetooltexturebrush.cpp b/apps/opencs/view/widget/scenetooltexturebrush.cpp index 408187279..35937f1a6 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.cpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.cpp @@ -57,9 +57,6 @@ CSVWidget::BrushSizeControls::BrushSizeControls(const QString &title, QWidget *p CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QWidget *parent) : QFrame(parent, Qt::Popup), - mBrushShape(0), - mBrushSize(1), - mBrushTexture("L0#0"), mDocument(document) { mBrushTextureLabel = "Selected texture: " + mBrushTexture + " "; @@ -207,10 +204,14 @@ void CSVWidget::TextureBrushWindow::setBrushSize(int brushSize) void CSVWidget::TextureBrushWindow::setBrushShape() { - if(mButtonPoint->isChecked()) mBrushShape = 0; - if(mButtonSquare->isChecked()) mBrushShape = 1; - if(mButtonCircle->isChecked()) mBrushShape = 2; - if(mButtonCustom->isChecked()) mBrushShape = 3; + if (mButtonPoint->isChecked()) + mBrushShape = CSVWidget::BrushShape_Point; + if (mButtonSquare->isChecked()) + mBrushShape = CSVWidget::BrushShape_Square; + if (mButtonCircle->isChecked()) + mBrushShape = CSVWidget::BrushShape_Circle; + if (mButtonCustom->isChecked()) + mBrushShape = CSVWidget::BrushShape_Custom; emit passBrushShape(mBrushShape); } @@ -228,7 +229,7 @@ CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, c mBrushHistory[0] = "L0#0"; setAcceptDrops(true); - connect(mTextureBrushWindow, SIGNAL(passBrushShape(int)), this, SLOT(setButtonIcon(int))); + connect(mTextureBrushWindow, SIGNAL(passBrushShape(CSVWidget::BrushShape)), this, SLOT(setButtonIcon(CSVWidget::BrushShape))); setButtonIcon(mTextureBrushWindow->mBrushShape); mPanel = new QFrame (this, Qt::Popup); @@ -258,31 +259,31 @@ CSVWidget::SceneToolTextureBrush::SceneToolTextureBrush (SceneToolbar *parent, c } -void CSVWidget::SceneToolTextureBrush::setButtonIcon (int brushShape) +void CSVWidget::SceneToolTextureBrush::setButtonIcon (CSVWidget::BrushShape brushShape) { QString tooltip = "Change brush settings

Currently selected: "; switch (brushShape) { - case 0: + case BrushShape_Point: setIcon (QIcon (QPixmap (":scenetoolbar/brush-point"))); tooltip += mTextureBrushWindow->toolTipPoint; break; - case 1: + case BrushShape_Square: setIcon (QIcon (QPixmap (":scenetoolbar/brush-square"))); tooltip += mTextureBrushWindow->toolTipSquare; break; - case 2: + case BrushShape_Circle: setIcon (QIcon (QPixmap (":scenetoolbar/brush-circle"))); tooltip += mTextureBrushWindow->toolTipCircle; break; - case 3: + case BrushShape_Custom: setIcon (QIcon (QPixmap (":scenetoolbar/brush-custom"))); tooltip += mTextureBrushWindow->toolTipCustom; diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 80e9a9382..5f5ccc6b1 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -15,6 +15,7 @@ #include #ifndef Q_MOC_RUN +#include "brushshapes.hpp" #include "scenetool.hpp" #include "../../model/doc/document.hpp" @@ -65,9 +66,9 @@ namespace CSVWidget const QString toolTipCustom = "Paint custom selection (not implemented yet)"; private: - int mBrushShape; - int mBrushSize; - std::string mBrushTexture; + CSVWidget::BrushShape mBrushShape = CSVWidget::BrushShape_Point; + int mBrushSize = 1; + std::string mBrushTexture = "L0#0"; CSMDoc::Document& mDocument; QLabel *mSelectedBrush; QGroupBox *mHorizontalGroupBox; @@ -88,7 +89,7 @@ namespace CSVWidget signals: void passBrushSize (int brushSize); - void passBrushShape(int brushShape); + void passBrushShape(CSVWidget::BrushShape brushShape); void passTextureId(std::string brushTexture); }; @@ -120,7 +121,7 @@ namespace CSVWidget friend class CSVRender::TerrainTextureMode; public slots: - void setButtonIcon(int brushShape); + void setButtonIcon(CSVWidget::BrushShape brushShape); void updateBrushHistory (const std::string& mBrushTexture); void clicked (const QModelIndex& index); virtual void activate();