Skip to content

196 rendering engine #197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Pixed.Application/Controls/FrameListControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</ImageBrush.Transform>
</ImageBrush>
</Grid.Background>
<local:SkiaImage MaxWidth="96" MaxHeight="96" Source="{Binding RenderSource}" RenderOptions.BitmapInterpolationMode="None"/>
<local:PixelImageControl MaxWidth="96" MaxHeight="96" Source="{Binding}" RenderOptions.BitmapInterpolationMode="None"/>
</Grid>
</Grid>
</UserControl>
2 changes: 1 addition & 1 deletion Pixed.Application/Controls/LayerListControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<Grid.Background>
<ImageBrush Source="avares://Pixed.Application/Resources/transparentBackground.png"/>
</Grid.Background>
<local:SkiaImage Width="32" Height="32" Source="{Binding RenderSource}" RenderOptions.BitmapInterpolationMode="None"/>
<local:PixelImageControl Width="32" Height="32" Source="{Binding}" RenderOptions.BitmapInterpolationMode="None"/>
</Grid>
<TextBlock Grid.Column="1" Text="{Binding Name}" Foreground="White" VerticalAlignment="Center" Margin="4"/>
<Button Grid.Column="2" Command="{Binding ChangeOpacityCommand}">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<Grid.Background>
<ImageBrush Source="avares://Pixed.Application/Resources/transparentBackground.png"/>
</Grid.Background>
<controls:SkiaImage MaxWidth="20" MaxHeight="20" Source="{Binding RenderSource}" RenderOptions.BitmapInterpolationMode="None"/>
<controls:PixelImageControl MaxWidth="20" MaxHeight="20" Source="{Binding}" RenderOptions.BitmapInterpolationMode="None"/>
</Grid>
</Grid>
<TextBlock Text="{Binding FileName}" Grid.Column="1" FontSize="14" VerticalAlignment="Center"/>
Expand Down
2 changes: 1 addition & 1 deletion Pixed.Application/Controls/PaintCanvas.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
PointerWheelChanged="Canvas_PointerWheelChanged"
RenderOptions.BitmapInterpolationMode="None"
Background="{Binding TransparentBrush}">
<controls:SkiaImage Name="image" RenderOptions.BitmapInterpolationMode="None" Source="{Binding ImageBitmap}"/>
<controls:PixelImageControl Name="image" RenderOptions.BitmapInterpolationMode="None" Source="{Binding RenderModel}"/>
<controls:ImageGrid Width="{Binding ScaledGridWidth}" Height="{Binding ScaledGridHeight}" Name="gridCanvas" IsHitTestVisible="False"/>
<controls:SelectionOverlay Width="{Binding ScaledGridWidth}" Height="{Binding ScaledGridHeight}" Name="selectionOverlay" IsHitTestVisible="False"/>
</Canvas>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,47 @@
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Avalonia.Controls;
using Avalonia.Controls.Automation.Peers;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Skia;
using Avalonia.Threading;
using Pixed.Core.Models;
using Pixed.Core.Utils;
using SkiaSharp;

