@@ -20,7 +20,6 @@ namespace TiltBrush
20
20
{
21
21
public class DuplicateSelectionCommand : BaseCommand
22
22
{
23
- // This command stores a copy of the selection and a copy of the duplicate.
24
23
private List < Stroke > m_SelectedStrokes ;
25
24
private List < GrabWidget > m_SelectedWidgets ;
26
25
@@ -33,51 +32,168 @@ public class DuplicateSelectionCommand : BaseCommand
33
32
private CanvasScript m_CurrentCanvas ;
34
33
35
34
private bool m_DupeInPlace ;
35
+ private bool m_NoSymmetrySpecialCase ;
36
36
37
37
public DuplicateSelectionCommand ( TrTransform xf , BaseCommand parent = null ) : base ( parent )
38
38
{
39
- // Save selected and duplicated strokes.
40
- m_SelectedStrokes = SelectionManager . m_Instance . SelectedStrokes . ToList ( ) ;
41
- m_DuplicatedStrokes = m_SelectedStrokes
42
- . Select ( stroke => SketchMemoryScript . m_Instance . DuplicateStroke (
43
- stroke , App . Scene . SelectionCanvas , null ) )
44
- . ToList ( ) ;
39
+ m_CurrentCanvas = App . ActiveCanvas ;
40
+ m_OriginTransform = SelectionManager . m_Instance . SelectionTransform ;
41
+ m_DuplicateTransform = xf ;
42
+ m_DupeInPlace = m_OriginTransform == m_DuplicateTransform ;
45
43
44
+ // Gather duplicate transforms based on current symmetry mode.
45
+ // Use Unity transforms and Matrix4x4 because we are going
46
+ // to be dealing with non-uniform scale.
47
+ List < TrTransform > xfSymmetriesGS = null ;
48
+ bool duplicateWidgetsAsTwoSided = false ;
49
+ switch ( PointerManager . m_Instance . CurrentSymmetryMode )
50
+ {
51
+ case PointerManager . SymmetryMode . SinglePlane :
52
+ duplicateWidgetsAsTwoSided = true ;
53
+ xfSymmetriesGS = new List < TrTransform >
54
+ {
55
+ TrTransform . identity ,
56
+ PointerManager . m_Instance . SymmetryWidget . ReflectionPlane . ToTrTransform ( )
57
+ } ;
58
+ break ;
59
+ case PointerManager . SymmetryMode . MultiMirror :
60
+ duplicateWidgetsAsTwoSided = true ;
61
+ xfSymmetriesGS = new List < TrTransform > ( ) ;
62
+
63
+ var xfCenter = TrTransform . FromTransform (
64
+ PointerManager . m_Instance . m_SymmetryLockedToController
65
+ ? PointerManager . m_Instance . MainPointer . transform
66
+ : PointerManager . m_Instance . SymmetryWidget . GrabTransform_GS
67
+ ) ;
68
+
69
+ var appScale = TrTransform . S ( App . Scene . Pose . scale ) ;
70
+ var pre = xfCenter * appScale ;
71
+ foreach ( var m in PointerManager . m_Instance . CustomMirrorMatrices )
72
+ {
73
+ var tr = TrTransform . FromMatrix4x4 ( m ) ;
74
+ xfSymmetriesGS . Add ( pre * tr * pre . inverse ) ;
75
+ }
76
+ break ;
77
+ case PointerManager . SymmetryMode . ScriptedSymmetryMode :
78
+ duplicateWidgetsAsTwoSided = true ;
79
+ xfSymmetriesGS = PointerManager . m_Instance . GetScriptedTransforms ( update : true ) ;
80
+ break ;
81
+ // case PointerManager.SymmetryMode.CustomSymmetryMode:
82
+ // break;
83
+ default :
84
+ break ;
85
+ }
86
+ // Save selected strokes.
87
+ m_SelectedStrokes = SelectionManager . m_Instance . SelectedStrokes . ToList ( ) ;
46
88
// Save selected widgets.
47
89
m_SelectedWidgets = SelectionManager . m_Instance . SelectedWidgets . ToList ( ) ;
48
- // Save duplicated widgets
90
+
91
+ m_DuplicatedStrokes = new List < Stroke > ( ) ;
49
92
m_DuplicatedWidgets = new List < GrabWidget > ( ) ;
50
- foreach ( var widget in m_SelectedWidgets )
93
+ if ( xfSymmetriesGS == null )
51
94
{
52
- var duplicatedWidget = widget . Clone ( ) ;
53
- m_DuplicatedWidgets . Add ( duplicatedWidget ) ;
95
+ // Special case for non-symmetry to match legacy code. Duplicate
96
+ // selection into selection canvas, deselect the old selection,
97
+ // and change the selection transform to apply the transform
98
+ // parameter. Is this necessary...? Probably better safe than
99
+ // sorry.
100
+ m_NoSymmetrySpecialCase = true ;
101
+
102
+ // Duplicate strokes.
103
+ foreach ( var stroke in m_SelectedStrokes )
104
+ {
105
+ m_DuplicatedStrokes . Add (
106
+ SketchMemoryScript . m_Instance . DuplicateStroke (
107
+ stroke , App . Scene . SelectionCanvas , null ) ) ;
108
+ }
109
+
110
+ // Duplicate widgets.
111
+ foreach ( var widget in m_SelectedWidgets )
112
+ {
113
+ m_DuplicatedWidgets . Add ( widget . Clone ( ) ) ;
114
+ }
54
115
}
116
+ else
117
+ {
118
+ // The new way, which works with arbitrary mirror matrices.
119
+ // Leave selection untouched and apply all transforms at
120
+ // creation time.
121
+ if ( ! m_DupeInPlace )
122
+ {
123
+ // Apply transform parameter.
124
+ var xfDelta = m_DuplicateTransform * m_OriginTransform . inverse ;
125
+ var appScale = TrTransform . S ( App . Scene . Pose . scale ) ;
126
+ var xfDeltaScaleAdj = appScale * xfDelta ;
127
+ xfDeltaScaleAdj . scale = xfDelta . scale ;
128
+ for ( int i = 0 ; i < xfSymmetriesGS . Count ; i ++ )
129
+ {
130
+ xfSymmetriesGS [ i ] = xfSymmetriesGS [ i ] * xfDeltaScaleAdj ;
131
+ }
132
+ }
55
133
56
- m_CurrentCanvas = App . ActiveCanvas ;
134
+ // Pre-calculate left transforms for canvas space.
135
+ var xfSymmetriesCS = new List < TrTransform > ( xfSymmetriesGS ) ;
136
+ var xfGSfromCS = App . Scene . SelectionCanvas . Pose ;
137
+ var xfCSfromGS = m_CurrentCanvas . Pose . inverse ;
138
+ for ( int i = 0 ; i < xfSymmetriesGS . Count ; i ++ )
139
+ {
140
+ xfSymmetriesCS [ i ] = xfCSfromGS * xfSymmetriesGS [ i ] * xfGSfromCS ;
141
+ }
57
142
58
- GroupManager . MoveStrokesToNewGroups ( m_DuplicatedStrokes , null ) ;
143
+ // Duplicate strokes.
144
+ foreach ( var stroke in m_SelectedStrokes )
145
+ {
146
+ for ( int i = 0 ; i < xfSymmetriesCS . Count ; i ++ )
147
+ {
148
+ m_DuplicatedStrokes . Add (
149
+ SketchMemoryScript . m_Instance . DuplicateStroke (
150
+ stroke , m_CurrentCanvas , xfSymmetriesCS [ i ] , absoluteScale : true ) ) ;
151
+ }
152
+ }
59
153
60
- m_OriginTransform = SelectionManager . m_Instance . SelectionTransform ;
61
- m_DuplicateTransform = xf ;
62
- m_DupeInPlace = m_OriginTransform == m_DuplicateTransform ;
154
+ // Duplicate widgets.
155
+ foreach ( var widget in m_SelectedWidgets )
156
+ {
157
+ // Generally speaking we want both sides of 2d media to appear
158
+ // when duplicating using multi-mirror.
159
+ bool duplicateAsTwoSided = widget is Media2dWidget
160
+ && duplicateWidgetsAsTwoSided ;
161
+
162
+ for ( int i = 0 ; i < xfSymmetriesGS . Count ; i ++ )
163
+ {
164
+ var duplicatedWidget = widget . Clone ( ) ;
165
+ var widgetXf = Coords . AsGlobal [ duplicatedWidget . GrabTransform_GS ] ;
166
+ widgetXf . scale = duplicatedWidget . GetSignedWidgetSize ( ) ;
167
+
168
+ if ( duplicateAsTwoSided )
169
+ {
170
+ ( ( Media2dWidget ) duplicatedWidget ) . TwoSided = true ;
171
+ }
172
+
173
+ var mat = xfSymmetriesGS [ i ] * widgetXf ;
174
+ duplicatedWidget . GrabTransform_GS . SetPositionAndRotation (
175
+ position : mat . translation ,
176
+ rotation : mat . rotation ) ;
177
+ duplicatedWidget . SetSignedWidgetSize ( mat . scale ) ;
178
+
179
+ m_DuplicatedWidgets . Add ( duplicatedWidget ) ;
180
+ }
181
+ }
182
+
183
+ if ( m_DuplicatedWidgets . Count > 0 )
184
+ {
185
+ SelectionManager . m_Instance . RegisterWidgetsInSelectionCanvas ( m_DuplicatedWidgets ) ;
186
+ SelectionManager . m_Instance . DeselectWidgets ( m_DuplicatedWidgets , m_CurrentCanvas ) ;
187
+ }
188
+ }
189
+
190
+ GroupManager . MoveStrokesToNewGroups ( m_DuplicatedStrokes , null ) ;
63
191
}
64
192
65
193
public override bool NeedsSave { get { return true ; } }
66
194
67
195
protected override void OnRedo ( )
68
196
{
69
- // Deselect selected strokes to current canvas.
70
- if ( m_SelectedStrokes != null )
71
- {
72
- SelectionManager . m_Instance . DeselectStrokes ( m_SelectedStrokes , m_CurrentCanvas ) ;
73
- }
74
-
75
- // Deselect selected widgets.
76
- if ( m_SelectedWidgets != null )
77
- {
78
- SelectionManager . m_Instance . DeselectWidgets ( m_SelectedWidgets , m_CurrentCanvas ) ;
79
- }
80
-
81
197
// Place duplicated strokes.
82
198
foreach ( var stroke in m_DuplicatedStrokes )
83
199
{
@@ -103,18 +219,32 @@ protected override void OnRedo()
103
219
}
104
220
TiltMeterScript . m_Instance . AdjustMeter ( stroke , up : true ) ;
105
221
}
106
- SelectionManager . m_Instance . RegisterStrokesInSelectionCanvas ( m_DuplicatedStrokes ) ;
107
222
108
223
// Place duplicated widgets.
109
224
for ( int i = 0 ; i < m_DuplicatedWidgets . Count ; ++ i )
110
225
{
111
226
m_DuplicatedWidgets [ i ] . RestoreFromToss ( ) ;
112
227
}
113
- SelectionManager . m_Instance . RegisterWidgetsInSelectionCanvas ( m_DuplicatedWidgets ) ;
114
228
115
- // Set selection widget transforms.
116
- SelectionManager . m_Instance . SelectionTransform = m_DuplicateTransform ;
117
- SelectionManager . m_Instance . UpdateSelectionWidget ( ) ;
229
+ if ( m_NoSymmetrySpecialCase )
230
+ {
231
+ if ( m_SelectedStrokes != null )
232
+ {
233
+ SelectionManager . m_Instance . DeselectStrokes ( m_SelectedStrokes , m_CurrentCanvas ) ;
234
+ }
235
+
236
+ if ( m_SelectedWidgets != null )
237
+ {
238
+ SelectionManager . m_Instance . DeselectWidgets ( m_SelectedWidgets , m_CurrentCanvas ) ;
239
+ }
240
+
241
+ SelectionManager . m_Instance . RegisterStrokesInSelectionCanvas ( m_DuplicatedStrokes ) ;
242
+ SelectionManager . m_Instance . RegisterWidgetsInSelectionCanvas ( m_DuplicatedWidgets ) ;
243
+
244
+ // Set selection widget transforms.
245
+ SelectionManager . m_Instance . SelectionTransform = m_DuplicateTransform ;
246
+ SelectionManager . m_Instance . UpdateSelectionWidget ( ) ;
247
+ }
118
248
}
119
249
120
250
protected override void OnUndo ( )
@@ -144,29 +274,33 @@ protected override void OnUndo()
144
274
}
145
275
TiltMeterScript . m_Instance . AdjustMeter ( stroke , up : false ) ;
146
276
}
147
- SelectionManager . m_Instance . DeregisterStrokesInSelectionCanvas ( m_DuplicatedStrokes ) ;
148
277
149
278
// Remove duplicated widgets.
150
279
for ( int i = 0 ; i < m_DuplicatedWidgets . Count ; ++ i )
151
280
{
152
281
m_DuplicatedWidgets [ i ] . Hide ( ) ;
153
282
}
154
- SelectionManager . m_Instance . DeregisterWidgetsInSelectionCanvas ( m_DuplicatedWidgets ) ;
155
-
156
- // Reset the selection transform before we select strokes.
157
- SelectionManager . m_Instance . SelectionTransform = m_OriginTransform ;
158
283
159
- // Select strokes.
160
- if ( m_SelectedStrokes != null )
161
- {
162
- SelectionManager . m_Instance . SelectStrokes ( m_SelectedStrokes ) ;
163
- }
164
- if ( m_SelectedWidgets != null )
284
+ if ( m_NoSymmetrySpecialCase )
165
285
{
166
- SelectionManager . m_Instance . SelectWidgets ( m_SelectedWidgets ) ;
167
- }
286
+ SelectionManager . m_Instance . DeregisterStrokesInSelectionCanvas ( m_DuplicatedStrokes ) ;
287
+ SelectionManager . m_Instance . DeregisterWidgetsInSelectionCanvas ( m_DuplicatedWidgets ) ;
288
+
289
+ // Reset the selection transform before we select strokes.
290
+ SelectionManager . m_Instance . SelectionTransform = m_OriginTransform ;
291
+
292
+ // Select strokes.
293
+ if ( m_SelectedStrokes != null )
294
+ {
295
+ SelectionManager . m_Instance . SelectStrokes ( m_SelectedStrokes ) ;
296
+ }
297
+ if ( m_SelectedWidgets != null )
298
+ {
299
+ SelectionManager . m_Instance . SelectWidgets ( m_SelectedWidgets ) ;
300
+ }
168
301
169
- SelectionManager . m_Instance . UpdateSelectionWidget ( ) ;
302
+ SelectionManager . m_Instance . UpdateSelectionWidget ( ) ;
303
+ }
170
304
}
171
305
172
306
public override bool Merge ( BaseCommand other )
0 commit comments