• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DemoBytom / DemoEngine / 13446237865

20 Feb 2025 10:55PM UTC coverage: 9.865% (-0.3%) from 10.129%
13446237865

push

coveralls.net

DemoBytom
Fixing FPS timer and adding crude UPS timer

FPS is now calculated per surface.
UPS is general.

227 of 2301 relevant lines covered (9.87%)

16997.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Demo.Engine.Core/Services/MainLoopServiceNew.cs
1
// Copyright © Michał Dembski and contributors.
2
// Distributed under MIT license. See LICENSE file in the root for more information.
3

4
using System.Diagnostics;
5
using System.Numerics;
6
using System.Threading.Channels;
7
using Demo.Engine.Core.Components.Keyboard;
8
using Demo.Engine.Core.Interfaces;
9
using Demo.Engine.Core.Interfaces.Rendering;
10
using Demo.Engine.Core.Interfaces.Rendering.Shaders;
11
using Demo.Engine.Core.Platform;
12
using Demo.Engine.Core.Requests.Keyboard;
13
using Demo.Engine.Core.ValueObjects;
14
using MediatR;
15
using Microsoft.Extensions.DependencyInjection;
16
using Microsoft.Extensions.Logging;
17
using Vortice.Mathematics;
18

19
namespace Demo.Engine.Core.Services;
20

21
internal sealed class MainLoopServiceNew
22
    : IMainLoopServiceNew,
23
      IDisposable
