2015-09-27 14:18:22 +00:00
# include "instancemode.hpp"
2016-01-10 07:56:15 +00:00
# include <QDragEnterEvent>
2016-05-18 01:24:16 +00:00
# include <QPoint>
2020-02-28 11:20:57 +00:00
# include <QString>
2016-01-10 07:56:15 +00:00
2015-12-15 09:40:00 +00:00
# include "../../model/prefs/state.hpp"
2015-09-29 14:07:14 +00:00
2020-03-03 19:18:09 +00:00
# include <osg/ComputeBoundsVisitor>
2020-02-27 09:54:11 +00:00
# include <osg/Group>
# include <osg/Vec3d>
# include <osgUtil/LineSegmentIntersector>
2016-01-10 07:56:15 +00:00
# include "../../model/world/idtable.hpp"
2016-01-14 12:20:01 +00:00
# include "../../model/world/idtree.hpp"
2016-01-10 07:56:15 +00:00
# include "../../model/world/commands.hpp"
2016-03-08 09:48:44 +00:00
# include "../../model/world/commandmacro.hpp"
2020-02-19 09:44:55 +00:00
# include "../../model/prefs/shortcut.hpp"
2016-01-10 07:56:15 +00:00
2016-01-15 11:07:25 +00:00
# include "../widget/scenetoolbar.hpp"
# include "../widget/scenetoolmode.hpp"
2020-04-20 16:47:14 +00:00
# include "mask.hpp"
2016-01-19 12:59:24 +00:00
2015-09-27 14:18:22 +00:00
# include "object.hpp"
2015-09-29 11:53:47 +00:00
# include "worldspacewidget.hpp"
2016-01-14 12:20:01 +00:00
# include "pagedworldspacewidget.hpp"
2016-01-19 11:17:13 +00:00
# include "instanceselectionmode.hpp"
2016-02-16 15:02:29 +00:00
# include "instancemovemode.hpp"
2015-09-27 14:18:22 +00:00
2016-03-01 14:48:34 +00:00
int CSVRender : : InstanceMode : : getSubModeFromId ( const std : : string & id ) const
{
return id = = " move " ? 0 : ( id = = " rotate " ? 1 : 2 ) ;
}
2016-08-10 23:31:34 +00:00
osg : : Vec3f CSVRender : : InstanceMode : : quatToEuler ( const osg : : Quat & rot ) const
{
float x , y , z ;
float test = 2 * ( rot . w ( ) * rot . y ( ) + rot . x ( ) * rot . z ( ) ) ;
if ( std : : abs ( test ) > = 1.f )
{
x = atan2 ( rot . x ( ) , rot . w ( ) ) ;
2018-09-17 10:52:43 +00:00
y = ( test > 0 ) ? ( osg : : PI / 2 ) : ( - osg : : PI / 2 ) ;
2016-08-10 23:31:34 +00:00
z = 0 ;
}
else
{
x = std : : atan2 ( 2 * ( rot . w ( ) * rot . x ( ) - rot . y ( ) * rot . z ( ) ) , 1 - 2 * ( rot . x ( ) * rot . x ( ) + rot . y ( ) * rot . y ( ) ) ) ;
y = std : : asin ( test ) ;
z = std : : atan2 ( 2 * ( rot . w ( ) * rot . z ( ) - rot . x ( ) * rot . y ( ) ) , 1 - 2 * ( rot . y ( ) * rot . y ( ) + rot . z ( ) * rot . z ( ) ) ) ;
}
return osg : : Vec3f ( - x , - y , - z ) ;
}
osg : : Quat CSVRender : : InstanceMode : : eulerToQuat ( const osg : : Vec3f & euler ) const
{
osg : : Quat xr = osg : : Quat ( - euler [ 0 ] , osg : : Vec3f ( 1 , 0 , 0 ) ) ;
osg : : Quat yr = osg : : Quat ( - euler [ 1 ] , osg : : Vec3f ( 0 , 1 , 0 ) ) ;
osg : : Quat zr = osg : : Quat ( - euler [ 2 ] , osg : : Vec3f ( 0 , 0 , 1 ) ) ;
return zr * yr * xr ;
}
2022-04-03 00:25:57 +00:00
float CSVRender : : InstanceMode : : roundFloatToMult ( const float val , const double mult ) const
{
return round ( val / mult ) * mult ;
}
2016-08-12 21:11:37 +00:00
osg : : Vec3f CSVRender : : InstanceMode : : getSelectionCenter ( const std : : vector < osg : : ref_ptr < TagBase > > & selection ) const
{
osg : : Vec3f center = osg : : Vec3f ( 0 , 0 , 0 ) ;
int objectCount = 0 ;
for ( std : : vector < osg : : ref_ptr < TagBase > > : : const_iterator iter ( selection . begin ( ) ) ; iter ! = selection . end ( ) ; + + iter )
{
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( iter - > get ( ) ) )
{
const ESM : : Position & position = objectTag - > mObject - > getPosition ( ) ;
center + = osg : : Vec3f ( position . pos [ 0 ] , position . pos [ 1 ] , position . pos [ 2 ] ) ;
+ + objectCount ;
}
}
2016-08-18 16:42:35 +00:00
if ( objectCount > 0 )
center / = objectCount ;
2016-08-12 21:11:37 +00:00
return center ;
}
osg : : Vec3f CSVRender : : InstanceMode : : getScreenCoords ( const osg : : Vec3f & pos )
{
osg : : Matrix viewMatrix = getWorldspaceWidget ( ) . getCamera ( ) - > getViewMatrix ( ) ;
osg : : Matrix projMatrix = getWorldspaceWidget ( ) . getCamera ( ) - > getProjectionMatrix ( ) ;
osg : : Matrix windowMatrix = getWorldspaceWidget ( ) . getCamera ( ) - > getViewport ( ) - > computeWindowMatrix ( ) ;
osg : : Matrix combined = viewMatrix * projMatrix * windowMatrix ;
return pos * combined ;
}
2021-01-09 21:35:07 +00:00
osg : : Vec3f CSVRender : : InstanceMode : : getProjectionSpaceCoords ( const osg : : Vec3f & pos )
{
osg : : Matrix viewMatrix = getWorldspaceWidget ( ) . getCamera ( ) - > getViewMatrix ( ) ;
osg : : Matrix projMatrix = getWorldspaceWidget ( ) . getCamera ( ) - > getProjectionMatrix ( ) ;
osg : : Matrix combined = viewMatrix * projMatrix ;
return pos * combined ;
}
osg : : Vec3f CSVRender : : InstanceMode : : getMousePlaneCoords ( const QPoint & point , const osg : : Vec3d & dragStart )
{
osg : : Matrix viewMatrix ;
viewMatrix . invert ( getWorldspaceWidget ( ) . getCamera ( ) - > getViewMatrix ( ) ) ;
osg : : Matrix projMatrix ;
projMatrix . invert ( getWorldspaceWidget ( ) . getCamera ( ) - > getProjectionMatrix ( ) ) ;
osg : : Matrix combined = projMatrix * viewMatrix ;
/* calculate viewport normalized coordinates
note : is there a reason to use getCamera ( ) - > getViewport ( ) - > computeWindowMatrix ( ) instead ? */
float x = ( point . x ( ) * 2 ) / getWorldspaceWidget ( ) . getCamera ( ) - > getViewport ( ) - > width ( ) - 1.0f ;
float y = 1.0f - ( point . y ( ) * 2 ) / getWorldspaceWidget ( ) . getCamera ( ) - > getViewport ( ) - > height ( ) ;
osg : : Vec3f mousePlanePoint = osg : : Vec3f ( x , y , dragStart . z ( ) ) * combined ;
return mousePlanePoint ;
}
2020-02-27 09:54:11 +00:00
CSVRender : : InstanceMode : : InstanceMode ( WorldspaceWidget * worldspaceWidget , osg : : ref_ptr < osg : : Group > parentNode , QWidget * parent )
2020-04-20 16:47:14 +00:00
: EditMode ( worldspaceWidget , QIcon ( " :scenetoolbar/editing-instance " ) , Mask_Reference | Mask_Terrain , " Instance editing " ,
2020-11-13 07:39:47 +00:00
parent ) , mSubMode ( nullptr ) , mSubModeId ( " move " ) , mSelectionMode ( nullptr ) , mDragMode ( DragMode_None ) ,
2020-02-27 09:54:11 +00:00
mDragAxis ( - 1 ) , mLocked ( false ) , mUnitScaleDist ( 1 ) , mParentNode ( parentNode )
2016-01-15 11:07:25 +00:00
{
2019-07-01 23:26:05 +00:00
connect ( this , SIGNAL ( requestFocus ( const std : : string & ) ) ,
worldspaceWidget , SIGNAL ( requestFocus ( const std : : string & ) ) ) ;
2020-02-19 09:44:55 +00:00
CSMPrefs : : Shortcut * deleteShortcut = new CSMPrefs : : Shortcut ( " scene-delete " , worldspaceWidget ) ;
connect ( deleteShortcut , SIGNAL ( activated ( bool ) ) , this , SLOT ( deleteSelectedInstances ( bool ) ) ) ;
2020-02-28 11:20:57 +00:00
// Following classes could be simplified by using QSignalMapper, which is obsolete in Qt5.10, but not in Qt4.8 and Qt5.14
CSMPrefs : : Shortcut * dropToCollisionShortcut = new CSMPrefs : : Shortcut ( " scene-instance-drop-collision " , worldspaceWidget ) ;
2020-03-04 14:49:37 +00:00
connect ( dropToCollisionShortcut , SIGNAL ( activated ( ) ) , this , SLOT ( dropSelectedInstancesToCollision ( ) ) ) ;
2020-02-28 11:20:57 +00:00
CSMPrefs : : Shortcut * dropToTerrainLevelShortcut = new CSMPrefs : : Shortcut ( " scene-instance-drop-terrain " , worldspaceWidget ) ;
2020-03-04 14:49:37 +00:00
connect ( dropToTerrainLevelShortcut , SIGNAL ( activated ( ) ) , this , SLOT ( dropSelectedInstancesToTerrain ( ) ) ) ;
2020-02-28 11:20:57 +00:00
CSMPrefs : : Shortcut * dropToCollisionShortcut2 = new CSMPrefs : : Shortcut ( " scene-instance-drop-collision-separately " , worldspaceWidget ) ;
2020-03-04 14:49:37 +00:00
connect ( dropToCollisionShortcut2 , SIGNAL ( activated ( ) ) , this , SLOT ( dropSelectedInstancesToCollisionSeparately ( ) ) ) ;
2020-02-28 11:20:57 +00:00
CSMPrefs : : Shortcut * dropToTerrainLevelShortcut2 = new CSMPrefs : : Shortcut ( " scene-instance-drop-terrain-separately " , worldspaceWidget ) ;
2020-03-04 14:49:37 +00:00
connect ( dropToTerrainLevelShortcut2 , SIGNAL ( activated ( ) ) , this , SLOT ( dropSelectedInstancesToTerrainSeparately ( ) ) ) ;
2016-01-15 11:07:25 +00:00
}
void CSVRender : : InstanceMode : : activate ( CSVWidget : : SceneToolbar * toolbar )
{
if ( ! mSubMode )
{
mSubMode = new CSVWidget : : SceneToolMode ( toolbar , " Edit Sub-Mode " ) ;
2016-02-16 15:02:29 +00:00
mSubMode - > addButton ( new InstanceMoveMode ( this ) , " move " ) ;
2018-04-15 09:35:45 +00:00
mSubMode - > addButton ( " :scenetoolbar/transform-rotate " , " rotate " ,
2016-01-15 11:07:25 +00:00
" Rotate selected instances "
2016-07-26 02:43:37 +00:00
" <ul><li>Use {scene-edit-primary} to rotate instances freely</li> "
" <li>Use {scene-edit-secondary} to rotate instances within the grid</li> "
2016-08-10 23:31:34 +00:00
" <li>The center of the view acts as the axis of rotation</li> "
2022-04-03 00:25:57 +00:00
" </ul> " ) ;
2018-04-15 09:35:45 +00:00
mSubMode - > addButton ( " :scenetoolbar/transform-scale " , " scale " ,
2016-01-15 11:07:25 +00:00
" Scale selected instances "
2016-07-26 02:43:37 +00:00
" <ul><li>Use {scene-edit-primary} to scale instances freely</li> "
" <li>Use {scene-edit-secondary} to scale instances along the grid</li> "
2016-08-10 23:31:34 +00:00
" <li>The scaling rate is based on how close the start of a drag is to the center of the screen</li> "
2022-04-03 00:25:57 +00:00
" </ul> " ) ;
2016-03-01 14:48:34 +00:00
2016-03-05 10:41:42 +00:00
mSubMode - > setButton ( mSubModeId ) ;
2016-03-01 14:48:34 +00:00
connect ( mSubMode , SIGNAL ( modeChanged ( const std : : string & ) ) ,
this , SLOT ( subModeChanged ( const std : : string & ) ) ) ;
2016-01-15 11:07:25 +00:00
}
2016-01-19 11:17:13 +00:00
if ( ! mSelectionMode )
2021-01-09 21:35:07 +00:00
mSelectionMode = new InstanceSelectionMode ( toolbar , getWorldspaceWidget ( ) , mParentNode ) ;
2016-01-19 11:17:13 +00:00
2016-02-16 15:02:29 +00:00
mDragMode = DragMode_None ;
2016-01-15 11:07:25 +00:00
EditMode : : activate ( toolbar ) ;
toolbar - > addTool ( mSubMode ) ;
2016-01-19 11:17:13 +00:00
toolbar - > addTool ( mSelectionMode ) ;
2016-03-01 14:48:34 +00:00
std : : string subMode = mSubMode - > getCurrentId ( ) ;
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . setSubMode ( getSubModeFromId ( subMode ) , Mask_Reference ) ;
2016-01-15 11:07:25 +00:00
}
void CSVRender : : InstanceMode : : deactivate ( CSVWidget : : SceneToolbar * toolbar )
2015-09-27 14:18:22 +00:00
{
2016-03-04 15:25:30 +00:00
mDragMode = DragMode_None ;
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . reset ( Mask_Reference ) ;
2016-03-04 14:31:50 +00:00
2016-01-19 11:17:13 +00:00
if ( mSelectionMode )
{
toolbar - > removeTool ( mSelectionMode ) ;
delete mSelectionMode ;
2020-11-13 07:39:47 +00:00
mSelectionMode = nullptr ;
2016-01-19 11:17:13 +00:00
}
if ( mSubMode )
{
toolbar - > removeTool ( mSubMode ) ;
delete mSubMode ;
2020-11-13 07:39:47 +00:00
mSubMode = nullptr ;
2016-01-19 11:17:13 +00:00
}
2015-09-27 14:18:22 +00:00
2016-01-15 11:07:25 +00:00
EditMode : : deactivate ( toolbar ) ;
2015-09-27 14:18:22 +00:00
}
2016-03-04 15:24:02 +00:00
void CSVRender : : InstanceMode : : setEditLock ( bool locked )
{
mLocked = locked ;
2016-03-05 09:44:46 +00:00
if ( mLocked )
2016-03-05 09:56:54 +00:00
getWorldspaceWidget ( ) . abortDrag ( ) ;
2016-03-04 15:24:02 +00:00
}
2016-05-12 22:21:43 +00:00
void CSVRender : : InstanceMode : : primaryEditPressed ( const WorldspaceHitResult & hit )
2015-09-27 14:18:22 +00:00
{
2015-12-15 09:40:00 +00:00
if ( CSMPrefs : : get ( ) [ " 3D Scene Input " ] [ " context-select " ] . isTrue ( ) )
2016-05-12 22:21:43 +00:00
primarySelectPressed ( hit ) ;
2015-09-29 14:07:14 +00:00
}
2015-09-27 14:18:22 +00:00
2019-07-01 23:26:05 +00:00
void CSVRender : : InstanceMode : : primaryOpenPressed ( const WorldspaceHitResult & hit )
{
if ( hit . tag )
{
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( hit . tag . get ( ) ) )
{
const std : : string refId = objectTag - > mObject - > getReferenceId ( ) ;
emit requestFocus ( refId ) ;
}
}
}
2016-05-12 22:21:43 +00:00
void CSVRender : : InstanceMode : : secondaryEditPressed ( const WorldspaceHitResult & hit )
2015-09-29 14:07:14 +00:00
{
2015-12-15 09:40:00 +00:00
if ( CSMPrefs : : get ( ) [ " 3D Scene Input " ] [ " context-select " ] . isTrue ( ) )
2016-05-12 22:21:43 +00:00
secondarySelectPressed ( hit ) ;
2015-09-27 14:18:22 +00:00
}
2016-05-12 22:21:43 +00:00
void CSVRender : : InstanceMode : : primarySelectPressed ( const WorldspaceHitResult & hit )
2015-10-29 10:20:06 +00:00
{
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . clearSelection ( Mask_Reference ) ;
2015-10-29 10:27:01 +00:00
2016-05-12 22:21:43 +00:00
if ( hit . tag )
2015-10-29 10:20:06 +00:00
{
2016-05-12 22:21:43 +00:00
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( hit . tag . get ( ) ) )
2015-10-29 10:20:06 +00:00
{
2015-10-29 10:27:01 +00:00
// hit an Object, select it
2015-10-29 10:20:06 +00:00
CSVRender : : Object * object = objectTag - > mObject ;
2015-10-29 10:27:01 +00:00
object - > setSelected ( true ) ;
2015-10-29 10:20:06 +00:00
return ;
}
}
}
2016-05-12 22:21:43 +00:00
void CSVRender : : InstanceMode : : secondarySelectPressed ( const WorldspaceHitResult & hit )
2015-09-27 14:18:22 +00:00
{
2016-05-12 22:21:43 +00:00
if ( hit . tag )
2015-09-27 14:18:22 +00:00
{
2016-05-12 22:21:43 +00:00
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( hit . tag . get ( ) ) )
2015-09-27 14:18:22 +00:00
{
// hit an Object, toggle its selection state
CSVRender : : Object * object = objectTag - > mObject ;
object - > setSelected ( ! object - > getSelected ( ) ) ;
2015-09-29 11:53:47 +00:00
return ;
2015-09-27 14:18:22 +00:00
}
}
}
2016-01-10 07:56:15 +00:00
2016-05-18 01:24:16 +00:00
bool CSVRender : : InstanceMode : : primaryEditStartDrag ( const QPoint & pos )
2016-02-16 15:02:29 +00:00
{
2016-03-04 15:24:02 +00:00
if ( mDragMode ! = DragMode_None | | mLocked )
2016-02-16 15:02:29 +00:00
return false ;
2016-05-18 01:24:16 +00:00
WorldspaceHitResult hit = getWorldspaceWidget ( ) . mousePick ( pos , getWorldspaceWidget ( ) . getInteractionMask ( ) ) ;
2016-08-14 18:43:29 +00:00
2020-04-20 16:47:14 +00:00
std : : vector < osg : : ref_ptr < TagBase > > selection = getWorldspaceWidget ( ) . getSelection ( Mask_Reference ) ;
2016-08-14 18:43:29 +00:00
if ( selection . empty ( ) )
2016-02-16 15:02:29 +00:00
{
2016-08-14 18:43:29 +00:00
// 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 ( ) )
2016-02-16 15:02:29 +00:00
{
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . clearSelection ( Mask_Reference ) ;
2016-08-14 18:43:29 +00:00
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( hit . tag . get ( ) ) )
{
CSVRender : : Object * object = objectTag - > mObject ;
object - > setSelected ( true ) ;
}
2016-02-16 15:02:29 +00:00
}
2020-04-20 16:47:14 +00:00
selection = getWorldspaceWidget ( ) . getSelection ( Mask_Reference ) ;
2016-08-14 18:43:29 +00:00
if ( selection . empty ( ) )
return false ;
}
2016-02-16 15:02:29 +00:00
2021-08-31 21:15:10 +00:00
mObjectsAtDragStart . clear ( ) ;
2016-02-16 15:02:29 +00:00
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 ( ) ) )
{
2016-08-10 23:31:34 +00:00
if ( mSubModeId = = " move " )
{
objectTag - > mObject - > setEdited ( Object : : Override_Position ) ;
2021-08-31 21:24:50 +00:00
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 ) ;
2021-08-31 21:15:10 +00:00
mDragStart = getMousePlaneCoords ( pos , getProjectionSpaceCoords ( thisPoint ) ) ;
mObjectsAtDragStart . emplace_back ( thisPoint ) ;
2016-08-10 23:31:34 +00:00
mDragMode = DragMode_Move ;
}
else if ( mSubModeId = = " rotate " )
{
objectTag - > mObject - > setEdited ( Object : : Override_Rotation ) ;
mDragMode = DragMode_Rotate ;
}
else if ( mSubModeId = = " scale " )
{
objectTag - > mObject - > setEdited ( Object : : Override_Scale ) ;
mDragMode = DragMode_Scale ;
2016-08-12 21:11:37 +00:00
// Calculate scale factor
2020-04-20 16:47:14 +00:00
std : : vector < osg : : ref_ptr < TagBase > > editedSelection = getWorldspaceWidget ( ) . getEdited ( Mask_Reference ) ;
2016-10-15 16:34:54 +00:00
osg : : Vec3f center = getScreenCoords ( getSelectionCenter ( editedSelection ) ) ;
2016-08-12 21:11:37 +00:00
2016-08-10 23:31:34 +00:00
int widgetHeight = getWorldspaceWidget ( ) . height ( ) ;
2016-08-12 21:11:37 +00:00
float dx = pos . x ( ) - center . x ( ) ;
float dy = ( widgetHeight - pos . y ( ) ) - center . y ( ) ;
2016-08-10 23:31:34 +00:00
2016-08-12 21:11:37 +00:00
mUnitScaleDist = std : : sqrt ( dx * dx + dy * dy ) ;
2016-08-10 23:31:34 +00:00
}
2016-02-16 15:02:29 +00:00
}
}
2016-05-12 22:21:43 +00:00
if ( CSVRender : : ObjectMarkerTag * objectTag = dynamic_cast < CSVRender : : ObjectMarkerTag * > ( hit . tag . get ( ) ) )
2016-03-04 11:00:05 +00:00
{
mDragAxis = objectTag - > mAxis ;
}
else
2016-03-04 11:02:45 +00:00
mDragAxis = - 1 ;
2016-02-16 15:02:29 +00:00
return true ;
}
2016-05-18 01:24:16 +00:00
bool CSVRender : : InstanceMode : : secondaryEditStartDrag ( const QPoint & pos )
2016-02-16 15:02:29 +00:00
{
2022-04-03 00:25:57 +00:00
if ( mDragMode ! = DragMode_None | | mLocked )
2016-03-04 15:24:02 +00:00
return false ;
2016-02-16 15:02:29 +00:00
2022-04-03 00:25:57 +00:00
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 ;
2016-02-16 15:02:29 +00:00
}
2021-01-09 21:35:07 +00:00
bool CSVRender : : InstanceMode : : primarySelectStartDrag ( const QPoint & pos )
{
if ( mDragMode ! = DragMode_None | | mLocked )
return false ;
std : : string primarySelectAction = CSMPrefs : : get ( ) [ " 3D Scene Editing " ] [ " primary-select-action " ] . toString ( ) ;
if ( primarySelectAction = = " Select only " ) mDragMode = DragMode_Select_Only ;
else if ( primarySelectAction = = " Add to selection " ) mDragMode = DragMode_Select_Add ;
else if ( primarySelectAction = = " Remove from selection " ) mDragMode = DragMode_Select_Remove ;
else if ( primarySelectAction = = " Invert selection " ) mDragMode = DragMode_Select_Invert ;
WorldspaceHitResult hit = getWorldspaceWidget ( ) . mousePick ( pos , getWorldspaceWidget ( ) . getInteractionMask ( ) ) ;
mSelectionMode - > setDragStart ( hit . worldPos ) ;
return true ;
}
bool CSVRender : : InstanceMode : : secondarySelectStartDrag ( const QPoint & pos )
{
if ( mDragMode ! = DragMode_None | | mLocked )
return false ;
std : : string secondarySelectAction = CSMPrefs : : get ( ) [ " 3D Scene Editing " ] [ " secondary-select-action " ] . toString ( ) ;
if ( secondarySelectAction = = " Select only " ) mDragMode = DragMode_Select_Only ;
else if ( secondarySelectAction = = " Add to selection " ) mDragMode = DragMode_Select_Add ;
else if ( secondarySelectAction = = " Remove from selection " ) mDragMode = DragMode_Select_Remove ;
else if ( secondarySelectAction = = " Invert selection " ) mDragMode = DragMode_Select_Invert ;
WorldspaceHitResult hit = getWorldspaceWidget ( ) . mousePick ( pos , getWorldspaceWidget ( ) . getInteractionMask ( ) ) ;
mSelectionMode - > setDragStart ( hit . worldPos ) ;
return true ;
}
2016-05-18 01:24:16 +00:00
void CSVRender : : InstanceMode : : drag ( const QPoint & pos , int diffX , int diffY , double speedFactor )
2016-02-16 15:02:29 +00:00
{
2016-08-10 23:31:34 +00:00
osg : : Vec3f offset ;
osg : : Quat rotation ;
2016-03-04 11:00:05 +00:00
2020-04-20 16:47:14 +00:00
std : : vector < osg : : ref_ptr < TagBase > > selection = getWorldspaceWidget ( ) . getEdited ( Mask_Reference ) ;
2016-03-04 11:00:05 +00:00
2022-04-03 00:25:57 +00:00
if ( mDragMode = = DragMode_Move | | mDragMode = = DragMode_Move_Snap ) { }
else if ( mDragMode = = DragMode_Rotate | | mDragMode = = DragMode_Rotate_Snap )
2016-08-10 23:31:34 +00:00
{
osg : : Vec3f eye , centre , up ;
getWorldspaceWidget ( ) . getCamera ( ) - > getViewMatrix ( ) . getLookAt ( eye , centre , up ) ;
2016-03-04 11:00:05 +00:00
2016-08-15 19:07:43 +00:00
float angle ;
osg : : Vec3f axis ;
2016-03-04 11:00:05 +00:00
2016-08-15 19:07:43 +00:00
if ( mDragAxis = = - 1 )
{
// Free rotate
float rotationFactor = CSMPrefs : : get ( ) [ " 3D Scene Input " ] [ " rotate-factor " ] . toDouble ( ) * speedFactor ;
2016-08-10 23:31:34 +00:00
2016-08-15 19:07:43 +00:00
osg : : Quat cameraRotation = getWorldspaceWidget ( ) . getCamera ( ) - > getInverseViewMatrix ( ) . getRotate ( ) ;
2016-08-10 23:31:34 +00:00
2016-08-15 19:07:43 +00:00
osg : : Vec3f camForward = centre - eye ;
osg : : Vec3f screenDir = cameraRotation * osg : : Vec3f ( diffX , diffY , 0 ) ;
screenDir . normalize ( ) ;
2016-08-10 23:31:34 +00:00
2016-08-15 19:07:43 +00:00
angle = std : : sqrt ( diffX * diffX + diffY * diffY ) * rotationFactor ;
axis = screenDir ^ camForward ;
}
else
2016-08-10 23:31:34 +00:00
{
2016-08-15 19:07:43 +00:00
// Global axis rotation
osg : : Vec3f camBack = eye - centre ;
2016-08-10 23:31:34 +00:00
for ( int i = 0 ; i < 3 ; + + i )
{
if ( i = = mDragAxis )
axis [ i ] = 1 ;
else
axis [ i ] = 0 ;
}
2016-08-15 19:07:43 +00:00
// Flip axis if facing opposite side
2016-08-10 23:31:34 +00:00
if ( camBack * axis < 0 )
axis * = - 1 ;
2016-08-15 19:07:43 +00:00
// Convert coordinate system
osg : : Vec3f screenCenter = getScreenCoords ( getSelectionCenter ( selection ) ) ;
int widgetHeight = getWorldspaceWidget ( ) . height ( ) ;
float newX = pos . x ( ) - screenCenter . x ( ) ;
float newY = ( widgetHeight - pos . y ( ) ) - screenCenter . y ( ) ;
float oldX = newX - diffX ;
float oldY = newY - diffY ; // diffY appears to already be flipped
osg : : Vec3f oldVec = osg : : Vec3f ( oldX , oldY , 0 ) ;
oldVec . normalize ( ) ;
osg : : Vec3f newVec = osg : : Vec3f ( newX , newY , 0 ) ;
newVec . normalize ( ) ;
// Find angle and axis of rotation
angle = std : : acos ( oldVec * newVec ) * speedFactor ;
if ( ( ( oldVec ^ newVec ) * camBack < 0 ) ^ ( camBack . z ( ) < 0 ) )
angle * = - 1 ;
2016-08-10 23:31:34 +00:00
}
rotation = osg : : Quat ( angle , axis ) ;
}
2022-04-03 00:25:57 +00:00
else if ( mDragMode = = DragMode_Scale | | mDragMode = = DragMode_Scale_Snap )
2016-02-16 15:02:29 +00:00
{
2016-08-12 21:11:37 +00:00
osg : : Vec3f center = getScreenCoords ( getSelectionCenter ( selection ) ) ;
// Calculate scaling distance/rate
2016-08-10 23:31:34 +00:00
int widgetHeight = getWorldspaceWidget ( ) . height ( ) ;
2016-08-12 21:11:37 +00:00
float dx = pos . x ( ) - center . x ( ) ;
float dy = ( widgetHeight - pos . y ( ) ) - center . y ( ) ;
2016-08-10 23:31:34 +00:00
2016-08-12 21:11:37 +00:00
float dist = std : : sqrt ( dx * dx + dy * dy ) ;
2016-08-10 23:31:34 +00:00
float scale = dist / mUnitScaleDist ;
// Only uniform scaling is currently supported
offset = osg : : Vec3f ( scale , scale , scale ) ;
}
2021-01-09 21:35:07 +00:00
else if ( mSelectionMode - > getCurrentId ( ) = = " cube-centre " )
{
osg : : Vec3f mousePlanePoint = getMousePlaneCoords ( pos , getProjectionSpaceCoords ( mSelectionMode - > getDragStart ( ) ) ) ;
mSelectionMode - > drawSelectionCubeCentre ( mousePlanePoint ) ;
return ;
}
else if ( mSelectionMode - > getCurrentId ( ) = = " cube-corner " )
{
osg : : Vec3f mousePlanePoint = getMousePlaneCoords ( pos , getProjectionSpaceCoords ( mSelectionMode - > getDragStart ( ) ) ) ;
mSelectionMode - > drawSelectionCubeCorner ( mousePlanePoint ) ;
return ;
}
else if ( mSelectionMode - > getCurrentId ( ) = = " sphere " )
{
osg : : Vec3f mousePlanePoint = getMousePlaneCoords ( pos , getProjectionSpaceCoords ( mSelectionMode - > getDragStart ( ) ) ) ;
mSelectionMode - > drawSelectionSphere ( mousePlanePoint ) ;
return ;
}
2016-08-10 23:31:34 +00:00
2021-08-31 21:15:10 +00:00
int i = 0 ;
2016-08-12 21:11:37 +00:00
// Apply
2021-08-31 21:15:10 +00:00
for ( std : : vector < osg : : ref_ptr < TagBase > > : : iterator iter ( selection . begin ( ) ) ; iter ! = selection . end ( ) ; + + iter , i + + )
2016-02-16 15:02:29 +00:00
{
2016-08-10 23:31:34 +00:00
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( iter - > get ( ) ) )
2016-03-04 11:00:05 +00:00
{
2022-04-03 00:25:57 +00:00
if ( mDragMode = = DragMode_Move | | mDragMode = = DragMode_Move_Snap )
2016-08-10 23:31:34 +00:00
{
ESM : : Position position = objectTag - > mObject - > getPosition ( ) ;
2021-08-31 21:24:50 +00:00
osg : : Vec3f mousePos = getMousePlaneCoords ( pos , getProjectionSpaceCoords ( mDragStart ) ) ;
2021-08-31 21:15:10 +00:00
float addToX = mousePos . x ( ) - mDragStart . x ( ) ;
float addToY = mousePos . y ( ) - mDragStart . y ( ) ;
float addToZ = mousePos . z ( ) - mDragStart . z ( ) ;
position . pos [ 0 ] = mObjectsAtDragStart [ i ] . x ( ) + addToX ;
position . pos [ 1 ] = mObjectsAtDragStart [ i ] . y ( ) + addToY ;
position . pos [ 2 ] = mObjectsAtDragStart [ i ] . z ( ) + addToZ ;
2016-02-16 15:02:29 +00:00
2022-04-03 00:25:57 +00:00
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 ( ) ) ;
}
2021-08-31 22:37:17 +00:00
// XYZ-locking
if ( mDragAxis ! = - 1 )
{
for ( int j = 0 ; j < 3 ; + + j )
{
if ( j ! = mDragAxis )
position . pos [ j ] = mObjectsAtDragStart [ i ] [ j ] ;
}
}
2016-08-10 23:31:34 +00:00
objectTag - > mObject - > setPosition ( position . pos ) ;
}
2022-04-03 00:25:57 +00:00
else if ( mDragMode = = DragMode_Rotate | | mDragMode = = DragMode_Rotate_Snap )
2016-02-16 15:02:29 +00:00
{
2016-08-10 23:31:34 +00:00
ESM : : Position position = objectTag - > mObject - > getPosition ( ) ;
osg : : Quat currentRot = eulerToQuat ( osg : : Vec3f ( position . rot [ 0 ] , position . rot [ 1 ] , position . rot [ 2 ] ) ) ;
osg : : Quat combined = currentRot * rotation ;
osg : : Vec3f euler = quatToEuler ( combined ) ;
// There appears to be a very rare rounding error that can cause asin to return NaN
if ( ! euler . isNaN ( ) )
2016-02-16 15:02:29 +00:00
{
2016-08-10 23:31:34 +00:00
position . rot [ 0 ] = euler . x ( ) ;
position . rot [ 1 ] = euler . y ( ) ;
position . rot [ 2 ] = euler . z ( ) ;
2016-02-16 15:02:29 +00:00
}
2016-08-10 23:31:34 +00:00
2022-04-03 00:25:57 +00:00
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 ( ) ) ) ;
}
2016-08-10 23:31:34 +00:00
objectTag - > mObject - > setRotation ( position . rot ) ;
2016-02-16 15:02:29 +00:00
}
2022-04-03 00:25:57 +00:00
else if ( mDragMode = = DragMode_Scale | | mDragMode = = DragMode_Scale_Snap )
2016-08-10 23:31:34 +00:00
{
// Reset scale
objectTag - > mObject - > setEdited ( 0 ) ;
objectTag - > mObject - > setEdited ( Object : : Override_Scale ) ;
2016-02-16 15:02:29 +00:00
2016-08-10 23:31:34 +00:00
float scale = objectTag - > mObject - > getScale ( ) ;
scale * = offset . x ( ) ;
2016-02-16 15:02:29 +00:00
2022-04-03 00:25:57 +00:00
if ( mDragMode = = DragMode_Scale_Snap )
{
scale = CSVRender : : InstanceMode : : roundFloatToMult ( scale , CSMPrefs : : get ( ) [ " 3D Scene Editing " ] [ " gridsnap-scale " ] . toDouble ( ) ) ;
}
2016-08-10 23:31:34 +00:00
objectTag - > mObject - > setScale ( scale ) ;
}
}
2016-02-16 15:02:29 +00:00
}
}
2016-05-18 01:24:16 +00:00
void CSVRender : : InstanceMode : : dragCompleted ( const QPoint & pos )
2016-02-16 15:02:29 +00:00
{
std : : vector < osg : : ref_ptr < TagBase > > selection =
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . getEdited ( Mask_Reference ) ;
2016-02-16 15:02:29 +00:00
QUndoStack & undoStack = getWorldspaceWidget ( ) . getDocument ( ) . getUndoStack ( ) ;
QString description ;
switch ( mDragMode )
{
2016-03-04 11:02:45 +00:00
case DragMode_Move : description = " Move Instances " ; break ;
2016-08-10 23:31:34 +00:00
case DragMode_Rotate : description = " Rotate Instances " ; break ;
case DragMode_Scale : description = " Scale Instances " ; break ;
2021-01-09 21:35:07 +00:00
case DragMode_Select_Only :
handleSelectDrag ( pos ) ;
return ;
break ;
case DragMode_Select_Add :
handleSelectDrag ( pos ) ;
return ;
break ;
case DragMode_Select_Remove :
handleSelectDrag ( pos ) ;
return ;
break ;
case DragMode_Select_Invert :
handleSelectDrag ( pos ) ;
return ;
break ;
2022-04-03 00:25:57 +00:00
case DragMode_Move_Snap : description = " Move Instances " ; break ;
case DragMode_Rotate_Snap : description = " Rotate Instances " ; break ;
case DragMode_Scale_Snap : description = " Scale Instances " ; break ;
2016-02-16 15:02:29 +00:00
case DragMode_None : break ;
}
2016-03-08 09:48:44 +00:00
CSMWorld : : CommandMacro macro ( undoStack , description ) ;
2016-02-16 15:02:29 +00:00
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 ( ) ) )
{
2016-03-11 13:04:47 +00:00
objectTag - > mObject - > apply ( macro ) ;
2016-02-16 15:02:29 +00:00
}
}
2021-08-31 22:56:11 +00:00
mObjectsAtDragStart . clear ( ) ;
2016-02-16 15:02:29 +00:00
mDragMode = DragMode_None ;
}
2016-03-04 14:19:26 +00:00
void CSVRender : : InstanceMode : : dragAborted ( )
{
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . reset ( Mask_Reference ) ;
2016-03-04 14:19:26 +00:00
mDragMode = DragMode_None ;
}
2016-02-16 15:02:29 +00:00
void CSVRender : : InstanceMode : : dragWheel ( int diff , double speedFactor )
{
2022-04-03 00:25:57 +00:00
if ( mDragMode = = DragMode_Move | | mDragMode = = DragMode_Move_Snap )
2016-02-16 15:02:29 +00:00
{
osg : : Vec3f eye ;
osg : : Vec3f centre ;
osg : : Vec3f up ;
getWorldspaceWidget ( ) . getCamera ( ) - > getViewMatrix ( ) . getLookAt ( eye , centre , up ) ;
osg : : Vec3f offset = centre - eye ;
offset . normalize ( ) ;
offset * = diff * speedFactor ;
std : : vector < osg : : ref_ptr < TagBase > > selection =
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . getEdited ( Mask_Reference ) ;
2016-02-16 15:02:29 +00:00
2021-08-31 22:37:17 +00:00
int j = 0 ;
2016-02-16 15:02:29 +00:00
for ( std : : vector < osg : : ref_ptr < TagBase > > : : iterator iter ( selection . begin ( ) ) ;
2021-08-31 22:37:17 +00:00
iter ! = selection . end ( ) ; + + iter , j + + )
2016-02-16 15:02:29 +00:00
{
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( iter - > get ( ) ) )
{
ESM : : Position position = objectTag - > mObject - > getPosition ( ) ;
for ( int i = 0 ; i < 3 ; + + i )
position . pos [ i ] + = offset [ i ] ;
objectTag - > mObject - > setPosition ( position . pos ) ;
2021-08-31 22:37:17 +00:00
osg : : Vec3f thisPoint ( position . pos [ 0 ] , position . pos [ 1 ] , position . pos [ 2 ] ) ;
mDragStart = getMousePlaneCoords ( getWorldspaceWidget ( ) . mapFromGlobal ( QCursor : : pos ( ) ) , getProjectionSpaceCoords ( thisPoint ) ) ;
mObjectsAtDragStart [ j ] = thisPoint ;
2016-02-16 15:02:29 +00:00
}
}
}
}
2016-01-10 07:56:15 +00:00
void CSVRender : : InstanceMode : : dragEnterEvent ( QDragEnterEvent * event )
{
if ( const CSMWorld : : TableMimeData * mime = dynamic_cast < const CSMWorld : : TableMimeData * > ( event - > mimeData ( ) ) )
{
if ( ! mime - > fromDocument ( getWorldspaceWidget ( ) . getDocument ( ) ) )
return ;
if ( mime - > holdsType ( CSMWorld : : UniversalId : : Type_Referenceable ) )
event - > accept ( ) ;
}
}
void CSVRender : : InstanceMode : : dropEvent ( QDropEvent * event )
{
if ( const CSMWorld : : TableMimeData * mime = dynamic_cast < const CSMWorld : : TableMimeData * > ( event - > mimeData ( ) ) )
{
CSMDoc : : Document & document = getWorldspaceWidget ( ) . getDocument ( ) ;
if ( ! mime - > fromDocument ( document ) )
return ;
2016-05-18 01:24:16 +00:00
WorldspaceHitResult hit = getWorldspaceWidget ( ) . mousePick ( event - > pos ( ) , getWorldspaceWidget ( ) . getInteractionMask ( ) ) ;
2016-01-10 07:56:15 +00:00
2016-05-18 01:24:16 +00:00
std : : string cellId = getWorldspaceWidget ( ) . getCellId ( hit . worldPos ) ;
2016-01-10 07:56:15 +00:00
2016-01-14 12:20:01 +00:00
CSMWorld : : IdTree & cellTable = dynamic_cast < CSMWorld : : IdTree & > (
* document . getData ( ) . getTableModel ( CSMWorld : : UniversalId : : Type_Cells ) ) ;
2016-01-10 07:56:15 +00:00
2016-01-14 12:20:01 +00:00
bool noCell = document . getData ( ) . getCells ( ) . searchId ( cellId ) = = - 1 ;
if ( noCell )
{
2018-05-16 08:41:37 +00:00
std : : string mode = CSMPrefs : : get ( ) [ " 3D Scene Editing " ] [ " outside-drop " ] . toString ( ) ;
2016-01-14 12:20:01 +00:00
// target cell does not exist
if ( mode = = " Discard " )
return ;
if ( mode = = " Create cell and insert " )
{
2017-04-28 15:30:26 +00:00
std : : unique_ptr < CSMWorld : : CreateCommand > createCommand (
2016-01-14 12:20:01 +00:00
new CSMWorld : : CreateCommand ( cellTable , cellId ) ) ;
int parentIndex = cellTable . findColumnIndex ( CSMWorld : : Columns : : ColumnId_Cell ) ;
int index = cellTable . findNestedColumnIndex ( parentIndex , CSMWorld : : Columns : : ColumnId_Interior ) ;
createCommand - > addNestedValue ( parentIndex , index , false ) ;
document . getUndoStack ( ) . push ( createCommand . release ( ) ) ;
if ( CSVRender : : PagedWorldspaceWidget * paged =
dynamic_cast < CSVRender : : PagedWorldspaceWidget * > ( & getWorldspaceWidget ( ) ) )
{
CSMWorld : : CellSelection selection = paged - > getCellSelection ( ) ;
selection . add ( CSMWorld : : CellCoordinates : : fromId ( cellId ) . first ) ;
paged - > setCellSelection ( selection ) ;
}
}
}
else if ( CSVRender : : PagedWorldspaceWidget * paged =
dynamic_cast < CSVRender : : PagedWorldspaceWidget * > ( & getWorldspaceWidget ( ) ) )
{
CSMWorld : : CellSelection selection = paged - > getCellSelection ( ) ;
if ( ! selection . has ( CSMWorld : : CellCoordinates : : fromId ( cellId ) . first ) )
{
// target cell exists, but is not shown
std : : string mode =
2018-05-16 08:41:37 +00:00
CSMPrefs : : get ( ) [ " 3D Scene Editing " ] [ " outside-visible-drop " ] . toString ( ) ;
2016-01-14 12:20:01 +00:00
if ( mode = = " Discard " )
return ;
if ( mode = = " Show cell and insert " )
{
selection . add ( CSMWorld : : CellCoordinates : : fromId ( cellId ) . first ) ;
paged - > setCellSelection ( selection ) ;
}
}
}
2016-01-10 07:56:15 +00:00
CSMWorld : : IdTable & referencesTable = dynamic_cast < CSMWorld : : IdTable & > (
* document . getData ( ) . getTableModel ( CSMWorld : : UniversalId : : Type_References ) ) ;
2016-01-14 12:20:01 +00:00
bool dropped = false ;
std : : vector < CSMWorld : : UniversalId > ids = mime - > getData ( ) ;
2016-01-10 07:56:15 +00:00
for ( std : : vector < CSMWorld : : UniversalId > : : const_iterator iter ( ids . begin ( ) ) ;
iter ! = ids . end ( ) ; + + iter )
if ( mime - > isReferencable ( iter - > getType ( ) ) )
{
// create reference
2017-04-28 15:30:26 +00:00
std : : unique_ptr < CSMWorld : : CreateCommand > createCommand (
2016-01-10 07:56:15 +00:00
new CSMWorld : : CreateCommand (
referencesTable , document . getData ( ) . getReferences ( ) . getNewId ( ) ) ) ;
createCommand - > addValue ( referencesTable . findColumnIndex (
CSMWorld : : Columns : : ColumnId_Cell ) , QString : : fromUtf8 ( cellId . c_str ( ) ) ) ;
createCommand - > addValue ( referencesTable . findColumnIndex (
2016-05-18 01:24:16 +00:00
CSMWorld : : Columns : : ColumnId_PositionXPos ) , hit . worldPos . x ( ) ) ;
2016-01-10 07:56:15 +00:00
createCommand - > addValue ( referencesTable . findColumnIndex (
2016-05-18 01:24:16 +00:00
CSMWorld : : Columns : : ColumnId_PositionYPos ) , hit . worldPos . y ( ) ) ;
2016-01-10 07:56:15 +00:00
createCommand - > addValue ( referencesTable . findColumnIndex (
2016-05-18 01:24:16 +00:00
CSMWorld : : Columns : : ColumnId_PositionZPos ) , hit . worldPos . z ( ) ) ;
2016-01-10 07:56:15 +00:00
createCommand - > addValue ( referencesTable . findColumnIndex (
CSMWorld : : Columns : : ColumnId_ReferenceableId ) ,
QString : : fromUtf8 ( iter - > getId ( ) . c_str ( ) ) ) ;
2016-03-24 10:12:05 +00:00
document . getUndoStack ( ) . push ( createCommand . release ( ) ) ;
2016-01-10 07:56:15 +00:00
dropped = true ;
}
if ( dropped )
event - > accept ( ) ;
}
}
2016-03-01 14:48:34 +00:00
int CSVRender : : InstanceMode : : getSubMode ( ) const
{
return mSubMode ? getSubModeFromId ( mSubMode - > getCurrentId ( ) ) : 0 ;
}
void CSVRender : : InstanceMode : : subModeChanged ( const std : : string & id )
{
2016-03-05 10:41:42 +00:00
mSubModeId = id ;
2016-03-05 09:56:54 +00:00
getWorldspaceWidget ( ) . abortDrag ( ) ;
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . setSubMode ( getSubModeFromId ( id ) , Mask_Reference ) ;
2016-03-01 14:48:34 +00:00
}
2020-02-19 09:44:55 +00:00
2021-01-09 21:35:07 +00:00
void CSVRender : : InstanceMode : : handleSelectDrag ( const QPoint & pos )
{
osg : : Vec3f mousePlanePoint = getMousePlaneCoords ( pos , getProjectionSpaceCoords ( mSelectionMode - > getDragStart ( ) ) ) ;
mSelectionMode - > dragEnded ( mousePlanePoint , mDragMode ) ;
mDragMode = DragMode_None ;
}
2020-02-19 09:44:55 +00:00
void CSVRender : : InstanceMode : : deleteSelectedInstances ( bool active )
{
2020-04-20 16:47:14 +00:00
std : : vector < osg : : ref_ptr < TagBase > > selection = getWorldspaceWidget ( ) . getSelection ( Mask_Reference ) ;
2020-02-19 09:44:55 +00:00
if ( selection . empty ( ) ) return ;
CSMDoc : : Document & document = getWorldspaceWidget ( ) . getDocument ( ) ;
CSMWorld : : IdTable & referencesTable = dynamic_cast < CSMWorld : : IdTable & > (
* document . getData ( ) . getTableModel ( CSMWorld : : UniversalId : : Type_References ) ) ;
QUndoStack & undoStack = document . getUndoStack ( ) ;
CSMWorld : : CommandMacro macro ( undoStack , " Delete Instances " ) ;
for ( osg : : ref_ptr < TagBase > tag : selection )
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( tag . get ( ) ) )
macro . push ( new CSMWorld : : DeleteCommand ( referencesTable , objectTag - > mObject - > getReferenceId ( ) ) ) ;
2020-04-20 16:47:14 +00:00
getWorldspaceWidget ( ) . clearSelection ( Mask_Reference ) ;
2020-02-19 09:44:55 +00:00
}
2020-02-27 09:54:11 +00:00
2021-01-28 21:10:33 +00:00
void CSVRender : : InstanceMode : : dropInstance ( CSVRender : : Object * object , float dropHeight )
2020-02-27 09:54:11 +00:00
{
2021-01-28 21:10:33 +00:00
object - > setEdited ( Object : : Override_Position ) ;
ESM : : Position position = object - > getPosition ( ) ;
position . pos [ 2 ] - = dropHeight ;
object - > setPosition ( position . pos ) ;
2020-02-27 09:54:11 +00:00
}
2021-01-28 21:10:33 +00:00
float CSVRender : : InstanceMode : : calculateDropHeight ( DropMode dropMode , CSVRender : : Object * object , float objectHeight )
2020-02-27 09:54:11 +00:00
{
2020-03-19 09:18:54 +00:00
osg : : Vec3d point = object - > getPosition ( ) . asVec3 ( ) ;
2020-02-27 09:54:11 +00:00
2020-02-28 11:20:57 +00:00
osg : : Vec3d start = point ;
2020-03-04 14:49:37 +00:00
start . z ( ) + = objectHeight ;
2020-02-28 11:20:57 +00:00
osg : : Vec3d end = point ;
2020-03-04 14:49:37 +00:00
end . z ( ) = std : : numeric_limits < float > : : lowest ( ) ;
2020-02-27 09:54:11 +00:00
2020-02-28 11:20:57 +00:00
osg : : ref_ptr < osgUtil : : LineSegmentIntersector > intersector ( new osgUtil : : LineSegmentIntersector (
osgUtil : : Intersector : : MODEL , start , end ) ) ;
intersector - > setIntersectionLimit ( osgUtil : : LineSegmentIntersector : : NO_LIMIT ) ;
osgUtil : : IntersectionVisitor visitor ( intersector ) ;
2021-01-28 21:10:33 +00:00
if ( dropMode & Terrain )
2020-04-20 16:47:14 +00:00
visitor . setTraversalMask ( Mask_Terrain ) ;
2021-01-28 21:10:33 +00:00
if ( dropMode & Collision )
2020-04-20 16:47:14 +00:00
visitor . setTraversalMask ( Mask_Terrain | Mask_Reference ) ;
2020-02-28 11:20:57 +00:00
mParentNode - > accept ( visitor ) ;
2020-04-04 13:45:26 +00:00
osgUtil : : LineSegmentIntersector : : Intersections : : iterator it = intersector - > getIntersections ( ) . begin ( ) ;
if ( it ! = intersector - > getIntersections ( ) . end ( ) )
2020-02-28 11:20:57 +00:00
{
osgUtil : : LineSegmentIntersector : : Intersection intersection = * it ;
2020-03-03 19:18:09 +00:00
float collisionLevel = intersection . getWorldIntersectPoint ( ) . z ( ) ;
return point . z ( ) - collisionLevel + objectHeight ;
2020-02-28 11:20:57 +00:00
}
return 0.0f ;
}
2020-03-04 14:49:37 +00:00
void CSVRender : : InstanceMode : : dropSelectedInstancesToCollision ( )
2020-02-28 11:20:57 +00:00
{
handleDropMethod ( Collision , " Drop instances to next collision " ) ;
}
2020-03-04 14:49:37 +00:00
void CSVRender : : InstanceMode : : dropSelectedInstancesToTerrain ( )
2020-02-28 11:20:57 +00:00
{
handleDropMethod ( Terrain , " Drop instances to terrain level " ) ;
}
2020-03-04 14:49:37 +00:00
void CSVRender : : InstanceMode : : dropSelectedInstancesToCollisionSeparately ( )
2020-02-28 11:20:57 +00:00
{
2021-01-28 21:22:48 +00:00
handleDropMethod ( CollisionSep , " Drop instances to next collision level separately " ) ;
2020-02-27 09:54:11 +00:00
}
2020-03-04 14:49:37 +00:00
void CSVRender : : InstanceMode : : dropSelectedInstancesToTerrainSeparately ( )
2020-02-28 11:20:57 +00:00
{
2021-01-28 21:22:48 +00:00
handleDropMethod ( TerrainSep , " Drop instances to terrain level separately " ) ;
2020-02-28 11:20:57 +00:00
}
void CSVRender : : InstanceMode : : handleDropMethod ( DropMode dropMode , QString commandMsg )
2020-02-27 09:54:11 +00:00
{
2020-04-20 16:47:14 +00:00
std : : vector < osg : : ref_ptr < TagBase > > selection = getWorldspaceWidget ( ) . getSelection ( Mask_Reference ) ;
2020-03-19 09:18:54 +00:00
if ( selection . empty ( ) )
return ;
2020-02-27 09:54:11 +00:00
CSMDoc : : Document & document = getWorldspaceWidget ( ) . getDocument ( ) ;
QUndoStack & undoStack = document . getUndoStack ( ) ;
2020-02-28 11:20:57 +00:00
CSMWorld : : CommandMacro macro ( undoStack , commandMsg ) ;
2021-01-28 21:10:33 +00:00
DropObjectHeightHandler dropObjectDataHandler ( & getWorldspaceWidget ( ) ) ;
2020-03-18 09:16:21 +00:00
2021-01-28 21:10:33 +00:00
if ( dropMode & Separate )
2020-03-18 09:16:21 +00:00
{
2021-01-28 21:10:33 +00:00
int counter = 0 ;
for ( osg : : ref_ptr < TagBase > tag : selection )
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( tag . get ( ) ) )
{
float objectHeight = dropObjectDataHandler . mObjectHeights [ counter ] ;
float dropHeight = calculateDropHeight ( dropMode , objectTag - > mObject , objectHeight ) ;
dropInstance ( objectTag - > mObject , dropHeight ) ;
objectTag - > mObject - > apply ( macro ) ;
counter + + ;
}
}
else
{
float smallestDropHeight = std : : numeric_limits < float > : : max ( ) ;
int counter = 0 ;
for ( osg : : ref_ptr < TagBase > tag : selection )
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( tag . get ( ) ) )
{
float objectHeight = dropObjectDataHandler . mObjectHeights [ counter ] ;
float thisDrop = calculateDropHeight ( dropMode , objectTag - > mObject , objectHeight ) ;
if ( thisDrop < smallestDropHeight )
smallestDropHeight = thisDrop ;
counter + + ;
}
for ( osg : : ref_ptr < TagBase > tag : selection )
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( tag . get ( ) ) )
{
dropInstance ( objectTag - > mObject , smallestDropHeight ) ;
objectTag - > mObject - > apply ( macro ) ;
}
2020-03-18 09:16:21 +00:00
}
}
2021-01-28 21:10:33 +00:00
CSVRender : : DropObjectHeightHandler : : DropObjectHeightHandler ( WorldspaceWidget * worldspacewidget )
2020-03-18 09:16:21 +00:00
: mWorldspaceWidget ( worldspacewidget )
{
2020-04-20 16:47:14 +00:00
std : : vector < osg : : ref_ptr < TagBase > > selection = mWorldspaceWidget - > getSelection ( Mask_Reference ) ;
2020-02-29 12:56:11 +00:00
for ( osg : : ref_ptr < TagBase > tag : selection )
2020-02-28 11:20:57 +00:00
{
2020-02-29 12:56:11 +00:00
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( tag . get ( ) ) )
{
2020-03-03 19:18:09 +00:00
osg : : ref_ptr < osg : : Group > objectNodeWithGUI = objectTag - > mObject - > getRootNode ( ) ;
osg : : ref_ptr < osg : : Group > objectNodeWithoutGUI = objectTag - > mObject - > getBaseNode ( ) ;
osg : : ComputeBoundsVisitor computeBounds ;
2020-04-20 16:47:14 +00:00
computeBounds . setTraversalMask ( Mask_Reference ) ;
2020-03-03 19:18:09 +00:00
objectNodeWithoutGUI - > accept ( computeBounds ) ;
osg : : BoundingBox bounds = computeBounds . getBoundingBox ( ) ;
float boundingBoxOffset = 0.0f ;
2020-03-19 09:18:54 +00:00
if ( bounds . valid ( ) )
boundingBoxOffset = bounds . zMin ( ) ;
2020-03-03 19:18:09 +00:00
2020-03-18 09:16:21 +00:00
mObjectHeights . emplace_back ( boundingBoxOffset ) ;
mOldMasks . emplace_back ( objectNodeWithGUI - > getNodeMask ( ) ) ;
2020-03-03 19:18:09 +00:00
2020-04-20 16:47:14 +00:00
objectNodeWithGUI - > setNodeMask ( 0 ) ;
2020-02-29 12:56:11 +00:00
}
}
2020-03-18 09:16:21 +00:00
}
2020-02-29 12:56:11 +00:00
2021-01-28 21:10:33 +00:00
CSVRender : : DropObjectHeightHandler : : ~ DropObjectHeightHandler ( )
2020-03-18 09:16:21 +00:00
{
2020-04-20 16:47:14 +00:00
std : : vector < osg : : ref_ptr < TagBase > > selection = mWorldspaceWidget - > getSelection ( Mask_Reference ) ;
2020-02-29 12:56:11 +00:00
int counter = 0 ;
for ( osg : : ref_ptr < TagBase > tag : selection )
{
if ( CSVRender : : ObjectTag * objectTag = dynamic_cast < CSVRender : : ObjectTag * > ( tag . get ( ) ) )
{
2020-03-03 19:18:09 +00:00
osg : : ref_ptr < osg : : Group > objectNodeWithGUI = objectTag - > mObject - > getRootNode ( ) ;
2020-03-18 09:16:21 +00:00
objectNodeWithGUI - > setNodeMask ( mOldMasks [ counter ] ) ;
2020-02-29 12:56:11 +00:00
counter + + ;
}
2020-02-28 11:20:57 +00:00
}
2020-02-27 09:54:11 +00:00
}