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
DirectImage.cs
1using System.Drawing;
7using SkiaSharp;
8
10
59public sealed class DirectImage : DirectDrawingMovableBase
60{
69 public enum ScaleMode
70 {
76
83
90
97
104 }
105
106 private SKImage? _image; // primary storage
107 private SKBitmap? _bitmap; // optional if provided instead of SKImage
108 private SKRect? _src; // source sprite region (in image pixels)
109 private ScaleMode _scale = ScaleMode.Stretch;
110
111 private readonly SKPaint _paint = new()
112 {
113 IsAntialias = true,
114 FilterQuality = SKFilterQuality.Medium,
115 BlendMode = SKBlendMode.SrcOver,
116 Color = SKColors.White // used for tint/alpha via color filter
117 };
118
119 // visual modifiers
120 private SKColor? _tint; // multiplied over image
121 private byte _opacity = 255; // 0..255
122
123 // rotation
124 private float _rotationDeg = 0f;
125
126 // normalized anchor (0..1) where 0,0 = top-left of dest rect
127 private float _anchorX = 0.5f, _anchorY = 0.5f;
128
129 private DirectImage(SKBitmap bitmap,
130 RenderSurfaceHostBase renderSurfaceHost,
132 SceneLayer? sceneLayer,
133 View? view,
134 Rectangle? screenBounds,
135 Rectangle? worldBounds,
136 string? name = null)
137 : base(renderSurfaceHost, mode, sceneLayer, view, screenBounds, worldBounds, name)
138 {
139 SetBitmap(bitmap);
140 }
141
142 private DirectImage(SKImage image,
143 RenderSurfaceHostBase renderSurfaceHost,
145 SceneLayer? sceneLayer,
146 View? view,
147 Rectangle? screenBounds,
148 Rectangle? worldBounds,
149 string? nickname = null)
150 : base(renderSurfaceHost, mode, sceneLayer, view, screenBounds, worldBounds, nickname)
151 {
152 SetImage(image);
153 }
154
175 public DirectImage(SKBitmap bitmap,
176 RenderSurfaceHostBase renderSurfaceHost,
177 SceneLayer sceneLayer,
178 Rectangle worldBounds,
179 string? nickname = null) : this(bitmap, renderSurfaceHost, DirectDrawingMode.SceneLayer, sceneLayer, null, null, worldBounds, nickname) { }
180
200 public DirectImage(SKBitmap bitmap,
201 RenderSurfaceHostBase renderSurfaceHost,
202 View view,
203 Rectangle screenBounds,
204 string? nickname = null) : this(bitmap, renderSurfaceHost, DirectDrawingMode.View, null, view, screenBounds, null, nickname) { }
205
227 public DirectImage(SKImage image,
228 RenderSurfaceHostBase renderSurfaceHost,
229 SceneLayer sceneLayer,
230 Rectangle worldBounds,
231 string? nickname = null) : this(image, renderSurfaceHost, DirectDrawingMode.SceneLayer, sceneLayer, null, null, worldBounds, nickname) { }
232
253 public DirectImage(SKImage image,
254 RenderSurfaceHostBase renderSurfaceHost,
255 View view,
256 Rectangle screenBounds,
257 string? nickname = null) : this(image, renderSurfaceHost, DirectDrawingMode.View, null, view, screenBounds, null, nickname) { }
258
276 public DirectImage SetBitmap(SKBitmap bitmap)
277 {
278 _bitmap = bitmap ?? throw new ArgumentNullException(nameof(bitmap));
279 _image = null;
280 ForceRefresh();
281 return this;
282 }
283
301 public DirectImage SetImage(SKImage image)
302 {
303 _image = image ?? throw new ArgumentNullException(nameof(image));
304 _bitmap = null;
305 ForceRefresh();
306 return this;
307 }
308
330 public DirectImage SetSourceRect(SKRect? srcPixels)
331 {
332 _src = srcPixels;
333 ForceRefresh();
334 return this;
335 }
336
360 public DirectImage SetScaleMode(ScaleMode mode)
361 {
362 _scale = mode;
363 ForceRefresh();
364 return this;
365 }
366
386 public DirectImage SetTint(SKColor color)
387 {
388 _tint = color;
389 ForceRefresh();
390 return this;
391 }
392
406 public DirectImage ClearTint()
407 {
408 _tint = null;
409 ForceRefresh();
410 return this;
411 }
412
431 public DirectImage SetOpacity(byte alpha)
432 {
433 _opacity = alpha;
434 ForceRefresh();
435 return this;
436 }
437
458 public DirectImage SetBlendMode(SKBlendMode mode)
459 {
460 _paint.BlendMode = mode;
461 ForceRefresh();
462 return this;
463 }
464
491 public DirectImage SetFilterQuality(SKFilterQuality q)
492 {
493 _paint.FilterQuality = q;
494 ForceRefresh();
495 return this;
496 }
497
516 public DirectImage SetRotation(float degrees)
517 {
518 _rotationDeg = degrees;
519 ForceRefresh();
520 return this;
521 }
522
548 public DirectImage SetAnchor(float ax, float ay)
549 {
550 _anchorX = Math.Clamp(ax, 0f, 1f);
551 _anchorY = Math.Clamp(ay, 0f, 1f);
552 ForceRefresh();
553 return this;
554 }
555
579 protected override void OnDraw(BackbufferBase backbuffer, RectangleF destRectScreen)
580 {
581 var canvas = backbuffer.Canvas;
582
583 // get SKImage to draw
584 var img = _image ?? (_bitmap != null ? SKImage.FromBitmap(_bitmap) : null);
585 if (img is null)
586 return;
587
588 if (backbuffer is RecordingBackbuffer && img.IsTextureBacked)
589 throw new NotSupportedException("Desktop frame recording requires a CPU image, not a context-bound texture.");
590
591 // source rect (pixels in image space)
592 SKRect src = _src ?? new SKRect(0, 0, img.Width, img.Height);
593
594 // destination rect (screen space), computed by scale mode
595 SKRect dst = ComputeDestRect(destRectScreen.ToPixelAlignedRect(), src, _scale);
596
597 // apply tint/opacity via color filter
598 // combine tint with opacity (multiply in linear-ish sRGB)
599 var tint = _tint ?? SKColors.White;
600 var withAlpha = new SKColor(tint.Red, tint.Green, tint.Blue, _opacity);
601 using var cf = SKColorFilter.CreateBlendMode(withAlpha, SKBlendMode.Modulate);
602 _paint.ColorFilter = cf;
603
604 // rotation about anchor inside dst
605 if (_rotationDeg != 0f)
606 {
607 float ax = dst.Left + _anchorX * dst.Width;
608 float ay = dst.Top + _anchorY * dst.Height;
609 canvas.Save();
610 canvas.RotateDegrees(_rotationDeg, ax, ay);
611 }
612
613 // draw
614 canvas.DrawImage(img, src, dst, _paint);
615
616 if (_rotationDeg != 0f)
617 canvas.Restore();
618
619 // if we created a transient SKImage from a bitmap, dispose it now
620 if (_image is null && img is not null)
621 img.Dispose();
622 }
623
624 private static SKRect ComputeDestRect(Rectangle bounds, SKRect src, ScaleMode mode)
625 {
626 var dst = bounds.ToSKRect();
627
628 if (mode == ScaleMode.Stretch)
629 return dst;
630
631 if (mode == ScaleMode.Center) // center, no scale
632 {
633 float w = MathF.Min(dst.Width, src.Width);
634 float h = MathF.Min(dst.Height, src.Height);
635 float dx = dst.MidX - w * 0.5f, dy = dst.MidY - h * 0.5f;
636
637 return new SKRect(dx, dy, dx + w, dy + h);
638 }
639
640 float srcW = src.Width, srcH = src.Height;
641 float dstW = dst.Width, dstH = dst.Height;
642
643 float scaleX = dstW / srcW;
644 float scaleY = dstH / srcH;
645
646 float scale = mode switch
647 {
648 ScaleMode.Fit => MathF.Min(scaleX, scaleY),
649 ScaleMode.Fill => MathF.Max(scaleX, scaleY),
650 ScaleMode.PixelPerfect => MathF.Max(1f, MathF.Floor(MathF.Min(scaleX, scaleY))),
651 _ => 1f
652 };
653
654 float w2 = srcW * scale, h2 = srcH * scale;
655 float x = dst.MidX - w2 * 0.5f;
656 float y = dst.MidY - h2 * 0.5f;
657
658 return new SKRect(x, y, x + w2, y + h2);
659 }
660}
View? View
Gets the view to which this direct drawing is attached, or null if the drawing is in scene-layer mode...
SceneLayer? SceneLayer
Gets the scene layer to which this direct drawing is attached, or null if the drawing is in view mode...
DirectDrawingMovableBase(RenderSurfaceHostBase renderSurfaceHost, DirectDrawingMode mode, SceneLayer? sceneLayer, View? view, Rectangle? screenBounds, Rectangle? worldBounds, string? name=null)
Initializes a new instance of the DirectDrawingMovableBase class with integrated movement capabilitie...
DirectImage(SKBitmap bitmap, RenderSurfaceHostBase renderSurfaceHost, SceneLayer sceneLayer, Rectangle worldBounds, string? nickname=null)
Initializes a new instance of the DirectImage class for scene-layer (world-space) rendering using a b...
DirectImage SetAnchor(float ax, float ay)
Sets the rotation and scaling anchor point within the destination rectangle using normalized coordina...
DirectImage SetScaleMode(ScaleMode mode)
Sets how the image is scaled to fit within the destination rectangle.
DirectImage SetFilterQuality(SKFilterQuality q)
Sets the filter quality used when scaling the image.
DirectImage ClearTint()
Removes any color tint, restoring the image's original colors.
DirectImage SetBlendMode(SKBlendMode mode)
Sets the Skia blend mode used when compositing this image onto the backbuffer.
DirectImage SetTint(SKColor color)
Applies a color tint (multiplicative blend) to the image.
override void OnDraw(BackbufferBase backbuffer, RectangleF destRectScreen)
Renders the image to the backbuffer with all configured transformations and effects applied.
DirectImage SetImage(SKImage image)
Replaces the backing image with a new one.
DirectImage SetBitmap(SKBitmap bitmap)
Replaces the backing bitmap with a new one.
DirectImage SetOpacity(byte alpha)
Sets the overall opacity (alpha transparency) of the image.
DirectImage(SKImage image, RenderSurfaceHostBase renderSurfaceHost, View view, Rectangle screenBounds, string? nickname=null)
Initializes a new instance of the DirectImage class for view (screen-space) rendering using a pre-enc...
DirectImage(SKImage image, RenderSurfaceHostBase renderSurfaceHost, SceneLayer sceneLayer, Rectangle worldBounds, string? nickname=null)
Initializes a new instance of the DirectImage class for scene-layer (world-space) rendering using a p...
DirectImage SetRotation(float degrees)
Sets the rotation angle in degrees around the anchor point.
DirectImage SetSourceRect(SKRect? srcPixels)
Sets the source rectangle within the image to display, enabling sprite sheet support.
ScaleMode
Defines how an image is scaled to fit within the destination rectangle.
@ Fit
Scales the image to fit entirely within the destination rectangle while preserving aspect ratio....
@ PixelPerfect
Scales the image by the largest integer factor that fits within the destination rectangle while prese...
@ Center
Displays the image at its native resolution without scaling, centered in the destination rectangle....
@ Fill
Scales the image to completely cover the destination rectangle while preserving aspect ratio....
@ Stretch
Stretches the image to fill the entire destination rectangle, ignoring aspect ratio....
DirectImage(SKBitmap bitmap, RenderSurfaceHostBase renderSurfaceHost, View view, Rectangle screenBounds, string? nickname=null)
Initializes a new instance of the DirectImage class for view (screen-space) rendering using a bitmap.
Represents a base class for managing a graphical backbuffer, and is the in-memory surface where rende...
SKCanvas Canvas
Gets the SkiaSharp canvas used for drawing operations on this backbuffer.
Represents a base class for hosting a render surface, providing functionality for managing rendering ...
Represents a rendered view of a scene, combining a camera position with a viewport configuration to c...
Definition View.cs:14
Represents a single layer within a Scene, containing a grid of tiles and supporting various coordinat...
Definition SceneLayer.cs:40
DirectDrawingMode
Specifies where direct drawing operations are applied within the rendering pipeline.