* ctrl + r: clone stuff and repeat recent transforms; clipper tool toggle resets transforms stack
This commit is contained in:
parent
7bcb57562f
commit
74a3da969c
|
|
@ -127,6 +127,7 @@ virtual void NudgeManipulator( const Vector3& nudge, const Vector3& view ) = 0;
|
||||||
virtual void translateSelected( const Vector3& translation ) = 0;
|
virtual void translateSelected( const Vector3& translation ) = 0;
|
||||||
virtual void rotateSelected( const Quaternion& rotation, bool snapOrigin = false ) = 0;
|
virtual void rotateSelected( const Quaternion& rotation, bool snapOrigin = false ) = 0;
|
||||||
virtual void scaleSelected( const Vector3& scaling, bool snapOrigin = false ) = 0;
|
virtual void scaleSelected( const Vector3& scaling, bool snapOrigin = false ) = 0;
|
||||||
|
virtual void repeatTransforms( const Callback& clone ) = 0;
|
||||||
|
|
||||||
virtual void pivotChanged() const = 0;
|
virtual void pivotChanged() const = 0;
|
||||||
virtual void setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const = 0;
|
virtual void setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const = 0;
|
||||||
|
|
|
||||||
|
|
@ -1383,6 +1383,14 @@ void Selection_Deselect(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scene_Clone_Selected(){
|
||||||
|
Scene_Clone_Selected( GlobalSceneGraph(), false );
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepeatTransforms(){
|
||||||
|
GlobalSelectionSystem().repeatTransforms( FreeCaller<Scene_Clone_Selected>() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Selection_NudgeUp(){
|
void Selection_NudgeUp(){
|
||||||
UndoableCommand undo( "nudgeSelectedUp" );
|
UndoableCommand undo( "nudgeSelectedUp" );
|
||||||
|
|
@ -2231,6 +2239,7 @@ GtkMenuItem* create_selection_menu(){
|
||||||
menu_separator( menu );
|
menu_separator( menu );
|
||||||
create_menu_item_with_mnemonic( menu, "Arbitrary rotation...", "ArbitraryRotation" );
|
create_menu_item_with_mnemonic( menu, "Arbitrary rotation...", "ArbitraryRotation" );
|
||||||
create_menu_item_with_mnemonic( menu, "Arbitrary scale...", "ArbitraryScale" );
|
create_menu_item_with_mnemonic( menu, "Arbitrary scale...", "ArbitraryScale" );
|
||||||
|
create_menu_item_with_mnemonic( menu, "Repeat Transforms", "RepeatTransforms" );
|
||||||
|
|
||||||
return selection_menu_item;
|
return selection_menu_item;
|
||||||
}
|
}
|
||||||
|
|
@ -3531,6 +3540,7 @@ void MainFrame_Construct(){
|
||||||
GlobalCommands_insert( "CloneSelectionAndMakeUnique", FreeCaller<Selection_Clone_MakeUnique>(), Accelerator( GDK_space, (GdkModifierType)GDK_SHIFT_MASK ) );
|
GlobalCommands_insert( "CloneSelectionAndMakeUnique", FreeCaller<Selection_Clone_MakeUnique>(), Accelerator( GDK_space, (GdkModifierType)GDK_SHIFT_MASK ) );
|
||||||
GlobalCommands_insert( "DeleteSelection2", FreeCaller<deleteSelection>(), Accelerator( GDK_BackSpace ) );
|
GlobalCommands_insert( "DeleteSelection2", FreeCaller<deleteSelection>(), Accelerator( GDK_BackSpace ) );
|
||||||
GlobalCommands_insert( "DeleteSelection", FreeCaller<deleteSelection>(), Accelerator( 'Z' ) );
|
GlobalCommands_insert( "DeleteSelection", FreeCaller<deleteSelection>(), Accelerator( 'Z' ) );
|
||||||
|
GlobalCommands_insert( "RepeatTransforms", FreeCaller<RepeatTransforms>(), Accelerator( 'R', (GdkModifierType)GDK_CONTROL_MASK ) );
|
||||||
// GlobalCommands_insert( "ParentSelection", FreeCaller<Scene_parentSelected>() );
|
// GlobalCommands_insert( "ParentSelection", FreeCaller<Scene_parentSelected>() );
|
||||||
GlobalCommands_insert( "UnSelectSelection2", FreeCaller<Selection_Deselect>(), Accelerator( GDK_Escape ) );
|
GlobalCommands_insert( "UnSelectSelection2", FreeCaller<Selection_Deselect>(), Accelerator( GDK_Escape ) );
|
||||||
GlobalCommands_insert( "UnSelectSelection", FreeCaller<Selection_Deselect>(), Accelerator( 'C' ) );
|
GlobalCommands_insert( "UnSelectSelection", FreeCaller<Selection_Deselect>(), Accelerator( 'C' ) );
|
||||||
|
|
|
||||||
|
|
@ -2852,18 +2852,6 @@ void translate( const Vector3& translation ){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DragTranslatable : public Translatable
|
|
||||||
{
|
|
||||||
void translate( const Vector3& translation ){
|
|
||||||
if ( GlobalSelectionSystem().Mode() == SelectionSystem::eComponent ) {
|
|
||||||
Scene_Translate_Component_Selected( GlobalSceneGraph(), translation );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Scene_Translate_Selected( GlobalSceneGraph(), translation );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SelectionVolume : public SelectionTest
|
class SelectionVolume : public SelectionTest
|
||||||
{
|
{
|
||||||
|
|
@ -3468,6 +3456,87 @@ void Scene_Skew_Selected( scene::Graph& graph, const Skew& skew, const Vector3&
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RepeatableTransforms
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Translation m_translation;
|
||||||
|
Rotation m_rotation;
|
||||||
|
Scale m_scale;
|
||||||
|
Skew m_skew;
|
||||||
|
/* next aren't used; TODO: think if unique origin per transform is needed, and how to implement this correctly for entities, having transform keys */
|
||||||
|
Vector3 m_rotationOrigin;
|
||||||
|
Vector3 m_scaleOrigin;
|
||||||
|
Vector3 m_skewOrigin;
|
||||||
|
|
||||||
|
bool m_rotationOriginSet;
|
||||||
|
bool m_scaleOriginSet;
|
||||||
|
bool m_skewOriginSet;
|
||||||
|
|
||||||
|
RepeatableTransforms(){
|
||||||
|
setIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIdentity() const {
|
||||||
|
return m_translation == c_translation_identity
|
||||||
|
&& m_rotation == c_rotation_identity
|
||||||
|
&& m_scale == c_scale_identity
|
||||||
|
&& m_skew == c_skew_identity;
|
||||||
|
}
|
||||||
|
void setIdentity(){
|
||||||
|
m_translation = c_translation_identity;
|
||||||
|
m_rotation = c_quaternion_identity;
|
||||||
|
m_scale = c_scale_identity;
|
||||||
|
m_skew = c_skew_identity;
|
||||||
|
|
||||||
|
m_rotationOrigin =
|
||||||
|
m_scaleOrigin =
|
||||||
|
m_skewOrigin = g_vector3_identity;
|
||||||
|
|
||||||
|
m_rotationOriginSet =
|
||||||
|
m_scaleOriginSet =
|
||||||
|
m_skewOriginSet = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class transform_selected : public SelectionSystem::Visitor
|
||||||
|
{
|
||||||
|
const RepeatableTransforms& m_transforms;
|
||||||
|
const Vector3& m_world_pivot;
|
||||||
|
public:
|
||||||
|
transform_selected( const RepeatableTransforms& transforms, const Vector3& world_pivot )
|
||||||
|
: m_transforms( transforms ), m_world_pivot( world_pivot ){
|
||||||
|
}
|
||||||
|
void visit( scene::Instance& instance ) const {
|
||||||
|
TransformNode* transformNode = Node_getTransformNode( instance.path().top() );
|
||||||
|
if ( transformNode != 0 ) {
|
||||||
|
Transformable* transform = Instance_getTransformable( instance );
|
||||||
|
if ( transform != 0 ) {
|
||||||
|
transform->setType( TRANSFORM_PRIMITIVE );
|
||||||
|
transform->setRotation( m_transforms.m_rotation );
|
||||||
|
transform->setScale( m_transforms.m_scale );
|
||||||
|
transform->setSkew( m_transforms.m_skew );
|
||||||
|
{
|
||||||
|
Editable* editable = Node_getEditable( instance.path().top() );
|
||||||
|
const Matrix4& localPivot = editable != 0 ? editable->getLocalPivot() : g_matrix4_identity;
|
||||||
|
|
||||||
|
const Matrix4 local_transform = matrix4_transform_for_components( c_translation_identity, m_transforms.m_rotation, m_transforms.m_scale, m_transforms.m_skew );
|
||||||
|
Vector3 parent_translation;
|
||||||
|
translation_for_pivoted_matrix_transform(
|
||||||
|
parent_translation,
|
||||||
|
local_transform,
|
||||||
|
m_world_pivot,
|
||||||
|
matrix4_multiplied_by_matrix4( matrix4_translation_for_vec3( matrix4_get_translation_vec3( instance.localToWorld() ) ), localPivot ),
|
||||||
|
matrix4_multiplied_by_matrix4( matrix4_translation_for_vec3( matrix4_get_translation_vec3( transformNode->localToParent() ) ), localPivot )
|
||||||
|
);
|
||||||
|
|
||||||
|
transform->setTranslation( parent_translation + m_transforms.m_translation );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class translate_component_selected : public SelectionSystem::Visitor
|
class translate_component_selected : public SelectionSystem::Visitor
|
||||||
{
|
{
|
||||||
const Vector3& m_translate;
|
const Vector3& m_translate;
|
||||||
|
|
@ -3572,6 +3641,31 @@ void Scene_Skew_Component_Selected( scene::Graph& graph, const Skew& skew, const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class transform_component_selected : public SelectionSystem::Visitor
|
||||||
|
{
|
||||||
|
const RepeatableTransforms& m_transforms;
|
||||||
|
const Vector3& m_world_pivot;
|
||||||
|
public:
|
||||||
|
transform_component_selected( const RepeatableTransforms& transforms, const Vector3& world_pivot )
|
||||||
|
: m_transforms( transforms ), m_world_pivot( world_pivot ){
|
||||||
|
}
|
||||||
|
void visit( scene::Instance& instance ) const {
|
||||||
|
Transformable* transform = Instance_getTransformable( instance );
|
||||||
|
if ( transform != 0 ) {
|
||||||
|
const Matrix4 local_transform = matrix4_transform_for_components( c_translation_identity, m_transforms.m_rotation, m_transforms.m_scale, m_transforms.m_skew );
|
||||||
|
Vector3 parent_translation;
|
||||||
|
translation_for_pivoted_matrix_transform( parent_translation, local_transform, m_world_pivot, instance.localToWorld(), Node_getTransformNode( instance.path().top() )->localToParent() );
|
||||||
|
|
||||||
|
transform->setType( TRANSFORM_COMPONENT );
|
||||||
|
transform->setRotation( m_transforms.m_rotation );
|
||||||
|
transform->setScale( m_transforms.m_scale );
|
||||||
|
transform->setSkew( m_transforms.m_skew );
|
||||||
|
transform->setTranslation( parent_translation + m_transforms.m_translation );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class BooleanSelector : public Selector
|
class BooleanSelector : public Selector
|
||||||
{
|
{
|
||||||
SelectionIntersection m_bestIntersection;
|
SelectionIntersection m_bestIntersection;
|
||||||
|
|
@ -3903,7 +3997,6 @@ TranslateFree m_freeResize;
|
||||||
TranslateAxis2 m_axisResize;
|
TranslateAxis2 m_axisResize;
|
||||||
TranslateFreeXY_Z m_freeDragXY_Z;
|
TranslateFreeXY_Z m_freeDragXY_Z;
|
||||||
ResizeTranslatable m_resize;
|
ResizeTranslatable m_resize;
|
||||||
DragTranslatable m_drag;
|
|
||||||
DragNewBrush m_dragNewBrush;
|
DragNewBrush m_dragNewBrush;
|
||||||
bool m_dragSelected; //drag selected primitives or components
|
bool m_dragSelected; //drag selected primitives or components
|
||||||
bool m_selected; //components selected temporally for drag
|
bool m_selected; //components selected temporally for drag
|
||||||
|
|
@ -3912,7 +4005,7 @@ bool m_newBrush;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DragManipulator() : m_freeResize( m_resize ), m_axisResize( m_resize ), m_freeDragXY_Z( m_drag ), m_dragSelected( false ), m_selected( false ), m_selected2( false ), m_newBrush( false ){
|
DragManipulator( Translatable& translatable ) : m_freeResize( m_resize ), m_axisResize( m_resize ), m_freeDragXY_Z( translatable ), m_dragSelected( false ), m_selected( false ), m_selected2( false ), m_newBrush( false ){
|
||||||
}
|
}
|
||||||
|
|
||||||
Manipulatable* GetManipulatable(){
|
Manipulatable* GetManipulatable(){
|
||||||
|
|
@ -4660,6 +4753,7 @@ RadiantSelectionSystem() :
|
||||||
m_rotate_manipulator( *this, 8, 64 ),
|
m_rotate_manipulator( *this, 8, 64 ),
|
||||||
m_scale_manipulator( *this, 0, 64 ),
|
m_scale_manipulator( *this, 0, 64 ),
|
||||||
m_skew_manipulator( *this, *this, *this, *this, m_bounds, m_pivot2world, m_pivotIsCustom ),
|
m_skew_manipulator( *this, *this, *this, *this, m_bounds, m_pivot2world, m_pivotIsCustom ),
|
||||||
|
m_drag_manipulator( *this ),
|
||||||
m_clip_manipulator( m_pivot2world, m_bounds ),
|
m_clip_manipulator( m_pivot2world, m_bounds ),
|
||||||
m_transformOrigin_manipulator( *this, m_pivotIsCustom ),
|
m_transformOrigin_manipulator( *this, m_pivotIsCustom ),
|
||||||
m_pivotChanged( false ),
|
m_pivotChanged( false ),
|
||||||
|
|
@ -4716,7 +4810,7 @@ void SetManipulatorMode( EManipulatorMode mode ){
|
||||||
case eScale: m_manipulator = &m_scale_manipulator; break;
|
case eScale: m_manipulator = &m_scale_manipulator; break;
|
||||||
case eSkew: m_manipulator = &m_skew_manipulator; break;
|
case eSkew: m_manipulator = &m_skew_manipulator; break;
|
||||||
case eDrag: m_manipulator = &m_drag_manipulator; break;
|
case eDrag: m_manipulator = &m_drag_manipulator; break;
|
||||||
case eClip: m_manipulator = &m_clip_manipulator; break;
|
case eClip: m_manipulator = &m_clip_manipulator; m_repeatableTransforms.setIdentity(); break;
|
||||||
case eBuild:
|
case eBuild:
|
||||||
{
|
{
|
||||||
m_build_manipulator.initialise();
|
m_build_manipulator.initialise();
|
||||||
|
|
@ -5156,6 +5250,7 @@ void translate( const Vector3& translation ){
|
||||||
//ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
|
//ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
|
||||||
|
|
||||||
m_translation = translation;
|
m_translation = translation;
|
||||||
|
m_repeatableTransforms.m_translation = translation;
|
||||||
|
|
||||||
m_pivot2world = m_pivot2world_start;
|
m_pivot2world = m_pivot2world_start;
|
||||||
matrix4_translate_by_vec3( m_pivot2world, translation );
|
matrix4_translate_by_vec3( m_pivot2world, translation );
|
||||||
|
|
@ -5179,6 +5274,9 @@ void rotate( const Quaternion& rotation ){
|
||||||
//ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
|
//ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
|
||||||
|
|
||||||
m_rotation = rotation;
|
m_rotation = rotation;
|
||||||
|
m_repeatableTransforms.m_rotation = rotation;
|
||||||
|
if( ( m_repeatableTransforms.m_rotationOriginSet = m_pivotIsCustom ) )
|
||||||
|
m_repeatableTransforms.m_rotationOrigin = vector4_to_vector3( m_pivot2world.t() );
|
||||||
|
|
||||||
if ( Mode() == eComponent ) {
|
if ( Mode() == eComponent ) {
|
||||||
Scene_Rotate_Component_Selected( GlobalSceneGraph(), m_rotation, vector4_to_vector3( m_pivot2world.t() ) );
|
Scene_Rotate_Component_Selected( GlobalSceneGraph(), m_rotation, vector4_to_vector3( m_pivot2world.t() ) );
|
||||||
|
|
@ -5204,6 +5302,9 @@ void outputRotation( TextOutputStream& ostream ){
|
||||||
void scale( const Vector3& scaling ){
|
void scale( const Vector3& scaling ){
|
||||||
if ( !nothingSelected() ) {
|
if ( !nothingSelected() ) {
|
||||||
m_scale = scaling;
|
m_scale = scaling;
|
||||||
|
m_repeatableTransforms.m_scale = scaling;
|
||||||
|
if( ( m_repeatableTransforms.m_scaleOriginSet = m_pivotIsCustom ) )
|
||||||
|
m_repeatableTransforms.m_scaleOrigin = vector4_to_vector3( m_pivot2world.t() );
|
||||||
|
|
||||||
if ( Mode() == eComponent ) {
|
if ( Mode() == eComponent ) {
|
||||||
Scene_Scale_Component_Selected( GlobalSceneGraph(), m_scale, vector4_to_vector3( m_pivot2world.t() ) );
|
Scene_Scale_Component_Selected( GlobalSceneGraph(), m_scale, vector4_to_vector3( m_pivot2world.t() ) );
|
||||||
|
|
@ -5229,6 +5330,9 @@ void outputScale( TextOutputStream& ostream ){
|
||||||
void skew( const Skew& skew ){
|
void skew( const Skew& skew ){
|
||||||
if ( !nothingSelected() ) {
|
if ( !nothingSelected() ) {
|
||||||
m_skew = skew;
|
m_skew = skew;
|
||||||
|
m_repeatableTransforms.m_skew = skew;
|
||||||
|
if( ( m_repeatableTransforms.m_skewOriginSet = m_pivotIsCustom ) )
|
||||||
|
m_repeatableTransforms.m_skewOrigin = vector4_to_vector3( m_pivot2world.t() );
|
||||||
|
|
||||||
if ( Mode() == eComponent ) {
|
if ( Mode() == eComponent ) {
|
||||||
Scene_Skew_Component_Selected( GlobalSceneGraph(), m_skew, vector4_to_vector3( m_pivot2world.t() ) );
|
Scene_Skew_Component_Selected( GlobalSceneGraph(), m_skew, vector4_to_vector3( m_pivot2world.t() ) );
|
||||||
|
|
@ -5243,11 +5347,8 @@ void skew( const Skew& skew ){
|
||||||
}
|
}
|
||||||
|
|
||||||
void rotateSelected( const Quaternion& rotation, bool snapOrigin = false ){
|
void rotateSelected( const Quaternion& rotation, bool snapOrigin = false ){
|
||||||
if( snapOrigin && !m_pivotIsCustom ){
|
if( snapOrigin && !m_pivotIsCustom )
|
||||||
m_pivot2world.tx() = float_snapped( m_pivot2world.tx(), GetSnapGridSize() );
|
vector3_snap( vector4_to_vector3( m_pivot2world.t() ), GetSnapGridSize() );
|
||||||
m_pivot2world.ty() = float_snapped( m_pivot2world.ty(), GetSnapGridSize() );
|
|
||||||
m_pivot2world.tz() = float_snapped( m_pivot2world.tz(), GetSnapGridSize() );
|
|
||||||
}
|
|
||||||
startMove();
|
startMove();
|
||||||
rotate( rotation );
|
rotate( rotation );
|
||||||
freezeTransforms();
|
freezeTransforms();
|
||||||
|
|
@ -5258,16 +5359,32 @@ void translateSelected( const Vector3& translation ){
|
||||||
freezeTransforms();
|
freezeTransforms();
|
||||||
}
|
}
|
||||||
void scaleSelected( const Vector3& scaling, bool snapOrigin = false ){
|
void scaleSelected( const Vector3& scaling, bool snapOrigin = false ){
|
||||||
if( snapOrigin && !m_pivotIsCustom ){
|
if( snapOrigin && !m_pivotIsCustom )
|
||||||
m_pivot2world.tx() = float_snapped( m_pivot2world.tx(), GetSnapGridSize() );
|
vector3_snap( vector4_to_vector3( m_pivot2world.t() ), GetSnapGridSize() );
|
||||||
m_pivot2world.ty() = float_snapped( m_pivot2world.ty(), GetSnapGridSize() );
|
|
||||||
m_pivot2world.tz() = float_snapped( m_pivot2world.tz(), GetSnapGridSize() );
|
|
||||||
}
|
|
||||||
startMove();
|
startMove();
|
||||||
scale( scaling );
|
scale( scaling );
|
||||||
freezeTransforms();
|
freezeTransforms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RepeatableTransforms m_repeatableTransforms;
|
||||||
|
|
||||||
|
void repeatTransforms( const Callback& clone ){
|
||||||
|
if ( countSelected() != 0 && !m_repeatableTransforms.isIdentity() ) {
|
||||||
|
startMove();
|
||||||
|
UndoableCommand undo( "repeatTransforms" );
|
||||||
|
if( Mode() == ePrimitive )
|
||||||
|
clone();
|
||||||
|
if ( Mode() == eComponent ) {
|
||||||
|
GlobalSelectionSystem().foreachSelectedComponent( transform_component_selected( m_repeatableTransforms, vector4_to_vector3( m_pivot2world.t() ) ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GlobalSelectionSystem().foreachSelected( transform_selected( m_repeatableTransforms, vector4_to_vector3( m_pivot2world.t() ) ) );
|
||||||
|
}
|
||||||
|
freezeTransforms();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool transformOrigin_isTranslatable() const{
|
bool transformOrigin_isTranslatable() const{
|
||||||
return ManipulatorMode() == eScale
|
return ManipulatorMode() == eScale
|
||||||
|| ManipulatorMode() == eSkew
|
|| ManipulatorMode() == eSkew
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user