0

i was wondering if WPF is capable of rendering a c64 style intro like this one:

https://c64intros.com/groups/f/fairlight-[flt]/flt-01

especially the upper part, where the green lines are "rotating" around the logo. when moving up, they seem to be behind the logo, when moving down, it looks like they're in front of it.

is WPF fast enough for such things? if yes, which type should i use as base? 2d or 3d?

g2zer0
  • 11
  • 1
  • I don't see why not. You can animate the Z-Index of an element on a canvas, so it should be fairly straightforward to do the "rotating" thing. I'd start off with simple 2D shapes (Rect, etc) on a canvas and get more complex if you need. WPF is easily fast enough. – canton7 Aug 12 '21 at 13:08

2 Answers2

2

Here a solution completely solved in XAML, no code behind necessary. It contains a dirty workaround for the text label as I wasn't able to manage it with the ZOrder property. I used the trick that WPF controls are "ZOrder-controlled" by their occurence in XAML. Two labels with the same content at the same location are placed and displayed alternately. So in XAML I placed a Label, a Path to draw the rectangle and then the second label with the same content.

The Storyboard controls the movement of the path/rectangle and hides or displays the first or the second label.

Inspired by:
Setting the Visibility of an Element to Collapsed when Storyboard completes using XAML
How to: Animate a Rectangle Geometry by Using Key Frames - Microsoft.com
Microsoft/WPF-Samples - GitHub.com

<Grid HorizontalAlignment="Center">

    <Label x:Name="TitleLabel1" Content="Fairlight" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,100" FontSize="128" FontFamily="Courier New" />

    <Path Stroke="Black" StrokeThickness="0" >
        <Path.Fill>
            <LinearGradientBrush StartPoint="0 0" EndPoint="0 1">
                <LinearGradientBrush.GradientStops>
                    <GradientStop Offset="0.0" Color="Green" />
                    <GradientStop Offset="0.5" Color="Honeydew" />
                    <GradientStop Offset="1" Color="Green" />
                </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>
        </Path.Fill>
        <Path.Data>
            <RectangleGeometry x:Name="RectangleGeometry" Rect="0,10,750,100" />
        </Path.Data>
        <Path.Triggers>
            <EventTrigger RoutedEvent="Path.Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <!-- Animate the Rect property of the RectangleGeometry which causes the rectangle to animate its position . -->
                        <RectAnimationUsingKeyFrames
                                Storyboard.TargetName="RectangleGeometry"
                                Storyboard.TargetProperty ="Rect"
                                Duration="0:0:2" FillBehavior="HoldEnd" RepeatBehavior="Forever">

                            <SplineRectKeyFrame Value="0,120,750,120" KeyTime="0:0:0.5" KeySpline="0.0,0.0 0.5,0.0"/>
                            <SplineRectKeyFrame Value="0,250,750,100" KeyTime="0:0:1.0" KeySpline="0.0,0.0 0.5,1.0"/>
                            <SplineRectKeyFrame Value="0,140,750,80" KeyTime="0:0:1.5" KeySpline="0.0,0.0 0.5,0.0"/>
                            <SplineRectKeyFrame Value="0,10,750,100" KeyTime="0:0:2.0" KeySpline="0.0,0.0 0.5,1.0"/>
                        </RectAnimationUsingKeyFrames>

                        <ObjectAnimationUsingKeyFrames 
                                Storyboard.TargetName="TitleLabel1"
                                Storyboard.TargetProperty ="Visibility"
                                Duration="0:0:2" FillBehavior="HoldEnd" RepeatBehavior="Forever">

                            <DiscreteObjectKeyFrame  KeyTime="0:0:1.0" Value="{x:Static Visibility.Hidden}"/>
                            <DiscreteObjectKeyFrame  KeyTime="0:0:2.0" Value="{x:Static Visibility.Visible}"/>
                        </ObjectAnimationUsingKeyFrames>
                        
                        <ObjectAnimationUsingKeyFrames 
                                Storyboard.TargetName="TitleLabel2"
                                Storyboard.TargetProperty ="Visibility"
                                Duration="0:0:2" FillBehavior="HoldEnd" RepeatBehavior="Forever">

                            <DiscreteObjectKeyFrame  KeyTime="0:0:0.0" Value="{x:Static Visibility.Hidden}"/>
                            <DiscreteObjectKeyFrame  KeyTime="0:0:1.0" Value="{x:Static Visibility.Visible}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Path.Triggers>
    </Path>

    <Label x:Name="TitleLabel2" Content="Fairlight" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,100" FontSize="128" FontFamily="Courier New" />

</Grid>
MarkusEgle
  • 2,795
  • 4
  • 41
  • 61
0

Use a writeableBitmap. This allow direct access to the backbuffer, and this should be perfectly fine for real time graphics. You will need to write your own code to actually set pixel values to something meaningfull, just like to old days.

You could probably also layer various wpf elements to get the desired effect. Wpf is quite flexible, you could even use your own pixelshaders, so getting the desired effect should be possible, but might be challenging.

That the 'rotating' green bar would be rather simple to do by animating a bitmap with the Y-position linked to a sine function, and adjusting the z order when it reaches the top/bottom.

Note: while this should give perfectly acceptable performance, I would expect the resource usage to be significantly higher than using lower level techniques. So don't expect to compete in the 64kb intro category.

JonasH
  • 28,608
  • 2
  • 10
  • 23