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
ViewManager.cs
1using System.Collections.ObjectModel;
2using System.Drawing;
4
6
13public sealed class ViewManager
14{
15 private readonly RenderSurfaceHostBase _renderSurfaceHost;
16 private readonly List<View> _views = new();
17
21 public event Action<View>? ViewAdded;
22
26 public event Action<View>? ViewRemoved;
27
28 private ViewManager() { }
29
30 internal ViewManager(RenderSurfaceHostBase renderSurfaceHost)
31 {
32 _renderSurfaceHost = renderSurfaceHost;
33 }
34
42 public ReadOnlyCollection<View> Views => _views.AsReadOnly();
43
70 public void AddView(Rectangle targetRectPx, float zoom = 1f, int zOrder = 0, RectangleF? worldBoundsPx = null)
71 {
72 if (worldBoundsPx is null)
73 worldBoundsPx = RectangleF.Empty;
74
75 var cam = new Camera(_renderSurfaceHost.Scene)
76 {
77 // clamp camera to Scene pixel bounds
78 WorldBoundsPx = worldBoundsPx.Value,
79 FollowLerpPerSecond = 0f // snap by default
80 };
81
82 cam.SnapTo(new PointF(0, 0));
83
84 var vp = new Viewport
85 {
86 TargetRectPx = targetRectPx,
87 Zoom = zoom
88 };
89
90 var view = new View(cam, vp) { ZOrder = zOrder };
91 view.Viewport.TargetRectChanged += OnViewportTargetRectChanged;
92 view.Viewport.ZoomChanged += OnViewportZoomChanged;
93
94 _views.Add(view);
95 _renderSurfaceHost.Scene.FullRefreshNeeded = true;
96
97 SortViews();
98
99 ViewAdded?.Invoke(view);
100 }
101
108 public void ConfigureSingleFullView(float zoom = 1f, int zOrder = 0)
109 {
110 if (_renderSurfaceHost.RenderSurfaceAdapter is null)
111 throw new InvalidOperationException("RenderSurfaceAdapter is not available.");
112
113 ClearViews();
114
115 var backbuffer = _renderSurfaceHost.Backbuffer;
116 var bounds = new Rectangle(0, 0, backbuffer.Width, backbuffer.Height);
117
118 RectangleF worldBoundsPx = RectangleF.Empty;
119 if (_renderSurfaceHost.Scene is not null)
120 worldBoundsPx = _renderSurfaceHost.Scene.GetWorldBoundsPx();
121
122 AddView(bounds, zoom, zOrder, worldBoundsPx);
123 }
124
131 public void ConfigureVerticalSplit(float leftZoom = 1f, float rightZoom = 1f)
132 {
133 if (_renderSurfaceHost.RenderSurfaceAdapter is null)
134 throw new InvalidOperationException("RenderSurfaceAdapter is not available.");
135
136 ClearViews();
137
138 var backbuffer = _renderSurfaceHost.Backbuffer;
139 int width = backbuffer.Width;
140 int height = backbuffer.Height;
141
142 int halfWidth = width / 2;
143
144 RectangleF worldBoundsPx = RectangleF.Empty;
145 if (_renderSurfaceHost.Scene is not null)
146 worldBoundsPx = _renderSurfaceHost.Scene.GetWorldBoundsPx();
147
148 // Left view
149 AddView(
150 new Rectangle(0, 0, halfWidth, height),
151 leftZoom,
152 zOrder: 0,
153 worldBoundsPx: worldBoundsPx);
154
155 // Right view
156 AddView(
157 new Rectangle(halfWidth, 0, width - halfWidth, height),
158 rightZoom,
159 zOrder: 1,
160 worldBoundsPx: worldBoundsPx);
161 }
162
169 public void ConfigureHorizontalSplit(float topZoom = 1f, float bottomZoom = 1f)
170 {
171 if (_renderSurfaceHost.RenderSurfaceAdapter is null)
172 throw new InvalidOperationException("RenderSurfaceAdapter is not available.");
173
174 ClearViews();
175
176 var backbuffer = _renderSurfaceHost.Backbuffer;
177 int width = backbuffer.Width;
178 int height = backbuffer.Height;
179
180 int halfHeight = height / 2;
181
182 RectangleF worldBoundsPx = RectangleF.Empty;
183 if (_renderSurfaceHost.Scene is not null)
184 worldBoundsPx = _renderSurfaceHost.Scene.GetWorldBoundsPx();
185
186 // Top view
187 AddView(
188 new Rectangle(0, 0, width, halfHeight),
189 topZoom,
190 zOrder: 0,
191 worldBoundsPx: worldBoundsPx);
192
193 // Bottom view
194 AddView(
195 new Rectangle(0, halfHeight, width, height - halfHeight),
196 bottomZoom,
197 zOrder: 1,
198 worldBoundsPx: worldBoundsPx);
199 }
200
210 public void ClearViews()
211 {
212 foreach (var view in _views!)
213 {
214 view.Viewport.TargetRectChanged -= OnViewportTargetRectChanged;
215 view.Viewport.ZoomChanged -= OnViewportZoomChanged;
216 ViewRemoved?.Invoke(view);
217 }
218
219 _views.Clear();
220
221 if (_renderSurfaceHost.Scene is not null)
222 _renderSurfaceHost.Scene.FullRefreshNeeded = true;
223 }
224
237 public IReadOnlyList<View> GetViewsBelow(View view)
238 {
239 int idx = _views.IndexOf(view);
240 if (idx <= 0)
241 return Array.Empty<View>();
242
243 // views with lower Z (earlier in sorted list)
244 return _views.GetRange(0, idx);
245 }
246
259 public IReadOnlyList<View> GetViewsAbove(View view)
260 {
261 int idx = _views.IndexOf(view);
262 if (idx < 0 || idx >= _views.Count - 1)
263 return Array.Empty<View>();
264
265 // views with higher Z (later in sorted list)
266 return _views.GetRange(idx + 1, _views.Count - (idx + 1));
267 }
268
269 #region internal methods
270
271 internal void UpdateCameras(float dtSeconds)
272 {
273 foreach (var view in _views)
274 view.Update(dtSeconds);
275 }
276
277 internal void BindToScene(Scene scene, bool limitCameraToWorldBoundPx)
278 {
279 RectangleF worldBoundsPx = limitCameraToWorldBoundPx ? scene.GetWorldBoundsPx() : RectangleF.Empty;
280
281 // if no views exist, create a default one
282 if (!_views.Any())
283 {
284 AddView(new Rectangle(0, 0, _renderSurfaceHost.Backbuffer.Width, _renderSurfaceHost.Backbuffer.Height), 1, 0, worldBoundsPx);
285 }
286 else
287 {
288 foreach (var view in _views)
289 {
290 view.Camera.WorldBoundsPx = worldBoundsPx;
291 }
292 }
293 }
294
295 #endregion internal methods
296
297 #region private methods
298
299 private void OnViewportZoomChanged(ViewportZoomChangedEventArgs args)
300 {
301 if (_renderSurfaceHost.Scene is not null)
302 _renderSurfaceHost.Scene.FullRefreshNeeded = true;
303 }
304
305 private void OnViewportTargetRectChanged(ViewportResizedEventArgs args)
306 {
307 if (_renderSurfaceHost.Scene is not null)
308 _renderSurfaceHost.Scene.FullRefreshNeeded = true;
309 }
310
311 private void SortViews()
312 {
313 _views.Sort(static (a, b) =>
314 {
315 int cmp = a.ZOrder.CompareTo(b.ZOrder);
316
317 if (cmp != 0)
318 return cmp;
319
320 // deterministic tie-breaker
321 return a.Id.CompareTo(b.Id);
322 });
323 }
324
325 #endregion private methods
326}
Represents a base class for hosting a render surface, providing functionality for managing rendering ...
Represents a world-space camera for a Scene. The camera tracks a world-space upper-left position in p...
Definition Camera.cs:16
void SnapTo(PointF worldUpperLeftPx)
Instantly moves the camera to the specified world-space position, interpreted as the upper-left corne...
Definition Camera.cs:92
Manages a collection of views for a render surface, handling view creation, removal,...
void ConfigureVerticalSplit(float leftZoom=1f, float rightZoom=1f)
Removes all existing views and creates a vertical split-screen layout: left and right views sharing t...
void ClearViews()
Removes all views from the manager, unsubscribing from their events and marking the scene as needing ...
IReadOnlyList< View > GetViewsAbove(View view)
Returns all views that are rendered in front of (above) the specified view, based on Z-order....
Action< View >? ViewRemoved
Occurs after a View is removed.
ReadOnlyCollection< View > Views
Gets a read-only collection of all views currently managed by this view manager. Views are sorted by ...
void ConfigureHorizontalSplit(float topZoom=1f, float bottomZoom=1f)
Removes all existing views and creates a horizontal split-screen layout: top and bottom views sharing...
void ConfigureSingleFullView(float zoom=1f, int zOrder=0)
Removes all existing views and creates a single full-screen view that occupies the entire logical Bac...
IReadOnlyList< View > GetViewsBelow(View view)
Returns all views that are rendered behind (below) the specified view, based on Z-order....
void AddView(Rectangle targetRectPx, float zoom=1f, int zOrder=0, RectangleF? worldBoundsPx=null)
Creates and adds a new view with the specified screen rectangle, zoom level, and Z-order....
Action< View >? ViewAdded
Occurs after a new View is added.
Represents a rendered view of a scene, combining a camera position with a viewport configuration to c...
Definition View.cs:14
A rectangular window on the render target with its own zoom and placement. Viewport never moves the w...
Definition Viewport.cs:10
Represents a game scene containing multiple layers of tiles, sprites, and game objects....
Definition Scene.cs:34
RectangleF GetWorldBoundsPx()
Computes a world-space pixel bounding rectangle that encloses all layers in the scene.
Definition Scene.cs:586