mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 07:45:39 +00:00
Merge branch 'sm-snap-to-reference' into 'master'
Open-CS: Snap to Reference See merge request OpenMW/openmw!2484
This commit is contained in:
commit
fa50890633
17 changed files with 257 additions and 19 deletions
|
@ -397,6 +397,8 @@ void CSMPrefs::State::declare()
|
|||
declareShortcut("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton));
|
||||
declareShortcut(
|
||||
"scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
|
||||
declareShortcut(
|
||||
"scene-select-tertiary", "Tertiary Select", QKeySequence(Qt::ShiftModifier | (int)Qt::MiddleButton));
|
||||
declareModifier("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift);
|
||||
declareShortcut("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete));
|
||||
declareShortcut("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G));
|
||||
|
|
|
@ -599,6 +599,18 @@ bool CSVRender::Cell::isDeleted() const
|
|||
return mDeleted;
|
||||
}
|
||||
|
||||
osg::ref_ptr<CSVRender::TagBase> CSVRender::Cell::getSnapTarget(unsigned int elementMask) const
|
||||
{
|
||||
osg::ref_ptr<TagBase> result;
|
||||
|
||||
if (elementMask & Mask_Reference)
|
||||
for (auto& obj : mObjects)
|
||||
if (obj.second->getSnapTarget())
|
||||
return obj.second->getTag();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<osg::ref_ptr<CSVRender::TagBase>> CSVRender::Cell::getSelection(unsigned int elementMask) const
|
||||
{
|
||||
std::vector<osg::ref_ptr<TagBase>> result;
|
||||
|
|
|
@ -162,6 +162,8 @@ namespace CSVRender
|
|||
|
||||
bool isDeleted() const;
|
||||
|
||||
osg::ref_ptr<TagBase> getSnapTarget(unsigned int elementMask) const;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> getSelection(unsigned int elementMask) const;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> getEdited(unsigned int elementMask) const;
|
||||
|
|
|
@ -48,6 +48,8 @@ void CSVRender::EditMode::primarySelectPressed(const WorldspaceHitResult& hit) {
|
|||
|
||||
void CSVRender::EditMode::secondarySelectPressed(const WorldspaceHitResult& hit) {}
|
||||
|
||||
void CSVRender::EditMode::tertiarySelectPressed(const WorldspaceHitResult& hit) {}
|
||||
|
||||
bool CSVRender::EditMode::primaryEditStartDrag(const QPoint& pos)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -57,6 +57,9 @@ namespace CSVRender
|
|||
/// Default-implementation: Ignored.
|
||||
virtual void secondarySelectPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
/// Default-implementation: Ignored.
|
||||
virtual void tertiarySelectPressed(const WorldspaceHitResult& hit);
|
||||
|
||||
/// Default-implementation: ignore and return false
|
||||
///
|
||||
/// \return Drag accepted?
|
||||
|
|
|
@ -96,9 +96,37 @@ osg::Quat CSVRender::InstanceMode::eulerToQuat(const osg::Vec3f& euler) const
|
|||
|
||||
float CSVRender::InstanceMode::roundFloatToMult(const float val, const double mult) const
|
||||
{
|
||||
if (mult == 0)
|
||||
return val;
|
||||
return round(val / mult) * mult;
|
||||
}
|
||||
|
||||
osg::Vec3 CSVRender::InstanceMode::calculateSnapPositionRelativeToTarget(osg::Vec3 initalPosition,
|
||||
osg::Vec3 targetPosition, osg::Vec3 targetRotation, osg::Vec3 translation, double snap) const
|
||||
{
|
||||
auto quatTargetRotation
|
||||
= osg::Quat(targetRotation[0], osg::X_AXIS, targetRotation[1], osg::Y_AXIS, targetRotation[2], osg::Z_AXIS);
|
||||
|
||||
// Break object world coords into snap target space
|
||||
auto localWorld = osg::Matrix::translate(initalPosition)
|
||||
* osg::Matrix::inverse(osg::Matrix::translate(targetPosition)) * osg::Matrix::rotate(quatTargetRotation);
|
||||
|
||||
osg::Vec3 localPosition = localWorld.getTrans();
|
||||
|
||||
osg::Vec3 newTranslation;
|
||||
newTranslation[0] = CSVRender::InstanceMode::roundFloatToMult(localPosition[0] + translation[0], snap);
|
||||
newTranslation[1] = CSVRender::InstanceMode::roundFloatToMult(localPosition[1] + translation[1], snap);
|
||||
newTranslation[2] = CSVRender::InstanceMode::roundFloatToMult(localPosition[2] + translation[2], snap);
|
||||
|
||||
// rebuild object's world coordinates (note: inverse operations from local construction)
|
||||
auto newObjectWorld = osg::Matrix::translate(newTranslation)
|
||||
* osg::Matrix::inverse(osg::Matrix::rotate(quatTargetRotation)) * osg::Matrix::translate(targetPosition);
|
||||
|
||||
osg::Vec3 newObjectPosition = newObjectWorld.getTrans();
|
||||
|
||||
return newObjectPosition;
|
||||
}
|
||||
|
||||
osg::Vec3f CSVRender::InstanceMode::getSelectionCenter(const std::vector<osg::ref_ptr<TagBase>>& selection) const
|
||||
{
|
||||
osg::Vec3f center = osg::Vec3f(0, 0, 0);
|
||||
|
@ -320,6 +348,27 @@ void CSVRender::InstanceMode::secondarySelectPressed(const WorldspaceHitResult&
|
|||
}
|
||||
}
|
||||
|
||||
void CSVRender::InstanceMode::tertiarySelectPressed(const WorldspaceHitResult& hit)
|
||||
{
|
||||
auto* snapTarget = dynamic_cast<CSVRender::ObjectTag*>(getWorldspaceWidget().getSnapTarget(Mask_Reference).get());
|
||||
|
||||
if (snapTarget)
|
||||
{
|
||||
snapTarget->mObject->setSnapTarget(false);
|
||||
}
|
||||
|
||||
if (hit.tag)
|
||||
{
|
||||
if (CSVRender::ObjectTag* objectTag = dynamic_cast<CSVRender::ObjectTag*>(hit.tag.get()))
|
||||
{
|
||||
// hit an Object, toggle its selection state
|
||||
CSVRender::Object* object = objectTag->mObject;
|
||||
object->setSnapTarget(!object->getSnapTarget());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSVRender::InstanceMode::primaryEditStartDrag(const QPoint& pos)
|
||||
{
|
||||
if (mDragMode != DragMode_None || mLocked)
|
||||
|
@ -525,6 +574,7 @@ void CSVRender::InstanceMode::drag(const QPoint& pos, int diffX, int diffY, doub
|
|||
osg::Quat rotation;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> selection = getWorldspaceWidget().getEdited(Mask_Reference);
|
||||
auto* snapTarget = dynamic_cast<CSVRender::ObjectTag*>(getWorldspaceWidget().getSnapTarget(Mask_Reference).get());
|
||||
|
||||
if (mDragMode == DragMode_Move || mDragMode == DragMode_Move_Snap)
|
||||
{
|
||||
|
@ -649,9 +699,25 @@ void CSVRender::InstanceMode::drag(const QPoint& pos, int diffX, int diffY, doub
|
|||
if (mDragMode == DragMode_Move_Snap)
|
||||
{
|
||||
double snap = CSMPrefs::get()["3D Scene Editing"]["gridsnap-movement"].toDouble();
|
||||
position.pos[0] = CSVRender::InstanceMode::roundFloatToMult(position.pos[0], snap);
|
||||
position.pos[1] = CSVRender::InstanceMode::roundFloatToMult(position.pos[1], snap);
|
||||
position.pos[2] = CSVRender::InstanceMode::roundFloatToMult(position.pos[2], snap);
|
||||
|
||||
if (snapTarget)
|
||||
{
|
||||
osg::Vec3 translation(addToX, addToY, addToZ);
|
||||
|
||||
auto snapTargetPosition = snapTarget->mObject->getPosition();
|
||||
auto newPosition = calculateSnapPositionRelativeToTarget(mObjectsAtDragStart[i],
|
||||
snapTargetPosition.asVec3(), snapTargetPosition.asRotationVec3(), translation, snap);
|
||||
|
||||
position.pos[0] = newPosition[0];
|
||||
position.pos[1] = newPosition[1];
|
||||
position.pos[2] = newPosition[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
position.pos[0] = CSVRender::InstanceMode::roundFloatToMult(position.pos[0], snap);
|
||||
position.pos[1] = CSVRender::InstanceMode::roundFloatToMult(position.pos[1], snap);
|
||||
position.pos[2] = CSVRender::InstanceMode::roundFloatToMult(position.pos[2], snap);
|
||||
}
|
||||
}
|
||||
|
||||
// XYZ-locking
|
||||
|
@ -709,6 +775,8 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
|
|||
{
|
||||
std::vector<osg::ref_ptr<TagBase>> selection = getWorldspaceWidget().getEdited(Mask_Reference);
|
||||
|
||||
auto* snapTarget = dynamic_cast<CSVRender::ObjectTag*>(getWorldspaceWidget().getSnapTarget(Mask_Reference).get());
|
||||
|
||||
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
|
||||
|
||||
QString description;
|
||||
|
@ -755,6 +823,7 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
|
|||
|
||||
CSMWorld::CommandMacro macro(undoStack, description);
|
||||
|
||||
// Is this even supposed to be here?
|
||||
for (std::vector<osg::ref_ptr<TagBase>>::iterator iter(selection.begin()); iter != selection.end(); ++iter)
|
||||
{
|
||||
if (CSVRender::ObjectTag* objectTag = dynamic_cast<CSVRender::ObjectTag*>(iter->get()))
|
||||
|
@ -763,12 +832,29 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
|
|||
{
|
||||
ESM::Position position = objectTag->mObject->getPosition();
|
||||
double snap = CSMPrefs::get()["3D Scene Editing"]["gridsnap-rotation"].toDouble();
|
||||
|
||||
float xOffset = 0;
|
||||
float yOffset = 0;
|
||||
float zOffset = 0;
|
||||
|
||||
if (snapTarget)
|
||||
{
|
||||
auto snapTargetPosition = snapTarget->mObject->getPosition();
|
||||
auto rotation = snapTargetPosition.rot;
|
||||
if (rotation)
|
||||
{
|
||||
xOffset = remainder(rotation[0], osg::DegreesToRadians(snap));
|
||||
yOffset = remainder(rotation[1], osg::DegreesToRadians(snap));
|
||||
zOffset = remainder(rotation[2], osg::DegreesToRadians(snap));
|
||||
}
|
||||
}
|
||||
|
||||
position.rot[0]
|
||||
= CSVRender::InstanceMode::roundFloatToMult(position.rot[0], osg::DegreesToRadians(snap));
|
||||
= CSVRender::InstanceMode::roundFloatToMult(position.rot[0], osg::DegreesToRadians(snap)) + xOffset;
|
||||
position.rot[1]
|
||||
= CSVRender::InstanceMode::roundFloatToMult(position.rot[1], osg::DegreesToRadians(snap));
|
||||
= CSVRender::InstanceMode::roundFloatToMult(position.rot[1], osg::DegreesToRadians(snap)) + yOffset;
|
||||
position.rot[2]
|
||||
= CSVRender::InstanceMode::roundFloatToMult(position.rot[2], osg::DegreesToRadians(snap));
|
||||
= CSVRender::InstanceMode::roundFloatToMult(position.rot[2], osg::DegreesToRadians(snap)) + zOffset;
|
||||
|
||||
objectTag->mObject->setRotation(position.rot);
|
||||
}
|
||||
|
@ -802,6 +888,8 @@ void CSVRender::InstanceMode::dragWheel(int diff, double speedFactor)
|
|||
offset *= diff * speedFactor;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> selection = getWorldspaceWidget().getEdited(Mask_Reference);
|
||||
auto snapTarget
|
||||
= dynamic_cast<CSVRender::ObjectTag*>(getWorldspaceWidget().getSnapTarget(Mask_Reference).get());
|
||||
|
||||
int j = 0;
|
||||
|
||||
|
@ -810,15 +898,32 @@ void CSVRender::InstanceMode::dragWheel(int diff, double speedFactor)
|
|||
if (CSVRender::ObjectTag* objectTag = dynamic_cast<CSVRender::ObjectTag*>(iter->get()))
|
||||
{
|
||||
ESM::Position position = objectTag->mObject->getPosition();
|
||||
auto preMovedObjectPosition = position.asVec3();
|
||||
for (int i = 0; i < 3; ++i)
|
||||
position.pos[i] += offset[i];
|
||||
|
||||
if (mDragMode == DragMode_Move_Snap)
|
||||
{
|
||||
double snap = CSMPrefs::get()["3D Scene Editing"]["gridsnap-movement"].toDouble();
|
||||
position.pos[0] = CSVRender::InstanceMode::roundFloatToMult(position.pos[0], snap);
|
||||
position.pos[1] = CSVRender::InstanceMode::roundFloatToMult(position.pos[1], snap);
|
||||
position.pos[2] = CSVRender::InstanceMode::roundFloatToMult(position.pos[2], snap);
|
||||
|
||||
if (snapTarget)
|
||||
{
|
||||
osg::Vec3 translation(snap, snap, snap);
|
||||
|
||||
auto snapTargetPosition = snapTarget->mObject->getPosition();
|
||||
auto newPosition = calculateSnapPositionRelativeToTarget(preMovedObjectPosition,
|
||||
snapTargetPosition.asVec3(), snapTargetPosition.asRotationVec3(), translation, snap);
|
||||
|
||||
position.pos[0] = newPosition[0];
|
||||
position.pos[1] = newPosition[1];
|
||||
position.pos[2] = newPosition[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
position.pos[0] = CSVRender::InstanceMode::roundFloatToMult(position.pos[0], snap);
|
||||
position.pos[1] = CSVRender::InstanceMode::roundFloatToMult(position.pos[1], snap);
|
||||
position.pos[2] = CSVRender::InstanceMode::roundFloatToMult(position.pos[2], snap);
|
||||
}
|
||||
}
|
||||
|
||||
objectTag->mObject->setPosition(position.pos);
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
#include <osg/Group>
|
||||
#include <osg/Node>
|
||||
#include <osg/Quat>
|
||||
#include <osg/Vec3d>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec3>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include "editmode.hpp"
|
||||
|
@ -59,23 +58,25 @@ namespace CSVRender
|
|||
bool mLocked;
|
||||
float mUnitScaleDist;
|
||||
osg::ref_ptr<osg::Group> mParentNode;
|
||||
osg::Vec3f mDragStart;
|
||||
std::vector<osg::Vec3f> mObjectsAtDragStart;
|
||||
osg::Vec3 mDragStart;
|
||||
std::vector<osg::Vec3> mObjectsAtDragStart;
|
||||
|
||||
int getSubModeFromId(const std::string& id) const;
|
||||
|
||||
osg::Vec3f quatToEuler(const osg::Quat& quat) const;
|
||||
osg::Quat eulerToQuat(const osg::Vec3f& euler) const;
|
||||
osg::Vec3 quatToEuler(const osg::Quat& quat) const;
|
||||
osg::Quat eulerToQuat(const osg::Vec3& euler) const;
|
||||
|
||||
float roundFloatToMult(const float val, const double mult) const;
|
||||
|
||||
osg::Vec3f getSelectionCenter(const std::vector<osg::ref_ptr<TagBase>>& selection) const;
|
||||
osg::Vec3f getScreenCoords(const osg::Vec3f& pos);
|
||||
osg::Vec3f getProjectionSpaceCoords(const osg::Vec3f& pos);
|
||||
osg::Vec3f getMousePlaneCoords(const QPoint& point, const osg::Vec3d& dragStart);
|
||||
osg::Vec3 getSelectionCenter(const std::vector<osg::ref_ptr<TagBase>>& selection) const;
|
||||
osg::Vec3 getScreenCoords(const osg::Vec3& pos);
|
||||
osg::Vec3 getProjectionSpaceCoords(const osg::Vec3& pos);
|
||||
osg::Vec3 getMousePlaneCoords(const QPoint& point, const osg::Vec3d& dragStart);
|
||||
void handleSelectDrag(const QPoint& pos);
|
||||
void dropInstance(CSVRender::Object* object, float dropHeight);
|
||||
float calculateDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight);
|
||||
osg::Vec3 calculateSnapPositionRelativeToTarget(osg::Vec3 initalPosition, osg::Vec3 targetPosition,
|
||||
osg::Vec3 targetRotation, osg::Vec3 translation, double snap) const;
|
||||
|
||||
public:
|
||||
InstanceMode(
|
||||
|
@ -97,6 +98,8 @@ namespace CSVRender
|
|||
|
||||
void secondarySelectPressed(const WorldspaceHitResult& hit) override;
|
||||
|
||||
void tertiarySelectPressed(const WorldspaceHitResult& hit) override;
|
||||
|
||||
bool primaryEditStartDrag(const QPoint& pos) override;
|
||||
|
||||
bool secondaryEditStartDrag(const QPoint& pos) override;
|
||||
|
|
|
@ -487,11 +487,17 @@ void CSVRender::Object::setSelected(bool selected)
|
|||
{
|
||||
mSelected = selected;
|
||||
|
||||
if (mSnapTarget)
|
||||
{
|
||||
setSnapTarget(false);
|
||||
}
|
||||
|
||||
mOutline->removeChild(mBaseNode);
|
||||
mRootNode->removeChild(mOutline);
|
||||
mRootNode->removeChild(mBaseNode);
|
||||
if (selected)
|
||||
{
|
||||
mOutline->setWireframeColor(osg::Vec4f(1, 1, 1, 1));
|
||||
mOutline->addChild(mBaseNode);
|
||||
mRootNode->addChild(mOutline);
|
||||
}
|
||||
|
@ -507,6 +513,36 @@ bool CSVRender::Object::getSelected() const
|
|||
return mSelected;
|
||||
}
|
||||
|
||||
void CSVRender::Object::setSnapTarget(bool isSnapTarget)
|
||||
{
|
||||
mSnapTarget = isSnapTarget;
|
||||
|
||||
if (mSelected)
|
||||
{
|
||||
setSelected(false);
|
||||
}
|
||||
|
||||
mOutline->removeChild(mBaseNode);
|
||||
mRootNode->removeChild(mOutline);
|
||||
mRootNode->removeChild(mBaseNode);
|
||||
if (isSnapTarget)
|
||||
{
|
||||
mOutline->setWireframeColor(osg::Vec4f(1, 1, 0, 1));
|
||||
mOutline->addChild(mBaseNode);
|
||||
mRootNode->addChild(mOutline);
|
||||
}
|
||||
else
|
||||
mRootNode->addChild(mBaseNode);
|
||||
|
||||
mMarkerTransparency = CSMPrefs::get()["Rendering"]["object-marker-alpha"].toDouble();
|
||||
updateMarker();
|
||||
}
|
||||
|
||||
bool CSVRender::Object::getSnapTarget() const
|
||||
{
|
||||
return mSnapTarget;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Group> CSVRender::Object::getRootNode()
|
||||
{
|
||||
return mRootNode;
|
||||
|
|
|
@ -87,6 +87,7 @@ namespace CSVRender
|
|||
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||
osg::ref_ptr<osgFX::Scribe> mOutline;
|
||||
bool mSelected;
|
||||
bool mSnapTarget;
|
||||
osg::Group* mParentNode;
|
||||
Resource::ResourceSystem* mResourceSystem;
|
||||
bool mForceBaseToZero;
|
||||
|
@ -140,6 +141,11 @@ namespace CSVRender
|
|||
|
||||
bool getSelected() const;
|
||||
|
||||
/// Mark Object as "snap target"
|
||||
void setSnapTarget(bool isSnapTarget);
|
||||
|
||||
bool getSnapTarget() const;
|
||||
|
||||
/// Get object node with GUI graphics
|
||||
osg::ref_ptr<osg::Group> getRootNode();
|
||||
|
||||
|
|
|
@ -844,6 +844,22 @@ void CSVRender::PagedWorldspaceWidget::resetAllAlteredHeights()
|
|||
cell.second->resetAlteredHeights();
|
||||
}
|
||||
|
||||
osg::ref_ptr<CSVRender::TagBase> CSVRender::PagedWorldspaceWidget::getSnapTarget(unsigned int elementMask) const
|
||||
{
|
||||
osg::ref_ptr<CSVRender::TagBase> result;
|
||||
|
||||
for (auto& [coords, cell] : mCells)
|
||||
{
|
||||
auto snapTarget = cell->getSnapTarget(elementMask);
|
||||
if (snapTarget)
|
||||
{
|
||||
return snapTarget;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<osg::ref_ptr<CSVRender::TagBase>> CSVRender::PagedWorldspaceWidget::getSelection(
|
||||
unsigned int elementMask) const
|
||||
{
|
||||
|
|
|
@ -159,6 +159,8 @@ namespace CSVRender
|
|||
|
||||
void resetAllAlteredHeights();
|
||||
|
||||
osg::ref_ptr<TagBase> getSnapTarget(unsigned int elementMask) const override;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> getSelection(unsigned int elementMask) const override;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> getEdited(unsigned int elementMask) const override;
|
||||
|
|
|
@ -189,6 +189,11 @@ CSVRender::Cell* CSVRender::UnpagedWorldspaceWidget::getCell(const CSMWorld::Cel
|
|||
return mCell.get();
|
||||
}
|
||||
|
||||
osg::ref_ptr<CSVRender::TagBase> CSVRender::UnpagedWorldspaceWidget::getSnapTarget(unsigned int elementMask) const
|
||||
{
|
||||
return mCell->getSnapTarget(elementMask);
|
||||
}
|
||||
|
||||
std::vector<osg::ref_ptr<CSVRender::TagBase>> CSVRender::UnpagedWorldspaceWidget::getSelection(
|
||||
unsigned int elementMask) const
|
||||
{
|
||||
|
|
|
@ -89,6 +89,8 @@ namespace CSVRender
|
|||
|
||||
Cell* getCell(const CSMWorld::CellCoordinates& coords) const override;
|
||||
|
||||
osg::ref_ptr<TagBase> getSnapTarget(unsigned int elementMask) const override;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> getSelection(unsigned int elementMask) const override;
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase>> getEdited(unsigned int elementMask) const override;
|
||||
|
|
|
@ -126,6 +126,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget(CSMDoc::Document& document, QWidge
|
|||
connect(secondarySelectShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this,
|
||||
&WorldspaceWidget::secondarySelect);
|
||||
|
||||
CSMPrefs::Shortcut* tertiarySelectShortcut = new CSMPrefs::Shortcut("scene-select-tertiary", this);
|
||||
connect(tertiarySelectShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this,
|
||||
&WorldspaceWidget::tertiarySelect);
|
||||
|
||||
CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this);
|
||||
connect(abortShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this, &WorldspaceWidget::abortDrag);
|
||||
|
||||
|
@ -690,6 +694,8 @@ void CSVRender::WorldspaceWidget::handleInteractionPress(const WorldspaceHitResu
|
|||
editMode.primarySelectPressed(hit);
|
||||
else if (type == InteractionType_SecondarySelect)
|
||||
editMode.secondarySelectPressed(hit);
|
||||
else if (type == InteractionType_TertiarySelect)
|
||||
editMode.tertiarySelectPressed(hit);
|
||||
else if (type == InteractionType_PrimaryOpen)
|
||||
editMode.primaryOpenPressed(hit);
|
||||
}
|
||||
|
@ -719,6 +725,11 @@ void CSVRender::WorldspaceWidget::secondarySelect(bool activate)
|
|||
handleInteraction(InteractionType_SecondarySelect, activate);
|
||||
}
|
||||
|
||||
void CSVRender::WorldspaceWidget::tertiarySelect(bool activate)
|
||||
{
|
||||
handleInteraction(InteractionType_TertiarySelect, activate);
|
||||
}
|
||||
|
||||
void CSVRender::WorldspaceWidget::speedMode(bool activate)
|
||||
{
|
||||
mSpeedMode = activate;
|
||||
|
|
|
@ -113,6 +113,7 @@ namespace CSVRender
|
|||
InteractionType_PrimarySelect,
|
||||
InteractionType_SecondaryEdit,
|
||||
InteractionType_SecondarySelect,
|
||||
InteractionType_TertiarySelect,
|
||||
InteractionType_PrimaryOpen,
|
||||
InteractionType_None
|
||||
};
|
||||
|
@ -196,6 +197,8 @@ namespace CSVRender
|
|||
|
||||
virtual Cell* getCell(const CSMWorld::CellCoordinates& coords) const = 0;
|
||||
|
||||
virtual osg::ref_ptr<TagBase> getSnapTarget(unsigned int elementMask) const = 0;
|
||||
|
||||
virtual std::vector<osg::ref_ptr<TagBase>> getSelection(unsigned int elementMask) const = 0;
|
||||
|
||||
virtual std::vector<osg::ref_ptr<TagBase>> getEdited(unsigned int elementMask) const = 0;
|
||||
|
@ -293,6 +296,8 @@ namespace CSVRender
|
|||
|
||||
void secondarySelect(bool activate);
|
||||
|
||||
void tertiarySelect(bool activate);
|
||||
|
||||
void speedMode(bool activate);
|
||||
|
||||
protected slots:
|
||||
|
|
25
docs/source/manuals/openmw-cs/cell-view.rst
Normal file
25
docs/source/manuals/openmw-cs/cell-view.rst
Normal file
|
@ -0,0 +1,25 @@
|
|||
Cell View
|
||||
########
|
||||
|
||||
This window deals with the manipulation of instances within one or more cells.
|
||||
|
||||
|
||||
Grid Snapping
|
||||
**********************
|
||||
|
||||
When manipulating one or more instances within the cell view, whether it's position,
|
||||
rotation, or scale, the instances can be snapped to specific values configured within
|
||||
the Edit->Preferences->3D Scene editing menu.
|
||||
|
||||
To begin snapping an instance, hold down CTRL when transforming the instance, whether
|
||||
it's with the gizmos or by dragging the mouse, and the instance will snap to the closest
|
||||
value as you manipulate the instance.
|
||||
|
||||
Snap to reference
|
||||
======================
|
||||
|
||||
If you want to snap instances relative to another instance, you can select a snap target
|
||||
with SHIFT + Middle Mouse Button to select a snap target. This will highlight the
|
||||
instance in a yellow wireframe. Then, just with regular snapping, you hold down CTRL
|
||||
when manipulating the instance(s) and the transformed values will be snapped to
|
||||
the snap values relative to the snap target's world space.
|
|
@ -29,3 +29,4 @@ few chapters to familiarise yourself with the new interface.
|
|||
tables-assets
|
||||
record-types
|
||||
record-filters
|
||||
cell-view
|
||||
|
|
Loading…
Reference in a new issue