Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
RenderSurfaceAdapterBase.cs
1using System.Drawing;
2using SkiaSharp;
3
4namespace Gondwana.Rendering;
5
10public abstract class RenderSurfaceAdapterBase
11{
12 private sealed class PresentationState(int bufferWidth, int bufferHeight, int adapterWidth, int adapterHeight)
13 {
14 internal readonly int BufferWidth = bufferWidth, BufferHeight = bufferHeight;
15 internal readonly int AdapterWidth = adapterWidth, AdapterHeight = adapterHeight;
16 internal readonly PresentationTransform Transform = PresentationTransform.Fit(bufferWidth, bufferHeight, adapterWidth, adapterHeight);
17 }
18
19 private readonly object _presentationSync = new();
20 private PresentationState _presentation = new(1, 1, 0, 0);
21 internal bool InitialSizeAvailable { get; private set; }
22
24 public PresentationTransform Presentation => Volatile.Read(ref _presentation).Transform;
25
27 public float PresentationScale => Presentation.Scale;
28
29 internal void SetBackbufferSize(int width, int height)
30 {
31 lock (_presentationSync)
32 {
33 var state = _presentation;
34 Volatile.Write(ref _presentation, new(width, height, state.AdapterWidth, state.AdapterHeight));
35 }
36 }
37
41 public Point AdapterPxToScreenPx(PointF adapterPx)
42 {
43 Presentation.TryAdapterPxToScreenPx(adapterPx, out var screen);
44 // Floor is essential: a fractional negative margin must not truncate to the edge pixel zero.
45 return new Point((int)Math.Floor(screen.X), (int)Math.Floor(screen.Y));
46 }
47
52 public void DrawImage(SKCanvas canvas, SKImage image, SKColor clearColor)
53 {
54 var state = Volatile.Read(ref _presentation);
55 // A queued CPU snapshot may precede an explicit resolution change. Fit that complete
56 // image using the same authoritative calculation until its replacement arrives.
57 var transform = image.Width == state.BufferWidth && image.Height == state.BufferHeight
58 ? state.Transform : PresentationTransform.Fit(image.Width, image.Height, state.AdapterWidth, state.AdapterHeight);
59 canvas.Clear(clearColor);
60 if (transform.Scale <= 0) return;
61 canvas.DrawImage(image, transform.DestinationRect, PresentationSampling);
62 }
63
64 internal static SKSamplingOptions PresentationSampling => new(
65 Engine.Instance.Configuration.RenderScalingFilter == RenderScalingFilter.NearestNeighbor
66 ? SKFilterMode.Nearest : SKFilterMode.Linear);
67
75 public event Action<RenderSurfaceAdapterResizedEventArgs>? Resized;
76
81 public int Width
82 {
83 get => Volatile.Read(ref _presentation).AdapterWidth;
84 protected set => SetDestinationSize(value, Height);
85 }
86
91 public int Height
92 {
93 get => Volatile.Read(ref _presentation).AdapterHeight;
94 protected set => SetDestinationSize(Width, value);
95 }
96
102 protected RenderSurfaceAdapterBase(int destWidth, int destHeight)
103 : this(destWidth, destHeight, initialSizeAvailable: true) { }
104
109 protected RenderSurfaceAdapterBase(int destWidth, int destHeight, bool initialSizeAvailable)
110 {
111 SetDestinationSize(destWidth, destHeight);
112 InitialSizeAvailable = initialSizeAvailable;
113 }
114
124 protected void SetDestinationSize(int destWidth, int destHeight)
125 {
126 var sizeAvailable = destWidth > 0 && destHeight > 0;
127 if (destWidth == Width && destHeight == Height && InitialSizeAvailable == sizeAvailable)
128 return;
129
130 var oldWidth = Width;
131 var oldHeight = Height;
132
133 InitialSizeAvailable = sizeAvailable;
134 lock (_presentationSync)
135 {
136 var state = _presentation;
137 Volatile.Write(ref _presentation, new(state.BufferWidth, state.BufferHeight, destWidth, destHeight));
138 }
139 Resized?.Invoke(new RenderSurfaceAdapterResizedEventArgs(this, oldWidth, oldHeight, Width, Height));
140 }
141
151 public abstract void Present(SKImage bufferImage, SKRectI bufferRect, SKRect destRect);
152}
int Width
Gets the current width of the render surface in pixels.
void Present(SKImage bufferImage, SKRectI bufferRect, SKRect destRect)
Presents the specified portion of the Backbuffer image to the destination rectangle on the RenderSurf...
RenderSurfaceAdapterBase(int destWidth, int destHeight, bool initialSizeAvailable)
Constructs an adapter whose initial layout may still be pending.
float PresentationScale
Current derived presentation scale; adapter resize does not resize the Backbuffer.
void SetDestinationSize(int destWidth, int destHeight)
Sets the destination size of the render surface and raises the Resized event if the dimensions have c...
PresentationTransform Presentation
Current immutable aspect-preserving mapping of Backbuffer ScreenPx to adapter pixels.
RenderSurfaceAdapterBase(int destWidth, int destHeight)
Initializes a new instance of the RenderSurfaceAdapterBase class with the specified dimensions.
Point AdapterPxToScreenPx(PointF adapterPx)
Converts adapter input to logical ScreenPx, retaining outside coordinates for capture/leave.
int Height
Gets the current height of the render surface in pixels.
Action< RenderSurfaceAdapterResizedEventArgs >? Resized
Occurs when the render surface adapter is resized.
void DrawImage(SKCanvas canvas, SKImage image, SKColor clearColor)
Presents a complete image using the same transform as pointer normalization.
Provides data for the RenderSurfaceAdapterBase.Resized event.
readonly record struct PresentationTransform(float Scale, SKRect DestinationRect)
Aspect-preserving mapping between logical Backbuffer ScreenPx and adapter pixels.
@ NearestNeighbor
Unfiltered nearest-pixel presentation for pixel art.