mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-06 09:45:33 +00:00
Implement grid snapping and angle snapping in OpenMW-CS
Adds configurable snap settings for instance movement, rotation and scaling, used with the secondary edit button
This commit is contained in:
parent
964f288c13
commit
6d7c8f25fc
5 changed files with 119 additions and 17 deletions
|
@ -243,6 +243,9 @@ void CSMPrefs::State::declare()
|
|||
secondarySelectAction.add (SelectOnly).add (SelectAdd).add (SelectRemove).add (selectInvert);
|
||||
|
||||
declareCategory ("3D Scene Editing");
|
||||
declareDouble("gridsnap-movement", "Grid snap size", 16);
|
||||
declareDouble("gridsnap-rotation", "Angle snap size", 15);
|
||||
declareDouble("gridsnap-scale", "Scale snap size", 0.25);
|
||||
declareInt ("distance", "Drop Distance", 50).
|
||||
setTooltip ("If an instance drop can not be placed against another object at the "
|
||||
"insert point, it will be placed by this distance from the insert point instead");
|
||||
|
|
|
@ -12,7 +12,10 @@ namespace CSVRender
|
|||
DragMode_Select_Only,
|
||||
DragMode_Select_Add,
|
||||
DragMode_Select_Remove,
|
||||
DragMode_Select_Invert
|
||||
DragMode_Select_Invert,
|
||||
DragMode_Move_Snap,
|
||||
DragMode_Rotate_Snap,
|
||||
DragMode_Scale_Snap
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -64,6 +64,11 @@ osg::Quat CSVRender::InstanceMode::eulerToQuat(const osg::Vec3f& euler) const
|
|||
return zr * yr * xr;
|
||||
}
|
||||
|
||||
float CSVRender::InstanceMode::roundFloatToMult(const float val, const double mult) const
|
||||
{
|
||||
return round(val / mult) * mult;
|
||||
}
|
||||
|
||||
osg::Vec3f CSVRender::InstanceMode::getSelectionCenter(const std::vector<osg::ref_ptr<TagBase> >& selection) const
|
||||
{
|
||||
osg::Vec3f center = osg::Vec3f(0, 0, 0);
|
||||
|
@ -156,15 +161,13 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
|
|||
"<ul><li>Use {scene-edit-primary} to rotate instances freely</li>"
|
||||
"<li>Use {scene-edit-secondary} to rotate instances within the grid</li>"
|
||||
"<li>The center of the view acts as the axis of rotation</li>"
|
||||
"</ul>"
|
||||
"<font color=Red>Grid rotate not implemented yet</font color>");
|
||||
"</ul>");
|
||||
mSubMode->addButton (":scenetoolbar/transform-scale", "scale",
|
||||
"Scale selected instances"
|
||||
"<ul><li>Use {scene-edit-primary} to scale instances freely</li>"
|
||||
"<li>Use {scene-edit-secondary} to scale instances along the grid</li>"
|
||||
"<li>The scaling rate is based on how close the start of a drag is to the center of the screen</li>"
|
||||
"</ul>"
|
||||
"<font color=Red>Grid scale not implemented yet</font color>");
|
||||
"</ul>");
|
||||
|
||||
mSubMode->setButton (mSubModeId);
|
||||
|
||||
|
@ -351,10 +354,81 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
|
|||
|
||||
bool CSVRender::InstanceMode::secondaryEditStartDrag (const QPoint& pos)
|
||||
{
|
||||
if (mLocked)
|
||||
if (mDragMode != DragMode_None || mLocked)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick(pos, getWorldspaceWidget().getInteractionMask());
|
||||
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection(Mask_Reference);
|
||||
if (selection.empty())
|
||||
{
|
||||
// Only change selection at the start of drag if no object is already selected
|
||||
if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
|
||||
{
|
||||
getWorldspaceWidget().clearSelection(Mask_Reference);
|
||||
if (CSVRender::ObjectTag* objectTag = dynamic_cast<CSVRender::ObjectTag*> (hit.tag.get()))
|
||||
{
|
||||
CSVRender::Object* object = objectTag->mObject;
|
||||
object->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
selection = getWorldspaceWidget().getSelection(Mask_Reference);
|
||||
if (selection.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
mObjectsAtDragStart.clear();
|
||||
|
||||
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()))
|
||||
{
|
||||
if (mSubModeId == "move")
|
||||
{
|
||||
objectTag->mObject->setEdited(Object::Override_Position);
|
||||
float x = objectTag->mObject->getPosition().pos[0];
|
||||
float y = objectTag->mObject->getPosition().pos[1];
|
||||
float z = objectTag->mObject->getPosition().pos[2];
|
||||
osg::Vec3f thisPoint(x, y, z);
|
||||
|
||||
mDragStart = getMousePlaneCoords(pos, getProjectionSpaceCoords(thisPoint));
|
||||
mObjectsAtDragStart.emplace_back(thisPoint);
|
||||
mDragMode = DragMode_Move_Snap;
|
||||
}
|
||||
else if (mSubModeId == "rotate")
|
||||
{
|
||||
objectTag->mObject->setEdited(Object::Override_Rotation);
|
||||
mDragMode = DragMode_Rotate_Snap;
|
||||
}
|
||||
else if (mSubModeId == "scale")
|
||||
{
|
||||
objectTag->mObject->setEdited(Object::Override_Scale);
|
||||
mDragMode = DragMode_Scale_Snap;
|
||||
|
||||
// Calculate scale factor
|
||||
std::vector<osg::ref_ptr<TagBase> > editedSelection = getWorldspaceWidget().getEdited(Mask_Reference);
|
||||
osg::Vec3f center = getScreenCoords(getSelectionCenter(editedSelection));
|
||||
|
||||
int widgetHeight = getWorldspaceWidget().height();
|
||||
|
||||
float dx = pos.x() - center.x();
|
||||
float dy = (widgetHeight - pos.y()) - center.y();
|
||||
|
||||
mUnitScaleDist = std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CSVRender::ObjectMarkerTag* objectTag = dynamic_cast<CSVRender::ObjectMarkerTag*> (hit.tag.get()))
|
||||
{
|
||||
mDragAxis = objectTag->mAxis;
|
||||
}
|
||||
else
|
||||
mDragAxis = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::InstanceMode::primarySelectStartDrag (const QPoint& pos)
|
||||
|
@ -400,8 +474,8 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||
|
||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (Mask_Reference);
|
||||
|
||||
if (mDragMode == DragMode_Move) {}
|
||||
else if (mDragMode == DragMode_Rotate)
|
||||
if (mDragMode == DragMode_Move || mDragMode == DragMode_Move_Snap) {}
|
||||
else if (mDragMode == DragMode_Rotate || mDragMode == DragMode_Rotate_Snap)
|
||||
{
|
||||
osg::Vec3f eye, centre, up;
|
||||
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up);
|
||||
|
@ -465,7 +539,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||
|
||||
rotation = osg::Quat(angle, axis);
|
||||
}
|
||||
else if (mDragMode == DragMode_Scale)
|
||||
else if (mDragMode == DragMode_Scale || mDragMode == DragMode_Scale_Snap)
|
||||
{
|
||||
osg::Vec3f center = getScreenCoords(getSelectionCenter(selection));
|
||||
|
||||
|
@ -507,7 +581,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||
{
|
||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
||||
{
|
||||
if (mDragMode == DragMode_Move)
|
||||
if (mDragMode == DragMode_Move || mDragMode == DragMode_Move_Snap)
|
||||
{
|
||||
ESM::Position position = objectTag->mObject->getPosition();
|
||||
osg::Vec3f mousePos = getMousePlaneCoords(pos, getProjectionSpaceCoords(mDragStart));
|
||||
|
@ -518,6 +592,13 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||
position.pos[1] = mObjectsAtDragStart[i].y() + addToY;
|
||||
position.pos[2] = mObjectsAtDragStart[i].z() + addToZ;
|
||||
|
||||
if (mDragMode == DragMode_Move_Snap)
|
||||
{
|
||||
position.pos[0] = CSVRender::InstanceMode::roundFloatToMult(position.pos[0], CSMPrefs::get()["3D Scene Editing"]["gridsnap-movement"].toDouble());
|
||||
position.pos[1] = CSVRender::InstanceMode::roundFloatToMult(position.pos[1], CSMPrefs::get()["3D Scene Editing"]["gridsnap-movement"].toDouble());
|
||||
position.pos[2] = CSVRender::InstanceMode::roundFloatToMult(position.pos[2], CSMPrefs::get()["3D Scene Editing"]["gridsnap-movement"].toDouble());
|
||||
}
|
||||
|
||||
// XYZ-locking
|
||||
if (mDragAxis != -1)
|
||||
{
|
||||
|
@ -530,7 +611,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||
|
||||
objectTag->mObject->setPosition(position.pos);
|
||||
}
|
||||
else if (mDragMode == DragMode_Rotate)
|
||||
else if (mDragMode == DragMode_Rotate || mDragMode == DragMode_Rotate_Snap)
|
||||
{
|
||||
ESM::Position position = objectTag->mObject->getPosition();
|
||||
|
||||
|
@ -546,9 +627,16 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||
position.rot[2] = euler.z();
|
||||
}
|
||||
|
||||
if (mDragMode == DragMode_Rotate_Snap)
|
||||
{
|
||||
position.rot[0] = CSVRender::InstanceMode::roundFloatToMult(position.rot[0], osg::DegreesToRadians(CSMPrefs::get()["3D Scene Editing"]["gridsnap-rotation"].toDouble()));
|
||||
position.rot[1] = CSVRender::InstanceMode::roundFloatToMult(position.rot[1], osg::DegreesToRadians(CSMPrefs::get()["3D Scene Editing"]["gridsnap-rotation"].toDouble()));
|
||||
position.rot[2] = CSVRender::InstanceMode::roundFloatToMult(position.rot[2], osg::DegreesToRadians(CSMPrefs::get()["3D Scene Editing"]["gridsnap-rotation"].toDouble()));
|
||||
}
|
||||
|
||||
objectTag->mObject->setRotation(position.rot);
|
||||
}
|
||||
else if (mDragMode == DragMode_Scale)
|
||||
else if (mDragMode == DragMode_Scale || mDragMode == DragMode_Scale_Snap)
|
||||
{
|
||||
// Reset scale
|
||||
objectTag->mObject->setEdited(0);
|
||||
|
@ -557,6 +645,11 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||
float scale = objectTag->mObject->getScale();
|
||||
scale *= offset.x();
|
||||
|
||||
if (mDragMode == DragMode_Scale_Snap)
|
||||
{
|
||||
scale = CSVRender::InstanceMode::roundFloatToMult(scale, CSMPrefs::get()["3D Scene Editing"]["gridsnap-scale"].toDouble());
|
||||
}
|
||||
|
||||
objectTag->mObject->setScale (scale);
|
||||
}
|
||||
}
|
||||
|
@ -593,7 +686,9 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
|
|||
handleSelectDrag(pos);
|
||||
return;
|
||||
break;
|
||||
|
||||
case DragMode_Move_Snap: description = "Move Instances"; break;
|
||||
case DragMode_Rotate_Snap: description = "Rotate Instances"; break;
|
||||
case DragMode_Scale_Snap: description = "Scale Instances"; break;
|
||||
case DragMode_None: break;
|
||||
}
|
||||
|
||||
|
@ -621,7 +716,7 @@ void CSVRender::InstanceMode::dragAborted()
|
|||
|
||||
void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor)
|
||||
{
|
||||
if (mDragMode==DragMode_Move)
|
||||
if (mDragMode==DragMode_Move || mDragMode==DragMode_Move_Snap)
|
||||
{
|
||||
osg::Vec3f eye;
|
||||
osg::Vec3f centre;
|
||||
|
|
|
@ -53,6 +53,8 @@ namespace CSVRender
|
|||
osg::Vec3f quatToEuler(const osg::Quat& quat) const;
|
||||
osg::Quat eulerToQuat(const osg::Vec3f& 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);
|
||||
|
|
|
@ -6,7 +6,6 @@ CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent)
|
|||
"Move selected instances"
|
||||
"<ul><li>Use {scene-edit-primary} to move instances around freely</li>"
|
||||
"<li>Use {scene-edit-secondary} to move instances around within the grid</li>"
|
||||
"</ul>"
|
||||
"<font color=Red>Grid move not implemented yet</font color>",
|
||||
"</ul>",
|
||||
parent)
|
||||
{}
|
||||
|
|
Loading…
Reference in a new issue