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
Viewport.cs
1using System.Drawing;
2
4
9public sealed class Viewport
10{
11 private Rectangle _targetRectPx = new Rectangle(0, 0, 1280, 720);
12 private float _zoom = 1f;
13 private float? _zoomTarget;
14 private float _zoomLerpPerSecond;
15 private float? _zoomDurationSeconds;
16 private float _zoomElapsedSeconds;
17 private float _zoomStart;
18
23 public event Action<ViewportResizedEventArgs>? TargetRectChanged;
24
28 public event Action<ViewportZoomChangedEventArgs>? ZoomChanged;
29
34 public Rectangle TargetRectPx
35 {
36 get => _targetRectPx;
37 set
38 {
39 if (value == _targetRectPx)
40 return;
41
42 var oldRect = _targetRectPx;
43 _targetRectPx = value;
44 TargetRectChanged?.Invoke(new ViewportResizedEventArgs(this, oldRect, value));
45 }
46 }
47
55 public void Resize(int width, int height)
56 {
57 var rect = TargetRectPx;
58 TargetRectPx = new Rectangle(rect.Left, rect.Top, width, height);
59 }
60
66 public float Zoom
67 {
68 get => _zoom;
69 set
70 {
71 if (Math.Abs(value - _zoom) < 1e-6f)
72 return;
73
74 var oldZoom = _zoom;
75 _zoom = value;
76 ZoomChanged?.Invoke(new ViewportZoomChangedEventArgs(this, oldZoom, value));
77 }
78 }
79
81 public PointF ScreenOffsetPx { get; set; } = PointF.Empty;
82
84 public SizeF VisibleWorldSizePx => new SizeF(TargetRectPx.Width / Zoom, TargetRectPx.Height / Zoom);
85
87 internal bool IsZoomAnimating => _zoomTarget is not null;
88
89 #region zoom zoom
90
95 public void SnapZoom(float zoom)
96 {
97 _zoomTarget = null;
98 _zoomLerpPerSecond = 0f;
99 _zoomDurationSeconds = null;
100 _zoomElapsedSeconds = 0f;
101 _zoomStart = zoom;
102
103 Zoom = zoom;
104 }
105
112 public void ZoomTo(float targetZoom, float lerpPerSecond)
113 {
114 if (lerpPerSecond <= 0f)
115 {
116 SnapZoom(targetZoom);
117 return;
118 }
119
120 _zoomStart = _zoom;
121 _zoomTarget = targetZoom;
122 _zoomLerpPerSecond = lerpPerSecond;
123 _zoomDurationSeconds = null;
124 _zoomElapsedSeconds = 0f;
125 }
126
133 public void ZoomToOverDuration(float targetZoom, float durationSeconds)
134 {
135 if (durationSeconds <= 0f)
136 {
137 SnapZoom(targetZoom);
138 return;
139 }
140
141 _zoomStart = _zoom;
142 _zoomTarget = targetZoom;
143
144 _zoomDurationSeconds = durationSeconds;
145 _zoomElapsedSeconds = 0f;
146
147 // The fixed-duration path calculates progress directly.
148 _zoomLerpPerSecond = 0f;
149 }
150
156 internal void UpdateZoom(float dtSeconds)
157 {
158 if (_zoomTarget is null)
159 return;
160
161 float target = _zoomTarget.Value;
162 float dt = Math.Max(0f, dtSeconds);
163
164 if (_zoomDurationSeconds is { } durationSeconds)
165 {
166 _zoomElapsedSeconds = Math.Min(_zoomElapsedSeconds + dt, durationSeconds);
167
168 float progress = durationSeconds > 0f ? _zoomElapsedSeconds / durationSeconds : 1f;
169
170 // Preserve the existing exponential ease-out character, but normalize
171 // it so progress reaches exactly 1 at the requested duration.
172 const float decay = 4.605170186f; // -ln(0.01)
173
174 float normalization = 1f - MathF.Exp(-decay);
175 float easedProgress = (1f - MathF.Exp(-decay * progress)) / normalization;
176
177 Zoom = _zoomStart + (target - _zoomStart) * easedProgress;
178
179 if (_zoomElapsedSeconds >= durationSeconds)
180 {
181 // This no longer causes a visible jump: easedProgress is already 1.
182 SnapZoom(target);
183 }
184
185 return;
186 }
187
188 if (_zoomLerpPerSecond <= 0f)
189 return;
190
191 float t = 1f - MathF.Exp(-_zoomLerpPerSecond * dt);
192
193 float newZoom = _zoom + (target - _zoom) * t;
194
195 Zoom = newZoom;
196
197 if (Math.Abs(newZoom - target) < 1e-4f)
198 SnapZoom(target);
199 }
200 #endregion zoom zoom
201}
Provides data for the Viewport.TargetRectChanged event, which is raised when a viewport's target rect...
Provides data for the Viewport.ZoomChanged event, which is raised when a viewport's zoom level change...
A rectangular window on the render target with its own zoom and placement. Viewport never moves the w...
Definition Viewport.cs:10
Rectangle TargetRectPx
Screen-space rectangle (in SCREEN / RenderSurface pixels) where this view is drawn....
Definition Viewport.cs:35
PointF ScreenOffsetPx
Optional per-view HUD/safe-area offset in screen pixels.
Definition Viewport.cs:81
void ZoomToOverDuration(float targetZoom, float durationSeconds)
Smoothly animates the zoom using exponential easing and snaps exactly to the target when the requeste...
Definition Viewport.cs:133
Action< ViewportResizedEventArgs >? TargetRectChanged
Fired whenever TargetRectPx changes (viewport resized or moved). Provides the Viewport instance and t...
Definition Viewport.cs:23
Action< ViewportZoomChangedEventArgs >? ZoomChanged
Occurs when the zoom level of the viewport changes.
Definition Viewport.cs:28
void SnapZoom(float zoom)
Instantly sets the zoom level, raising the ZoomChanged event.
Definition Viewport.cs:95
void ZoomTo(float targetZoom, float lerpPerSecond)
Smoothly animates the zoom toward a target level using an exponential lerp rate in "per second" units...
Definition Viewport.cs:112
void Resize(int width, int height)
Updates the viewport size while preserving its current on-screen origin. This is a convenience around...
Definition Viewport.cs:55
SizeF VisibleWorldSizePx
World size visible through this viewport (used for Camera clamping).
Definition Viewport.cs:84
float Zoom
Zoom factor applied to the world when rendering this view. Values greater than 1 zoom in,...
Definition Viewport.cs:67