mirror of
https://github.com/fadden/6502bench.git
synced 2025-01-13 00:29:44 +00:00
Progress toward wireframe animations
Handle the remaining visualization editor UI controls, except for the "test" button. Save/restore wireframe animations in the project file. Changed the preview from a 1-pixel-wide line drawn by a path half the window size to a 2-pixel-wide line drawn by a path the exact window size.
This commit is contained in:
parent
7e92a86ffa
commit
b68e39ab6b
@ -1051,8 +1051,18 @@ namespace SourceGen {
|
||||
vis = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't store VisWireframeAnimations in a separate area. They're just like
|
||||
// static Visualizations but with an extra "is animated" parameter set. Check
|
||||
// for that here and create the correct type.
|
||||
if (parms.TryGetValue(VisWireframeAnimation.P_IS_ANIMATED, out object objVal) &&
|
||||
objVal is bool && (bool)objVal) {
|
||||
vis = new VisWireframeAnimation(serVis.Tag, serVis.VisGenIdent,
|
||||
new ReadOnlyDictionary<string, object>(parms), null, null);
|
||||
} else {
|
||||
vis = new Visualization(serVis.Tag, serVis.VisGenIdent,
|
||||
new ReadOnlyDictionary<string, object>(parms));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,26 @@
|
||||
},
|
||||
|
||||
"UserLabels":{
|
||||
},
|
||||
"10":{
|
||||
"Label":"vertices",
|
||||
"Value":4106,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"44":{
|
||||
"Label":"edges",
|
||||
"Value":4140,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"},
|
||||
|
||||
"101":{
|
||||
"Label":"faces",
|
||||
"Value":4197,
|
||||
"Source":"User",
|
||||
"Type":"GlobalAddr",
|
||||
"LabelAnno":"None"}},
|
||||
|
||||
"OperandFormats":{
|
||||
"10":{
|
||||
@ -248,8 +267,14 @@
|
||||
"_isPerspective":true,
|
||||
"_isBfcEnabled":true,
|
||||
"_eulerRotX":0,
|
||||
"_eulerRotY":34,
|
||||
"_eulerRotZ":65}},
|
||||
"_eulerRotY":21,
|
||||
"_eulerRotZ":65,
|
||||
"_isAnimatedWireframe":true,
|
||||
"_deltaRotX":-6,
|
||||
"_deltaRotY":30,
|
||||
"_deltaRotZ":0,
|
||||
"_frameCount":60,
|
||||
"_frameDelayMsec":100}},
|
||||
|
||||
{
|
||||
"Tag":"bmp_data",
|
||||
@ -269,7 +294,7 @@
|
||||
"Tag":"anim00002c",
|
||||
"VisGenIdent":"(animation)",
|
||||
"VisGenParams":{
|
||||
"_frame-delay-msec":500}}],
|
||||
"_frameDelayMsec":100}}],
|
||||
"VisualizationSets":{
|
||||
"10":{
|
||||
"Tags":["wf_data",
|
||||
|
@ -36,7 +36,7 @@ namespace SourceGen {
|
||||
/// <summary>
|
||||
/// Frame delay parameter.
|
||||
/// </summary>
|
||||
public const string P_FRAME_DELAY_MSEC_PARAM = "_frame-delay-msec";
|
||||
public const string P_FRAME_DELAY_MSEC_PARAM = "_frameDelayMsec";
|
||||
public const string P_FRAME_DELAY_MSEC_PARAM_OLD = "frame-delay-msec";
|
||||
|
||||
/// <summary>
|
||||
|
@ -32,25 +32,36 @@ namespace SourceGen {
|
||||
/// <summary>
|
||||
/// Frame delay parameter.
|
||||
/// </summary>
|
||||
public const string P_FRAME_DELAY_MSEC = "_frame-delay-msec";
|
||||
public const string P_FRAME_DELAY_MSEC = "_frameDelayMsec";
|
||||
|
||||
/// <summary>
|
||||
/// Frame count parameter.
|
||||
/// </summary>
|
||||
public const string P_FRAME_COUNT = "_frame-count";
|
||||
public const string P_FRAME_COUNT = "_frameCount";
|
||||
|
||||
public const string P_IS_ANIMATED = "_isAnimatedWireframe";
|
||||
|
||||
public const string P_EULER_ROT_X = "_eulerRotX";
|
||||
public const string P_EULER_ROT_Y = "_eulerRotY";
|
||||
public const string P_EULER_ROT_Z = "_eulerRotZ";
|
||||
|
||||
public const string P_DELTA_ROT_X = "_deltaRotX";
|
||||
public const string P_DELTA_ROT_Y = "_deltaRotY";
|
||||
public const string P_DELTA_ROT_Z = "_deltaRotZ";
|
||||
|
||||
private IVisualizationWireframe mVisWire;
|
||||
|
||||
public VisWireframeAnimation(string tag, string visGenIdent,
|
||||
ReadOnlyDictionary<string, object> visGenParams, Visualization oldObj,
|
||||
IVisualizationWireframe visWire)
|
||||
: base(tag, visGenIdent, visGenParams, oldObj) {
|
||||
Debug.Assert(visWire != null);
|
||||
// visWire may be null when loading from project file
|
||||
mVisWire = visWire;
|
||||
}
|
||||
|
||||
public override void SetThumbnail(IVisualizationWireframe visWire,
|
||||
ReadOnlyDictionary<string, object> parms) {
|
||||
base.SetThumbnail(visWire, parms);
|
||||
mVisWire = visWire;
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ namespace SourceGen {
|
||||
/// </summary>
|
||||
/// <param name="visWire">Visualization object.</param>
|
||||
/// <param name="parms">Visualization parameters.</param>
|
||||
public void SetThumbnail(IVisualizationWireframe visWire,
|
||||
public virtual void SetThumbnail(IVisualizationWireframe visWire,
|
||||
ReadOnlyDictionary<string, object> parms) {
|
||||
Debug.Assert(visWire != null);
|
||||
Debug.Assert(parms != null);
|
||||
|
@ -134,7 +134,8 @@ limitations under the License.
|
||||
|
||||
<Border Grid.Row="1" BorderThickness="1" HorizontalAlignment="Stretch"
|
||||
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}"
|
||||
Background="{StaticResource CheckerBackground}">
|
||||
Background="{StaticResource CheckerBackground}"
|
||||
SnapsToDevicePixels="True">
|
||||
<!-- explicit width gets cleared after initial window layout -->
|
||||
<Grid Name="previewGrid" Width="548" Height="400">
|
||||
<!-- either the image or the path is shown, not both; background is set to
|
||||
@ -144,7 +145,7 @@ limitations under the License.
|
||||
<!-- ClipToBounds="True" -->
|
||||
<!-- RenderOptions.EdgeMode="Aliased" -->
|
||||
<Viewbox>
|
||||
<Path Name="wireframePath" Stroke="White"/>
|
||||
<Path Name="wireframePath" Stroke="White" StrokeThickness="2"/>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
</Border>
|
||||
@ -192,24 +193,24 @@ limitations under the License.
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Rectangle Grid.Row="0" Grid.ColumnSpan="3" Margin="4" HorizontalAlignment="Stretch"
|
||||
<Rectangle Grid.Row="0" Grid.ColumnSpan="3" Margin="0,4,0,4" HorizontalAlignment="Stretch"
|
||||
Fill="LightGray" Height="2"/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" Text="Initial X rotation (deg):" Margin="0,5,0,0"/>
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" Text="X axis rotation (deg):" Margin="0,5,0,0"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="1" Margin="4,4,0,0" Width="30" MaxLength="3"
|
||||
Text="{Binding ElementName=initialXSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Slider Name="initialXSlider" Grid.Column="2" Grid.Row="1" Margin="4,4,0,0" Width="360"
|
||||
Minimum="0" Maximum="359" TickFrequency="1" IsSnapToTickEnabled="True"
|
||||
ValueChanged="InitialRotSlider_ValueChanged"/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="2" Text="Initial Y rotation (deg):" Margin="0,5,0,0"/>
|
||||
<TextBlock Grid.Column="0" Grid.Row="2" Text="Y axis rotation (deg):" Margin="0,5,0,0"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="2" Margin="4,4,0,0" Width="30" MaxLength="3"
|
||||
Text="{Binding ElementName=initialYSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Slider Name="initialYSlider" Grid.Column="2" Grid.Row="2" Margin="4,4,0,0" Width="360"
|
||||
Minimum="0" Maximum="359" TickFrequency="1" IsSnapToTickEnabled="True"
|
||||
ValueChanged="InitialRotSlider_ValueChanged"/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="3" Text="Initial Z rotation (deg):" Margin="0,5,0,0"/>
|
||||
<TextBlock Grid.Column="0" Grid.Row="3" Text="Z axis rotation (deg):" Margin="0,5,0,0"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="3" Margin="4,4,0,0" Width="30" MaxLength="3"
|
||||
Text="{Binding ElementName=initialZSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Slider Name="initialZSlider" Grid.Column="2" Grid.Row="3" Margin="4,4,0,0" Width="360"
|
||||
@ -222,24 +223,35 @@ limitations under the License.
|
||||
<!-- remaining items are enabled when "isAnimated" checkbox is checked -->
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="5" Grid.ColumnSpan="2" Margin="0,5,0,0"
|
||||
Text="Rotation per frame:"/>
|
||||
Text="Rotation per frame:"
|
||||
IsEnabled="{Binding ElementName=isAnimated, Path=IsChecked}"/>
|
||||
<StackPanel Grid.Column="1" Grid.Row="5" Grid.ColumnSpan="2" Orientation="Horizontal" Margin="4,4,0,0"
|
||||
IsEnabled="{Binding ElementName=isAnimated, Path=IsChecked}">
|
||||
<TextBlock Text="X:" Margin="0,1,0,0"/>
|
||||
<TextBox Width="40" MaxLength="4" Margin="4,0,0,0"/>
|
||||
<TextBox Width="40" MaxLength="4" Margin="4,0,0,0"
|
||||
Text="{Binding RotDeltaX}"/>
|
||||
<TextBlock Text="Y:" Margin="8,1,0,0"/>
|
||||
<TextBox Width="40" MaxLength="4" Margin="4,0,0,0"/>
|
||||
<TextBox Width="40" MaxLength="4" Margin="4,0,0,0"
|
||||
Text="{Binding RotDeltaY}"/>
|
||||
<TextBlock Text="Z:" Margin="8,1,0,0"/>
|
||||
<TextBox Width="40" MaxLength="4" Margin="4,0,0,0"/>
|
||||
<TextBox Width="40" MaxLength="4" Margin="4,0,0,0"
|
||||
Text="{Binding RotDeltaZ}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="6" Text="Frame count:" Margin="0,5,0,0"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="6" Width="50" Height="18" Margin="4,4,0,0"/>
|
||||
<TextBlock Grid.Column="0" Grid.Row="6" Text="Frame count:" Margin="0,5,0,0"
|
||||
IsEnabled="{Binding ElementName=isAnimated, Path=IsChecked}"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="6" Width="50" Height="18" Margin="4,4,0,0"
|
||||
Text="{Binding FrameCount}" MaxLength="4"
|
||||
IsEnabled="{Binding ElementName=isAnimated, Path=IsChecked}"/>
|
||||
<Button Grid.Column="2" Grid.Row="6" Width="70" Margin="4,4,0,0" HorizontalAlignment="Left"
|
||||
Content="Auto" />
|
||||
Content="Auto" Click="AutoFrameCountButton_Click"
|
||||
IsEnabled="{Binding ElementName=isAnimated, Path=IsChecked}"/>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="7" Text="Frame delay (msec):" Margin="0,5,0,0"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="7" Width="50" Margin="4,4,0,0"/>
|
||||
<TextBlock Grid.Column="0" Grid.Row="7" Text="Frame delay (msec):" Margin="0,5,0,0"
|
||||
IsEnabled="{Binding ElementName=isAnimated, Path=IsChecked}"/>
|
||||
<TextBox Grid.Column="1" Grid.Row="7" Width="50" Margin="4,4,0,0"
|
||||
Text="{Binding FrameDelayMsec}" MaxLength="5"
|
||||
IsEnabled="{Binding ElementName=isAnimated, Path=IsChecked}"/>
|
||||
</Grid>
|
||||
|
||||
<DockPanel Grid.Column="0" Grid.Row="5" Margin="0,8,0,0" LastChildFill="False">
|
||||
|
@ -81,18 +81,6 @@ namespace SourceGen.WpfGui {
|
||||
}
|
||||
private bool mIsValid;
|
||||
|
||||
public Visibility WireframeCtrlVisibility {
|
||||
get { return mWireframeCtrlVisibility; }
|
||||
set { mWireframeCtrlVisibility = value; OnPropertyChanged(); }
|
||||
}
|
||||
private Visibility mWireframeCtrlVisibility;
|
||||
|
||||
public bool IsWireframeAnimated {
|
||||
get { return mIsWireframeAnimated; }
|
||||
set { mIsWireframeAnimated = value; OnPropertyChanged(); }
|
||||
}
|
||||
private bool mIsWireframeAnimated;
|
||||
|
||||
/// <summary>
|
||||
/// Visualization tag.
|
||||
/// </summary>
|
||||
@ -166,6 +154,54 @@ namespace SourceGen.WpfGui {
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#region Wireframe Stuff
|
||||
|
||||
// Visibility of the wireframe-specific UI.
|
||||
public Visibility WireframeCtrlVisibility {
|
||||
get { return mWireframeCtrlVisibility; }
|
||||
set { mWireframeCtrlVisibility = value; OnPropertyChanged(); }
|
||||
}
|
||||
private Visibility mWireframeCtrlVisibility;
|
||||
|
||||
// "Animated" checkbox.
|
||||
public bool IsWireframeAnimated {
|
||||
get { return mIsWireframeAnimated; }
|
||||
set { mIsWireframeAnimated = value; OnPropertyChanged(); }
|
||||
}
|
||||
private bool mIsWireframeAnimated;
|
||||
|
||||
public int RotDeltaX {
|
||||
get { return mRotDeltaX; }
|
||||
set { mRotDeltaX = value; OnPropertyChanged(); }
|
||||
}
|
||||
private int mRotDeltaX;
|
||||
|
||||
public int RotDeltaY {
|
||||
get { return mRotDeltaY; }
|
||||
set { mRotDeltaY = value; OnPropertyChanged(); }
|
||||
}
|
||||
private int mRotDeltaY;
|
||||
|
||||
public int RotDeltaZ {
|
||||
get { return mRotDeltaZ; }
|
||||
set { mRotDeltaZ = value; OnPropertyChanged(); }
|
||||
}
|
||||
private int mRotDeltaZ;
|
||||
|
||||
public int FrameCount {
|
||||
get { return mFrameCount; }
|
||||
set { mFrameCount = value; OnPropertyChanged(); }
|
||||
}
|
||||
private int mFrameCount;
|
||||
|
||||
public int FrameDelayMsec {
|
||||
get { return mFrameDelayMsec; }
|
||||
set { mFrameDelayMsec = value; OnPropertyChanged(); }
|
||||
}
|
||||
private int mFrameDelayMsec;
|
||||
|
||||
#endregion Wireframe Stuff
|
||||
|
||||
private class ScriptSupport : MarshalByRefObject, PluginCommon.IApplication {
|
||||
private EditVisualization mOuter;
|
||||
|
||||
@ -390,6 +426,7 @@ namespace SourceGen.WpfGui {
|
||||
|
||||
WireframeCtrlVisibility = includeWire ? Visibility.Visible : Visibility.Collapsed;
|
||||
if (includeWire) {
|
||||
// Slider control limits values to [0,359].
|
||||
int rotX = (int)initialXSlider.Value;
|
||||
int rotY = (int)initialYSlider.Value;
|
||||
int rotZ = (int)initialZSlider.Value;
|
||||
@ -397,6 +434,22 @@ namespace SourceGen.WpfGui {
|
||||
valueDict.Add(VisWireframeAnimation.P_EULER_ROT_X, rotX);
|
||||
valueDict.Add(VisWireframeAnimation.P_EULER_ROT_Y, rotY);
|
||||
valueDict.Add(VisWireframeAnimation.P_EULER_ROT_Z, rotZ);
|
||||
|
||||
// Strictly speaking we don't need this, because we use a different object
|
||||
// type, but this ties into how the object is stored in the project file.
|
||||
valueDict.Add(VisWireframeAnimation.P_IS_ANIMATED, IsWireframeAnimated);
|
||||
|
||||
// These could be any integer value, but the UI limits them to 4 chars, and
|
||||
// it's all mod 360.
|
||||
valueDict.Add(VisWireframeAnimation.P_DELTA_ROT_X, RotDeltaX);
|
||||
valueDict.Add(VisWireframeAnimation.P_DELTA_ROT_Y, RotDeltaY);
|
||||
valueDict.Add(VisWireframeAnimation.P_DELTA_ROT_Z, RotDeltaZ);
|
||||
|
||||
// These aren't strictly checked by the UI, so range-check here.
|
||||
int fc = (FrameCount >= 1 && FrameCount <= 9999) ? FrameCount : 1;
|
||||
valueDict.Add(VisWireframeAnimation.P_FRAME_COUNT, fc);
|
||||
int dly = (FrameDelayMsec >= 1 && FrameDelayMsec <= 999999) ? FrameDelayMsec : 100;
|
||||
valueDict.Add(VisWireframeAnimation.P_FRAME_DELAY_MSEC, dly);
|
||||
}
|
||||
|
||||
return new ReadOnlyDictionary<string, object>(valueDict);
|
||||
@ -550,8 +603,9 @@ namespace SourceGen.WpfGui {
|
||||
} else {
|
||||
previewGrid.Background = Brushes.Black;
|
||||
previewImage.Source = Visualization.BLANK_IMAGE;
|
||||
wireframePath.Data = Visualization.GenerateWireframePath(visWire, parms,
|
||||
Math.Min(previewImage.ActualWidth, previewImage.ActualHeight) / 2);
|
||||
double dim = Math.Floor(
|
||||
Math.Min(previewImage.ActualWidth, previewImage.ActualHeight));
|
||||
wireframePath.Data = Visualization.GenerateWireframePath(visWire, parms, dim);
|
||||
BitmapDimensions = "n/a";
|
||||
|
||||
mVisObj = visWire;
|
||||
@ -590,6 +644,26 @@ namespace SourceGen.WpfGui {
|
||||
VisWireframeAnimation.P_EULER_ROT_Y, 0);
|
||||
initialZSlider.Value = Util.GetFromObjDict(mOrigVis.VisGenParams,
|
||||
VisWireframeAnimation.P_EULER_ROT_Z, 0);
|
||||
|
||||
// Set this according to the object type, rather than P_IS_ANIMATED. The two
|
||||
// should always be in sync. This should help make it more obvious if they
|
||||
// aren't.
|
||||
IsWireframeAnimated = (mOrigVis is VisWireframeAnimation);
|
||||
|
||||
// This should make it *really* obvious.
|
||||
Debug.Assert(IsWireframeAnimated == Util.GetFromObjDict(mOrigVis.VisGenParams,
|
||||
VisWireframeAnimation.P_IS_ANIMATED, false));
|
||||
|
||||
RotDeltaX = Util.GetFromObjDict(mOrigVis.VisGenParams,
|
||||
VisWireframeAnimation.P_DELTA_ROT_X, 0);
|
||||
RotDeltaY = Util.GetFromObjDict(mOrigVis.VisGenParams,
|
||||
VisWireframeAnimation.P_DELTA_ROT_Y, 0);
|
||||
RotDeltaZ = Util.GetFromObjDict(mOrigVis.VisGenParams,
|
||||
VisWireframeAnimation.P_DELTA_ROT_Z, 0);
|
||||
FrameCount = Util.GetFromObjDict(mOrigVis.VisGenParams,
|
||||
VisWireframeAnimation.P_FRAME_COUNT, 1);
|
||||
FrameDelayMsec = Util.GetFromObjDict(mOrigVis.VisGenParams,
|
||||
VisWireframeAnimation.P_FRAME_DELAY_MSEC, 100);
|
||||
}
|
||||
|
||||
UpdateControls();
|
||||
@ -617,6 +691,40 @@ namespace SourceGen.WpfGui {
|
||||
private void TestAnim_Click(object sender, RoutedEventArgs e) {
|
||||
Debug.WriteLine("TEST!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the number of frames in the animation based on how many incremental
|
||||
/// rotations are required to return the shape to its initial orientation. The
|
||||
/// count will always be between 1 and 360.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There might be a clever way to do this with math, but this is pretty simple.
|
||||
/// </remarks>
|
||||
private void AutoFrameCountButton_Click(object sender, RoutedEventArgs e) {
|
||||
int xr, yr, zr;
|
||||
int xstart = xr = (int)initialXSlider.Value;
|
||||
int ystart = yr = (int)initialYSlider.Value;
|
||||
int zstart = zr = (int)initialZSlider.Value;
|
||||
|
||||
int count;
|
||||
if (RotDeltaX == 0 && RotDeltaY == 0 && RotDeltaZ == 0) {
|
||||
count = 1;
|
||||
} else {
|
||||
count = 0;
|
||||
while (count < 360) {
|
||||
xr = (xr + 360 + RotDeltaX) % 360;
|
||||
yr = (yr + 360 + RotDeltaY) % 360;
|
||||
zr = (zr + 360 + RotDeltaZ) % 360;
|
||||
count++;
|
||||
|
||||
if (xr == xstart && yr == ystart && zr == zstart) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FrameCount = count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Loading…
x
Reference in New Issue
Block a user