* ctrl + r: clone stuff and repeat recent transforms; clipper tool toggle resets transforms stack

This commit is contained in:
Garux 2019-01-18 15:00:06 +03:00
parent 7bcb57562f
commit 74a3da969c
3 changed files with 153 additions and 25 deletions

View File

@ -127,6 +127,7 @@ virtual void NudgeManipulator( const Vector3& nudge, const Vector3& view ) = 0;
virtual void translateSelected( const Vector3& translation ) = 0;
virtual void rotateSelected( const Quaternion& rotation, 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 setCustomTransformOrigin( const Vector3& origin, const bool set[3] ) const = 0;

View File

@ -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(){
UndoableCommand undo( "nudgeSelectedUp" );
@ -2231,6 +2239,7 @@ GtkMenuItem* create_selection_menu(){
menu_separator( menu );
create_menu_item_with_mnemonic( menu, "Arbitrary rotation...", "ArbitraryRotation" );
create_menu_item_with_mnemonic( menu, "Arbitrary scale...", "ArbitraryScale" );
create_menu_item_with_mnemonic( menu, "Repeat Transforms", "RepeatTransforms" );
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( "DeleteSelection2", FreeCaller<deleteSelection>(), Accelerator( GDK_BackSpace ) );
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( "UnSelectSelection2", FreeCaller<Selection_Deselect>(), Accelerator( GDK_Escape ) );
GlobalCommands_insert( "UnSelectSelection", FreeCaller<Selection_Deselect>(), Accelerator( 'C' ) );

View File

@ -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
{
@ -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
{
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
{
SelectionIntersection m_bestIntersection;
@ -3903,7 +3997,6 @@ TranslateFree m_freeResize;
TranslateAxis2 m_axisResize;
TranslateFreeXY_Z m_freeDragXY_Z;
ResizeTranslatable m_resize;
DragTranslatable m_drag;
DragNewBrush m_dragNewBrush;
bool m_dragSelected; //drag selected primitives or components
bool m_selected; //components selected temporally for drag
@ -3912,7 +4005,7 @@ bool m_newBrush;
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(){
@ -4660,6 +4753,7 @@ RadiantSelectionSystem() :
m_rotate_manipulator( *this, 8, 64 ),
m_scale_manipulator( *this, 0, 64 ),
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_transformOrigin_manipulator( *this, m_pivotIsCustom ),
m_pivotChanged( false ),
@ -4716,7 +4810,7 @@ void SetManipulatorMode( EManipulatorMode mode ){
case eScale: m_manipulator = &m_scale_manipulator; break;
case eSkew: m_manipulator = &m_skew_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:
{
m_build_manipulator.initialise();
@ -5156,6 +5250,7 @@ void translate( const Vector3& translation ){
//ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
m_translation = translation;
m_repeatableTransforms.m_translation = translation;
m_pivot2world = m_pivot2world_start;
matrix4_translate_by_vec3( m_pivot2world, translation );
@ -5179,6 +5274,9 @@ void rotate( const Quaternion& rotation ){
//ASSERT_MESSAGE(!m_pivotChanged, "pivot is invalid");
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 ) {
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 ){
if ( !nothingSelected() ) {
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 ) {
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 ){
if ( !nothingSelected() ) {
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 ) {
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 ){
if( snapOrigin && !m_pivotIsCustom ){
m_pivot2world.tx() = float_snapped( m_pivot2world.tx(), GetSnapGridSize() );
m_pivot2world.ty() = float_snapped( m_pivot2world.ty(), GetSnapGridSize() );
m_pivot2world.tz() = float_snapped( m_pivot2world.tz(), GetSnapGridSize() );
}
if( snapOrigin && !m_pivotIsCustom )
vector3_snap( vector4_to_vector3( m_pivot2world.t() ), GetSnapGridSize() );
startMove();
rotate( rotation );
freezeTransforms();
@ -5258,16 +5359,32 @@ void translateSelected( const Vector3& translation ){
freezeTransforms();
}
void scaleSelected( const Vector3& scaling, bool snapOrigin = false ){
if( snapOrigin && !m_pivotIsCustom ){
m_pivot2world.tx() = float_snapped( m_pivot2world.tx(), GetSnapGridSize() );
m_pivot2world.ty() = float_snapped( m_pivot2world.ty(), GetSnapGridSize() );
m_pivot2world.tz() = float_snapped( m_pivot2world.tz(), GetSnapGridSize() );
}
if( snapOrigin && !m_pivotIsCustom )
vector3_snap( vector4_to_vector3( m_pivot2world.t() ), GetSnapGridSize() );
startMove();
scale( scaling );
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{
return ManipulatorMode() == eScale
|| ManipulatorMode() == eSkew