diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index 7708feb79..67c60601e 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -68,7 +68,8 @@ ImplementEnumType( WorldEditorDropType, { WorldEditor::DropAtScreenCenter, "screenCenter", "Places at a position projected outwards from the screen's center.\n" }, { WorldEditor::DropAtCentroid, "atCentroid", "Places at the center position of the current centroid.\n" }, { WorldEditor::DropToTerrain, "toTerrain", "Places on the terrain.\n" }, - { WorldEditor::DropBelowSelection, "belowSelection", "Places at a position below the selected object.\n" } + { WorldEditor::DropBelowSelection, "belowSelection", "Places at a position below the selected object.\n" }, + { WorldEditor::DropAtGizmo, "atGizmo", "Places at the gizmo point.\n" } EndImplementEnumType; ImplementEnumType( WorldEditorAlignmentType, @@ -643,10 +644,10 @@ void WorldEditor::dropSelection(Selection* sel) Point3F offset = -boxCenter; offset.z += bounds.len_z() * 0.5f; - sel->offset( offset, mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(offset, (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); } else - sel->offset( Point3F( -centroid ), mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(Point3F(-centroid), (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); break; } @@ -657,7 +658,7 @@ void WorldEditor::dropSelection(Selection* sel) if(mDropAtBounds && !sel->containsGlobalBounds()) center = sel->getBoxBottomCenter(); - sel->offset( Point3F( smCamPos - center ), mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(Point3F(smCamPos - center), (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); sel->orient(smCamMatrix, center); break; } @@ -668,7 +669,7 @@ void WorldEditor::dropSelection(Selection* sel) if(mDropAtBounds && !sel->containsGlobalBounds()) sel->getBoxBottomCenter(); - sel->offset( Point3F( smCamPos - center ), mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(Point3F(smCamPos - center), (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); break; } @@ -680,7 +681,7 @@ void WorldEditor::dropSelection(Selection* sel) Point3F offset = smCamPos - center; offset.z -= mDropBelowCameraOffset; - sel->offset( offset, mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(offset, (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); break; } @@ -712,7 +713,7 @@ void WorldEditor::dropSelection(Selection* sel) event.vec = wp - smCamPos; event.vec.normalizeSafe(); event.vec *= viewdist; - sel->offset( Point3F( event.pos - center ) += event.vec, mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(Point3F(event.pos - center) += event.vec, (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); break; } @@ -728,12 +729,26 @@ void WorldEditor::dropSelection(Selection* sel) dropBelowSelection(sel, centroid, mDropAtBounds); break; } + + case DropAtGizmo: + { + dropAtGizmo(sel, mGizmo->getPosition()-centroid); + break; + } } // updateClientTransforms(sel); } +void WorldEditor::dropAtGizmo(Selection* sel, const Point3F & gizmoPos) +{ + if (!sel->size()) + return; + + sel->offset(gizmoPos, (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); +} + void WorldEditor::dropBelowSelection(Selection* sel, const Point3F & centroid, bool useBottomBounds) { if(!sel->size()) @@ -756,7 +771,7 @@ void WorldEditor::dropBelowSelection(Selection* sel, const Point3F & centroid, sel->enableCollision(); if( hit ) - sel->offset( ri.point - start, mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(ri.point - start, (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); } //------------------------------------------------------------------------------ @@ -800,7 +815,7 @@ void WorldEditor::terrainSnapSelection(Selection* sel, U8 modifier, Point3F gizm { mStuckToGround = true; - sel->offset( ri.point - centroid, mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(ri.point - centroid, (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); if(mTerrainSnapAlignment != AlignNone) { @@ -1026,7 +1041,7 @@ void WorldEditor::softSnapSelection(Selection* sel, U8 modifier, Point3F gizmoPo if ( minT <= 1.0f ) foundPoint += ( end - start ) * (0.5f - minT); - sel->offset( foundPoint - sel->getCentroid(), mGridSnap ? mGridPlaneSize : 0.f ); + sel->offset(foundPoint - sel->getCentroid(), (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); } mSoftSnapIsStuck = found; @@ -1805,7 +1820,7 @@ WorldEditor::WorldEditor() mSoftSnapDebugPoint.set(0.0f, 0.0f, 0.0f); mGridSnap = false; - + mUseGroupCenter = true; mFadeIcons = true; mFadeIconsDist = 8.f; } @@ -2254,7 +2269,7 @@ void WorldEditor::on3DMouseDragged(const Gui3DMouseEvent & event) mGizmo->getProfile()->snapToGrid = snapToGrid; } - mSelected->offset( mGizmo->getOffset() ); + mSelected->offset(mGizmo->getOffset(), (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); // Handle various sticking terrainSnapSelection( mSelected, event.modifier, mGizmo->getPosition() ); @@ -2686,7 +2701,8 @@ void WorldEditor::initPersistFields() addGroup( "Grid" ); addField( "gridSnap", TypeBool, Offset( mGridSnap, WorldEditor ), - "If true, transform operations will snap to the grid." ); + "If true, transform operations will snap to the grid."); + addField("useGroupCenter", TypeBool, Offset(mUseGroupCenter, WorldEditor)); endGroup( "Grid" ); @@ -3035,7 +3051,7 @@ void WorldEditor::transformSelection(bool position, Point3F& p, bool relativePos { if( relativePos ) { - mSelected->offset( p, mGridSnap ? mGridPlaneSize : 0.f ); + mSelected->offset(p, (!mUseGroupCenter && mGridSnap) ? mGridPlaneSize : 0.f); } else { @@ -3641,7 +3657,7 @@ void WorldEditor::makeSelectionPrefab( const char *filename ) else { //Only push the cleanup of the group if it's ONLY a SimGroup. - cleanup.push_back(grp); + cleanup.push_back( grp ); } } else diff --git a/Engine/source/gui/worldEditor/worldEditor.h b/Engine/source/gui/worldEditor/worldEditor.h index f1c231ee9..fb125daf5 100644 --- a/Engine/source/gui/worldEditor/worldEditor.h +++ b/Engine/source/gui/worldEditor/worldEditor.h @@ -164,7 +164,8 @@ class WorldEditor : public EditTSCtrl bool copySelection(Selection* sel); bool pasteSelection(bool dropSel=true); void dropSelection(Selection* sel); - void dropBelowSelection(Selection* sel, const Point3F & centroid, bool useBottomBounds=false); + void dropBelowSelection(Selection* sel, const Point3F & centroid, bool useBottomBounds = false); + void dropAtGizmo(Selection* sel, const Point3F & gizmoPos); void terrainSnapSelection(Selection* sel, U8 modifier, Point3F gizmoPos, bool forceStick=false); void softSnapSelection(Selection* sel, U8 modifier, Point3F gizmoPos); @@ -296,7 +297,8 @@ class WorldEditor : public EditTSCtrl DropAtScreenCenter, DropAtCentroid, DropToTerrain, - DropBelowSelection + DropBelowSelection, + DropAtGizmo }; // Snapping alignment mode @@ -349,6 +351,7 @@ class WorldEditor : public EditTSCtrl F32 mDropAtScreenCenterMax; bool mGridSnap; + bool mUseGroupCenter; bool mStickToGround; bool mStuckToGround; ///< Selection is stuck to the ground AlignmentType mTerrainSnapAlignment; ///< How does the stickied object align to the terrain diff --git a/Engine/source/gui/worldEditor/worldEditorSelection.cpp b/Engine/source/gui/worldEditor/worldEditorSelection.cpp index 72f406b98..57c2747d1 100644 --- a/Engine/source/gui/worldEditor/worldEditorSelection.cpp +++ b/Engine/source/gui/worldEditor/worldEditorSelection.cpp @@ -306,9 +306,9 @@ void WorldEditorSelection::offset( const Point3F& offset, F32 gridSnap ) if( gridSnap != 0.f ) { - wPos.x -= mFmod( wPos.x, gridSnap ); - wPos.y -= mFmod( wPos.y, gridSnap ); - wPos.z -= mFmod( wPos.z, gridSnap ); + wPos.x = _snapFloat(wPos.x, gridSnap); + wPos.y = _snapFloat(wPos.y, gridSnap); + wPos.z = _snapFloat(wPos.z, gridSnap); } mat.setColumn(3, wPos); @@ -318,6 +318,22 @@ void WorldEditorSelection::offset( const Point3F& offset, F32 gridSnap ) mCentroidValid = false; } +F32 WorldEditorSelection::_snapFloat(const F32 &val, const F32 &snap) const +{ + if (snap == 0.0f) + return val; + + F32 a = mFmod(val, snap); + + F32 temp = val; + + if (mFabs(a) > (snap / 2)) + val < 0.0f ? temp -= snap : temp += snap; + + return(temp - a); +} + + //----------------------------------------------------------------------------- void WorldEditorSelection::setPosition(const Point3F & pos) diff --git a/Engine/source/gui/worldEditor/worldEditorSelection.h b/Engine/source/gui/worldEditor/worldEditorSelection.h index a2ff89c42..9ff9eef9c 100644 --- a/Engine/source/gui/worldEditor/worldEditorSelection.h +++ b/Engine/source/gui/worldEditor/worldEditorSelection.h @@ -108,6 +108,7 @@ class WorldEditorSelection : public SimPersistSet // void offset(const Point3F& delta, F32 gridSnap = 0.f ); void setPosition(const Point3F & pos); + F32 _snapFloat(const F32 &val, const F32 &snap) const; void setCentroidPosition(bool useBoxCenter, const Point3F & pos); void orient(const MatrixF &, const Point3F &); diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui index 24f5c8172..64332f8a3 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui @@ -28,7 +28,7 @@ canMinimize = "0"; canMaximize = "0"; position = "400 31"; - extent =" 175 257"; + extent =" 175 267"; MinExtent = "175 130"; text = "Snap Options"; closeCommand = "ESnapOptions.hideDialog();"; @@ -51,7 +51,7 @@ Visible = "1"; hovertime = "1000"; Docking = "Client"; - Margin = "3 22 3 3"; + Margin = "3 32 3 3"; Padding = "0 0 0 0"; AnchorTop = "1"; AnchorBottom = "0"; @@ -793,6 +793,25 @@ canSave = "1"; canSaveDynamicFields = "0"; }; + new GuiCheckBoxCtrl() { + text = "Use Group Center"; + groupNum = "1"; + useMouseEvents = "0"; + isContainer = "0"; + horizSizing = "right"; + vertSizing = "top"; + position = "4 246"; + extent = "105 24"; + minExtent = "8 8"; + visible = "1"; + active = "1"; + command = "toggleSnappingOptions(\"byGroup\");"; + tooltipProfile = "ToolsGuiToolTipProfile"; + hovertime = "1000"; + internalName = "GroupSnapButton"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; new GuiTextCtrl() { text = "Size"; maxLength = "1024"; diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs index 31f794d17..bc1905292 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -2050,12 +2050,14 @@ function EWorldEditor::syncGui( %this ) EWorldEditorToolbar-->renderHandleBtn.setStateOn( EWorldEditor.renderObjHandle ); EWorldEditorToolbar-->renderTextBtn.setStateOn( EWorldEditor.renderObjText ); + EWorldEditorToolbar-->objectSnapDownBtn.setStateOn( %this.stickToGround ); SnapToBar-->objectSnapBtn.setStateOn( EWorldEditor.getSoftSnap() ); EWorldEditorToolbar-->softSnapSizeTextEdit.setText( EWorldEditor.getSoftSnapSize() ); ESnapOptions-->SnapSize.setText( EWorldEditor.getSoftSnapSize() ); ESnapOptions-->GridSize.setText( EWorldEditor.getGridSize() ); ESnapOptions-->GridSnapButton.setStateOn( %this.getGridSnap() ); + ESnapOptions-->GroupSnapButton.setStateOn( %this.UseGroupCenter ); SnapToBar-->objectGridSnapBtn.setStateOn( %this.getGridSnap() ); ESnapOptions-->NoSnapButton.setStateOn( !%this.stickToGround && !%this.getSoftSnap() && !%this.getGridSnap() ); } @@ -2458,6 +2460,11 @@ function toggleSnappingOptions( %var ) { EWorldEditor.setGridSnap( !EWorldEditor.getGridSnap() ); } + else if( %var $= "byGroup" ) + { + EWorldEditor.UseGroupCenter = !EWorldEditor.UseGroupCenter; + ESnapOptions->GroupSnapButton.setStateOn(EWorldEditor.UseGroupCenter); + } else { // No snapping. diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs index be068b9ed..dbe978cab 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs @@ -315,6 +315,7 @@ function EditorGui::buildMenus(%this) item[5] = "at Centroid" TAB "" TAB "atCentroid"; item[6] = "to Terrain" TAB "" TAB "toTerrain"; item[7] = "Below Selection" TAB "" TAB "belowSelection"; + item[8] = "At Gizmo" TAB "" TAB "atGizmo"; }; %this.alignBoundsMenu = new PopupMenu() diff --git a/Templates/Full/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui b/Templates/Full/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui index 24f5c8172..64332f8a3 100644 --- a/Templates/Full/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui +++ b/Templates/Full/game/tools/worldEditor/gui/ObjectSnapOptionsWindow.ed.gui @@ -28,7 +28,7 @@ canMinimize = "0"; canMaximize = "0"; position = "400 31"; - extent =" 175 257"; + extent =" 175 267"; MinExtent = "175 130"; text = "Snap Options"; closeCommand = "ESnapOptions.hideDialog();"; @@ -51,7 +51,7 @@ Visible = "1"; hovertime = "1000"; Docking = "Client"; - Margin = "3 22 3 3"; + Margin = "3 32 3 3"; Padding = "0 0 0 0"; AnchorTop = "1"; AnchorBottom = "0"; @@ -793,6 +793,25 @@ canSave = "1"; canSaveDynamicFields = "0"; }; + new GuiCheckBoxCtrl() { + text = "Use Group Center"; + groupNum = "1"; + useMouseEvents = "0"; + isContainer = "0"; + horizSizing = "right"; + vertSizing = "top"; + position = "4 246"; + extent = "105 24"; + minExtent = "8 8"; + visible = "1"; + active = "1"; + command = "toggleSnappingOptions(\"byGroup\");"; + tooltipProfile = "ToolsGuiToolTipProfile"; + hovertime = "1000"; + internalName = "GroupSnapButton"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; new GuiTextCtrl() { text = "Size"; maxLength = "1024"; diff --git a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs index 31f794d17..bc1905292 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs @@ -2050,12 +2050,14 @@ function EWorldEditor::syncGui( %this ) EWorldEditorToolbar-->renderHandleBtn.setStateOn( EWorldEditor.renderObjHandle ); EWorldEditorToolbar-->renderTextBtn.setStateOn( EWorldEditor.renderObjText ); + EWorldEditorToolbar-->objectSnapDownBtn.setStateOn( %this.stickToGround ); SnapToBar-->objectSnapBtn.setStateOn( EWorldEditor.getSoftSnap() ); EWorldEditorToolbar-->softSnapSizeTextEdit.setText( EWorldEditor.getSoftSnapSize() ); ESnapOptions-->SnapSize.setText( EWorldEditor.getSoftSnapSize() ); ESnapOptions-->GridSize.setText( EWorldEditor.getGridSize() ); ESnapOptions-->GridSnapButton.setStateOn( %this.getGridSnap() ); + ESnapOptions-->GroupSnapButton.setStateOn( %this.UseGroupCenter ); SnapToBar-->objectGridSnapBtn.setStateOn( %this.getGridSnap() ); ESnapOptions-->NoSnapButton.setStateOn( !%this.stickToGround && !%this.getSoftSnap() && !%this.getGridSnap() ); } @@ -2458,6 +2460,11 @@ function toggleSnappingOptions( %var ) { EWorldEditor.setGridSnap( !EWorldEditor.getGridSnap() ); } + else if( %var $= "byGroup" ) + { + EWorldEditor.UseGroupCenter = !EWorldEditor.UseGroupCenter; + ESnapOptions->GroupSnapButton.setStateOn(EWorldEditor.UseGroupCenter); + } else { // No snapping. diff --git a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs index be068b9ed..dbe978cab 100644 --- a/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs +++ b/Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs @@ -315,6 +315,7 @@ function EditorGui::buildMenus(%this) item[5] = "at Centroid" TAB "" TAB "atCentroid"; item[6] = "to Terrain" TAB "" TAB "toTerrain"; item[7] = "Below Selection" TAB "" TAB "belowSelection"; + item[8] = "At Gizmo" TAB "" TAB "atGizmo"; }; %this.alignBoundsMenu = new PopupMenu()