namespace Pixed.Application.Controls;
internal class SkiaImage : Control
internal class PixelImageControl : Control
{
private class InternalImage : IImage, ICustomDrawOperation
{
private SKBitmap? _source;
private PixelImage? _source;
private Size _size;

public Size Size => _size;

public Rect Bounds { get; set; }

public SKBitmap? Source => _source;
public PixelImage? Source => _source;

public InternalImage(SKBitmap? source)
public InternalImage() : this(null)
{
}
public InternalImage(PixelImage? source)
{
UpdateBitmap(source);
}

public void UpdateBitmap(SKBitmap? source)
public void UpdateBitmap(PixelImage? source)
{
_source = source;
if (source?.Info.Size is SKSizeI size)
if (source is PixelImage image)
{
_size = new(size.Width, size.Height);
var bitmap = image.Render();
_size = new(bitmap.Width, bitmap.Height);
}
}

public InternalImage Clone()
{
return new InternalImage(_source?.Copy());
}

public InternalImage(uint[] colors, Pixed.Core.Models.Point size) : this(SkiaUtils.FromArray(colors, size))
{
}

public void Draw(DrawingContext context, Rect sourceRect, Rect destRect)
{
Bounds = destRect;
Expand All @@ -60,12 +55,12 @@ public void Draw(DrawingContext context, Rect sourceRect, Rect destRect)

public void Render(ImmediateDrawingContext context)
{
if (Source is SKBitmap bitmap && context.PlatformImpl.GetFeature<ISkiaSharpApiLeaseFeature>() is ISkiaSharpApiLeaseFeature leaseFeature)
if (Source != null && context.PlatformImpl.GetFeature<ISkiaSharpApiLeaseFeature>() is ISkiaSharpApiLeaseFeature leaseFeature)
{
ISkiaSharpApiLease lease = leaseFeature.Lease();
using (lease)
{
lease.SkCanvas.DrawBitmap(bitmap, Bounds);
lease.SkCanvas.DrawBitmap(Source.Render(), Bounds);
}
}
}
Expand All @@ -77,37 +72,37 @@ public void Dispose()
/// <summary>
/// Defines the <see cref="Source"/> property.
/// </summary>
public static readonly StyledProperty<SKBitmap?> SourceProperty =
AvaloniaProperty.Register<SkiaImage, SKBitmap?>(nameof(Source));
public static readonly StyledProperty<PixelImage?> SourceProperty =
AvaloniaProperty.Register<PixelImageControl, PixelImage?>(nameof(Source));

/// <summary>
/// Defines the <see cref="Stretch"/> property.
/// </summary>
public static readonly StyledProperty<Stretch> StretchProperty =
AvaloniaProperty.Register<SkiaImage, Stretch>(nameof(Stretch), Stretch.Uniform);
AvaloniaProperty.Register<PixelImageControl, Stretch>(nameof(Stretch), Stretch.Uniform);

/// <summary>
/// Defines the <see cref="StretchDirection"/> property.
/// </summary>
public static readonly StyledProperty<StretchDirection> StretchDirectionProperty =
AvaloniaProperty.Register<SkiaImage, StretchDirection>(
AvaloniaProperty.Register<PixelImageControl, StretchDirection>(
nameof(StretchDirection),
StretchDirection.Both);

static SkiaImage()
static PixelImageControl()
{
AffectsRender<SkiaImage>(SourceProperty, StretchProperty, StretchDirectionProperty);
AffectsMeasure<SkiaImage>(SourceProperty, StretchProperty, StretchDirectionProperty);
AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue<SkiaImage>(AutomationControlType.Image);
AffectsRender<PixelImageControl>(SourceProperty, StretchProperty, StretchDirectionProperty);
AffectsMeasure<PixelImageControl>(SourceProperty, StretchProperty, StretchDirectionProperty);
AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue<PixelImageControl>(AutomationControlType.Image);
}

private readonly InternalImage _image = new(null);
private readonly InternalImage _image = new();

/// <summary>
/// Gets or sets the image that will be displayed.
/// </summary>
[Content]
public SKBitmap? Source
public PixelImage? Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
Expand Down Expand Up @@ -140,8 +135,13 @@ public StretchDirection StretchDirection
/// <param name="context">The drawing context.</param>
public sealed override void Render(DrawingContext context)
{
if (Source == null)
{
return;
}

var source = Source.Render();
_image.UpdateBitmap(Source);
var source = Source;

if (source != null && Bounds.Width > 0 && Bounds.Height > 0)
{
Expand All @@ -159,6 +159,8 @@ public sealed override void Render(DrawingContext context)
_image.Bounds = destRect;
context.DrawImage(_image, sourceRect, destRect);
}

Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Input);
}

/// <summary>
Expand All @@ -168,7 +170,7 @@ public sealed override void Render(DrawingContext context)
/// <returns>The desired size of the control.</returns>
protected override Size MeasureOverride(Size availableSize)
{
var source = Source;
var source = Source?.Render();
var result = new Size();

if (source != null)
Expand All @@ -182,7 +184,7 @@ protected override Size MeasureOverride(Size availableSize)
/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
var source = Source;
var source = Source?.Render();

if (source != null)
{
Expand All @@ -195,9 +197,4 @@ protected override Size ArrangeOverride(Size finalSize)
return new Size();
}
}

protected override AutomationPeer OnCreateAutomationPeer()
{
return new ImageAutomationPeer(this);
}
}
4 changes: 2 additions & 2 deletions Pixed.Application/Controls/ProjectAnimation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ public void Render(ImmediateDrawingContext context)
}

var frameBitmap = _applicationData.CurrentModel.Frames[_frameIndex] ?? null;
if (frameBitmap == null || frameBitmap.RenderSource == null)
if (frameBitmap == null)
{
return;
}

var renderSource = frameBitmap.RenderSource;
var renderSource = frameBitmap.Render();
if (context.PlatformImpl.GetFeature<ISkiaSharpApiLeaseFeature>() is ISkiaSharpApiLeaseFeature leaseFeature)
{
ISkiaSharpApiLease lease = leaseFeature.Lease();
Expand Down
36 changes: 36 additions & 0 deletions Pixed.Application/Models/RenderModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Pixed.Core.Models;
using SkiaSharp;

namespace Pixed.Application.Models;
internal class RenderModel : PixelImage
{
private Frame? _frame;
private SKBitmap? _overlay;

public Frame? Frame
{
get => _frame;
set
{
_frame = value;
}
}
public SKBitmap? Overlay
{
get => _overlay;
set
{
_overlay = value;
}
}
public override SKBitmap Render()
{
SKBitmap image = new(_frame.Width, _frame.Height, true);
SKCanvas canvas = new(image);
canvas.Clear(SKColors.Transparent);
canvas.DrawBitmap(_frame.Render(), SKPoint.Empty);
canvas.DrawBitmap(_overlay, SKPoint.Empty);
canvas.Dispose();
return image;
}
}
1 change: 0 additions & 1 deletion Pixed.Application/Pages/Main.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ private async Task ChangeOpacityAction(Layer layer)
if (result.HasValue)
{
layer.Opacity = result.Value;
layer.RefreshRenderSource();
}
}

Expand Down
6 changes: 0 additions & 6 deletions Pixed.Application/ViewModels/LayersSectionViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,6 @@ public LayersSectionViewModel(ApplicationData applicationData, IMenuItemRegistry
SelectedLayer = f.SelectedLayer;
});

_layerModified = Subjects.LayerModified.Subscribe(l =>
{
l.Rerender();
});

_layerAdded = Subjects.LayerAdded.Subscribe(l =>
{
SelectedLayer = _applicationData.CurrentFrame.Layers.IndexOf(l);
Expand Down Expand Up @@ -235,7 +230,6 @@ private void MergeLayerAction()

Subjects.LayerRemoved.OnNext(removedLayer);
Subjects.LayerModified.OnNext(currentLayer);
currentLayer.RefreshRenderSource();
Subjects.FrameModified.OnNext(Frame);
OnPropertyChanged(nameof(Layers));
_applicationData.CurrentModel.AddHistory();
Expand Down
Loading
Loading