24
{
25
    private readonly ILogger<MainLoopServiceNew> _logger;
26
    private readonly ChannelWriter<StaThreadRequests> _channelWriter;
27
    private readonly IMediator _mediator;
28
    private readonly IShaderAsyncCompiler _shaderCompiler;
29
    private readonly IFpsTimer _fpsTimer;
30
    private readonly IServiceProvider _serviceProvider;
31
    private readonly IMainLoopLifetime _mainLoopLifetime;
32
    private ICube[] _drawables = [];
×
33
    private bool _disposedValue;
34

35
    public Task ExecutingTask { get; }
×
36

37
    public MainLoopServiceNew(
×
38
        ILogger<MainLoopServiceNew> logger,
×
39
        ChannelWriter<StaThreadRequests> channelWriter,
×
40
        IMediator mediator,
×
41
        IShaderAsyncCompiler shaderCompiler,
×
42
        IFpsTimer fpsTimer,
×
43
        IServiceProvider serviceProvider,
×
44
        IRenderingEngine renderingEngine,
×
45
        IMainLoopLifetime mainLoopLifetime)
×
46
    {
47
        _logger = logger;
×
48
        _channelWriter = channelWriter;
×
49
        _mediator = mediator;
×
50
        _shaderCompiler = shaderCompiler;
×
51
        _fpsTimer = fpsTimer;
×
52
        _serviceProvider = serviceProvider;
×
53
        _mainLoopLifetime = mainLoopLifetime;
×
54
        ExecutingTask = DoAsync(
×
55
            renderingEngine);
×
56
    }
×
57

58
    private async Task DoAsync(
59
        IRenderingEngine renderingEngine)
60
    {
61
        _ = await _shaderCompiler.CompileShaders(_mainLoopLifetime.Token);
×
62

63
        var keyboardHandle = await _mediator.Send(new KeyboardHandleRequest(), CancellationToken.None);
×
64
        var keyboardCharCache = await _mediator.Send(new KeyboardCharCacheRequest(), CancellationToken.None);
×
65

66
        _drawables =
×
67
        [
×
68
            _serviceProvider.GetRequiredService<ICube>(),
×
69
        ];
×
70

71
        var surfaces = new RenderingSurfaceId[]
×
72
        {
×
73
            await _channelWriter.CreateSurface(
×
74
                _mainLoopLifetime.Token),
×
75
            await _channelWriter.CreateSurface(
×
76
                _mainLoopLifetime.Token),
×
77
        };
×
78

79
        var previous = Stopwatch.GetTimestamp();
×
80
        var lag = TimeSpan.Zero;
×
81

82
        var msPerUpdate = TimeSpan.FromSeconds(1) / 60;
×
83

84
        var doEventsFunc = StaThreadRequests.DoEventsOk(RenderingSurfaceId.Empty);
×
85
        var doEventsOk = true;
×
86

87
        while (
×
88
            doEventsOk
×
89
            //&& IsRunning
×
90
            && !_mainLoopLifetime.Token.IsCancellationRequested)
×
91
        {
92
            var current = Stopwatch.GetTimestamp();
×
93
            var elapsed = Stopwatch.GetElapsedTime(previous, current);
×
94
            previous = current;
×
95
            lag += elapsed;
×
96

97
            //process input
98
            // TODO!
99

100
            while (lag >= msPerUpdate)
×
101
            {
102
                //Update
103
                // TODO - fix the UPS timer.. somehow :D
104
                _fpsTimer.StopUpdateTimer();
×
105
                foreach (var renderingSurfaceId in surfaces)
×
106
                {
107
                    if (!renderingEngine.TryGetRenderingSurface(
×
108
                        renderingSurfaceId,
×
109
                        out var renderingSurface))
×
110
                    {
111
                        _logger.LogCritical(
×
112
                            "Rendering surface {id} not found!",
×
113
                            renderingSurfaceId);
×
114
                        break;
×
115
                    }
116

117
                    await Update(
×
118
                          renderingSurface,
×
119
                          keyboardHandle,
×
120
                          keyboardCharCache);
×
121
                }
122
                lag -= msPerUpdate;
×
123
                _fpsTimer.StartUpdateTimer();
×
124
            }
125

126
            //Render
127
            foreach (var renderingSurfaceId in surfaces)
×
128
            {
129
                doEventsOk &= await _channelWriter.DoEventsOk(
×
130
                    renderingSurfaceId,
×
131
                    doEventsFunc,
×
132
                    _mainLoopLifetime.Token);
×
133

134
                using var scope = _fpsTimer.StartRenderingTimerScope(
×
135
                    renderingSurfaceId);
×
136

137
                Render(
×
138
                    renderingEngine,
×
139
                    renderingSurfaceId);
×
140
            }
×
141
        }
142
        _channelWriter.Complete();
×
143
        _mainLoopLifetime.Cancel();
×
144
    }
×
145

146
    private float _r, _g, _b = 0.0f;
147

148
    private float _sin = 0.0f;
149
    private bool _fullscreen = false;
150
    private bool _f11Pressed = false;
151

152
    private ValueTask Update(
153
        IRenderingSurface renderingSurface,
154
        KeyboardHandle keyboardHandle,
155
        KeyboardCharCache keyboardCharCache)
156
    {
157
        if (keyboardHandle.GetKeyPressed(VirtualKeys.OemOpenBrackets))
×
158
        {
159
            keyboardCharCache.Clear();
×
160
        }
161
        if (keyboardHandle.GetKeyPressed(VirtualKeys.OemCloseBrackets))
×
162
        {
163
            var str = keyboardCharCache?.ReadCache();
×
164
            if (!string.IsNullOrEmpty(str))
×
165
            {
166
                _logger.LogInformation(str);
×
167
            }
168
        }
169
        if (keyboardHandle.GetKeyPressed(VirtualKeys.Escape))
×
170
        {
171
            _mainLoopLifetime.Cancel();
×
172
            foreach (var drawable in _drawables)
×
173
            {
174
                (drawable as IDisposable)?.Dispose();
×
175
            }
176

177
            _drawables = [];
×
178
            return ValueTask.CompletedTask;
×
179
        }
180
        if (keyboardHandle.GetKeyPressed(VirtualKeys.F11))
×
181
        {
182
            if (!_f11Pressed)
×
183
            {
184
                _fullscreen = !_fullscreen;
×
185
            }
186
            _f11Pressed = true;
×
187
        }
188
        else
189
        {
190
            _f11Pressed = false;
×
191
        }
192

193
        if (keyboardHandle.GetKeyPressed(VirtualKeys.Back)
×
194
            && _drawables.ElementAtOrDefault(0) is IDisposable d)
×
195
        {
196
            Debug.WriteLine("Removing cube!");
197

198
            _drawables = _drawables.Length > 0
×
199
                ? _drawables[1..]
×
200
                : [];
×
201

202
            d?.Dispose();
×
203

204
            Debug.WriteLine("Cube removed!");
205
        }
206
        if (keyboardHandle.GetKeyPressed(VirtualKeys.Enter)
×
207
            && _drawables.Length < 2
×
208
            && _serviceProvider is not null)
×
209
        {
210
            Debug.WriteLine("Adding new Cube!");
211
            _drawables = new List<ICube>(_drawables)
×
212
                {
×
213
                    _serviceProvider.GetRequiredService<ICube>()
×
214
                }.ToArray();
×
215
            Debug.WriteLine("Cube added!!");
216
        }
217

218
        //if (_drawables.Length == 2)
219
        //{
220
        //    foreach (var drawable in _drawables)
221
        //    {
222
        //        (drawable as IDisposable)?.Dispose();
223
        //    }
224

225
        //    _drawables = Array.Empty<ICube>();
226
        //}
227
        //else if (_drawables.Length < 2 && _sp is not null /*&& _dontCreate == false*/)
228
        //{
229
        //    _drawables = new List<ICube>(_drawables)
230
        //        {
231
        //            _sp.GetRequiredService<ICube>()
232
        //        }.ToArray();
233
        //    //_dontCreate = true;
234
        //}
235

236
        //Share the rainbow
237
        _r = float.Sin((_sin + 0) * float.Pi / 180);
×
238
        _g = float.Sin((_sin + 120) * float.Pi / 180);
×
239
        _b = float.Sin((_sin + 240) * float.Pi / 180);
×
240

241
        //Taste the rainbow
242
        if (++_sin > 360)
×
243
        {
244
            _sin = 0;
×
245
        }
246
        _angleInRadians = (_angleInRadians + 0.01f) % TWO_PI;
×
247

248
        _drawables.ElementAtOrDefault(0)
×
249
            ?.Update(renderingSurface, Vector3.Zero, _angleInRadians);
×
250
        _drawables.ElementAtOrDefault(1)
×
251
            ?.Update(renderingSurface, new Vector3(0.5f, 0.0f, -0.5f), -_angleInRadians * 1.5f);
×
252

253
        return ValueTask.CompletedTask;
×
254
    }
255

256
    /// <summary>
257
    /// https://bitbucket.org/snippets/DemoBytom/aejA59/maps-value-between-from-one-min-max-range
258
    /// </summary>
259
    public static float Map(float value, float inMin, float inMax, float outMin, float outMax)
260
        => ((value - inMin) * (outMax - outMin) / (inMax - inMin)) + outMin;
×
261

262
    private float _angleInRadians = 0.0f;
263
    private const float TWO_PI = MathHelper.TwoPi;
264

265
    private void Render(
266
        IRenderingEngine renderingEngine,
267
        RenderingSurfaceId renderingSurfaceId)
268
        => renderingEngine.Draw(
×
269
            color: new Color4(_r, _g, _b, 1.0f),
×
270
            renderingSurfaceId: renderingSurfaceId,
×
271
            drawables: _drawables);
×
272

273
    private void Dispose(bool disposing)
274
    {
275
        if (!_disposedValue)
×
276
        {
277
            if (disposing)
×
278
            {
279
                foreach (var drawable in _drawables)
×
280
                {
281
                    if (drawable is IDisposable disposable)
×
282
                    {
283
                        disposable.Dispose();
×
284
                    }
285
                }
286
            }
287

288
            _disposedValue = true;
×
289
        }
290
    }
×
291

292
    public void Dispose()
293
    {
294
        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
295
        Dispose(disposing: true);
×
296
        GC.SuppressFinalize(this);
×
297
    }
×
298
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc