RavEngine
Loading...
Searching...
No Matches
App.hpp
1#pragma once
2#include <chrono>
3#include <concurrentqueue.h>
4#include "SpinLock.hpp"
5#include <taskflow/taskflow.hpp>
6#include "NetworkManager.hpp"
7#if !RVE_SERVER
8#include <RGL/Types.hpp>
9#include "RenderTargetCollection.hpp"
10#include "AudioSnapshot.hpp"
11#endif
12#include <optional>
13#include "GetApp.hpp"
14
15#define SINGLE_THREADED 0
16
17namespace RavEngine {
18
19struct RenderEngine;
20struct VirtualFilesystem;
21struct FrameData;
22struct Window;
23struct AudioPlayer;
24
25 struct AppConfig {
26 enum class RenderBackend {
27 Metal,
28 DirectX12,
29 Vulkan,
30 WebGPU,
31 AutoSelect
32 } preferredBackend = RenderBackend::AutoSelect;
33 };
34
35 typedef std::chrono::high_resolution_clock clocktype;
36 typedef std::chrono::duration<double, std::micro> timeDiff;
37 typedef std::chrono::seconds deltaSeconds;
38 typedef std::chrono::time_point<clocktype> timePoint;
39
40 class InputManager;
41 class World;
42
43 class App {
44 friend class NetworkManager;
45#if RVE_SERVER
46 constexpr static std::chrono::duration<double> min_tick_time{1.0/60};
47#endif
48
49#if !RVE_SERVER
50 std::unique_ptr<RenderEngine> Renderer;
51#endif
52 std::unique_ptr<VirtualFilesystem> Resources;
53 public:
54 App();
55 virtual ~App();
56
57 // set this to true in app constructor if XR is desired
58 bool wantsXR = false;
59
63 virtual void OnFatal(const std::string_view msg){}
64
68 virtual void OnDropAudioWorklets(uint32_t ndropped);
69
70 // Override to disable audio. If false, audio backend will not be initialized and audio player threads will not be created.
71 virtual bool NeedsAudio() const {
72 return true;
73 }
74
75 bool GetAudioActive() const;
76
77 // Override to disable networking. If true, networking backend and associated threads will be created.
78 virtual bool NeedsNetworking() const {
79 return false;
80 }
81
85 void Quit();
86
90 int run(int argc, char** argv);
91
92 constexpr static float evalNormal = 60; //normal speed is 60 hz
93
97 inline double GetCurrentTime(){
98 return time;
99 };
100
101 //number of cores on device
102 const int numcpus = std::thread::hardware_concurrency();
103
104 //global thread pool, threads = logical processors on CPU
105 tf::Executor executor{
106#if SINGLE_THREADED
107 1 // use main thread only on emscripten
108#else
109 std::max<size_t>(std::thread::hardware_concurrency() - 2, 2) // for audio - TODO: make configurable
110#endif
111 };
112
113 //networking interface
114 NetworkManager networkManager;
115
116 inline VirtualFilesystem& GetResources(){
117 return *Resources.get();
118 }
119#if !RVE_SERVER
120 inline RenderEngine& GetRenderEngine(){
121 return *Renderer.get();
122 }
123#endif
124#if !RVE_SERVER
125 inline auto& GetAudioPlayer(){
126 return player;
127 }
128#endif
129
130 inline bool HasRenderEngine(){
131#if !RVE_SERVER
132 return static_cast<bool>(Renderer);
133#else
134 return false;
135#endif
136 }
137
149 template<typename T>
150 constexpr inline void DispatchMainThread(const T& f){
151 main_tasks.enqueue(f);
152 }
153
157 float CurrentTPS();
158 float GetCurrentFPSScale() const{
159 return currentScale;
160 }
161#if !RVE_SERVER
162 Ref<InputManager> inputManager;
163#endif
164
169 void SetRenderedWorld(Ref<World> newWorld);
170
175 void AddWorld(Ref<World> world);
176
181 void RemoveWorld(Ref<World> world);
182
186 void RemoveAllWorlds();
187
193 void AddReplaceWorld(Ref<World> oldWorld, Ref<World> newWorld);
194
195#if !RVE_SERVER
196
202 void SetWindowTitle(const char* title);
203#endif
204
205 std::optional<Ref<World>> GetWorldByName(const std::string& name);
206
207 auto GetCurrentRenderWorld() {
208 return renderWorld;
209 }
210
211
212#if !RVE_SERVER
214 uint8_t current = 0, inactive = 0, render = 0;
215 };
216 static AudioBitsetUnpack UnpackAudioBitset(uint8_t audioCurrentBitset) {
217 uint8_t currentIdx = (audioCurrentBitset & audioCurrentMask) >> audioCurrentShift;
218 uint8_t inactiveIdx = (audioCurrentBitset & audioInactiveMask) >> audioInactiveShift;
219 uint8_t renderIdx = (audioCurrentBitset & audioRenderMask) >> audioRenderShift;
220
221 return { currentIdx, inactiveIdx, renderIdx };
222 }
223
224 static uint8_t RepackAudioBitset(AudioBitsetUnpack values) {
225 uint8_t audioNextBitset = 0;
226 audioNextBitset |= values.current << audioCurrentShift;
227 audioNextBitset |= values.inactive << audioInactiveShift;
228 audioNextBitset |= values.render << audioRenderShift;
229
230 return audioNextBitset;
231 }
232
233 inline void SwapCurrrentAudioSnapshot(){
234 // swapping currentIdx with inactiveIdx
235 uint8_t audioCurrentBitset = audioswapbitset.load();
236 uint8_t audioNextBitset = audioCurrentBitset;
237
238 auto makeNextBitset = [&audioCurrentBitset]{
239 auto indices = UnpackAudioBitset(audioCurrentBitset);
240
241 std::swap(indices.current, indices.inactive);
242
243 uint8_t audioNextBitset = RepackAudioBitset(indices);
244
245 // set the audioAvailable flag
246 audioNextBitset |= 1 << audioAvailableShift;
247
248 return audioNextBitset;
249 };
250 audioNextBitset = makeNextBitset();
251
252 while (!audioswapbitset.compare_exchange_weak(audioCurrentBitset, audioNextBitset, std::memory_order_release, std::memory_order_relaxed)){
253 audioNextBitset = makeNextBitset();
254 }
255 }
256 inline void SwapRenderAudioSnapshotIfNeeded(){
257 // swapping inactive with render
258 auto audioCurrentBitset = audioswapbitset.load();
259 if (NewAudioAvailable(audioCurrentBitset)) {
260 uint8_t audioNextBitset = audioCurrentBitset;
261 auto makeNextBitset = [&audioCurrentBitset] {
262 auto indices = UnpackAudioBitset(audioCurrentBitset);
263 std::swap(indices.inactive, indices.render);
264 // newAudioAvailable is set to false automatically because repackAudioBitset sets all bits to 0
265 uint8_t audioNextBitset = RepackAudioBitset(indices);
266 return audioNextBitset;
267 };
268 audioNextBitset = makeNextBitset();
269
270 while (!audioswapbitset.compare_exchange_weak(audioCurrentBitset, audioNextBitset, std::memory_order_release, std::memory_order_relaxed)){
271 audioNextBitset = makeNextBitset();
272 }
273 }
274 }
275 inline AudioSnapshot* GetCurrentAudioSnapshot(){
276 auto bitset = audioswapbitset.load();
277 auto idx = (bitset & audioCurrentMask) >> audioCurrentShift;
278 auto ptr = &audioSnapshots[idx];
279 return ptr;
280 }
281 inline AudioSnapshot* GetRenderAudioSnapshot(){
282 auto bitset = audioswapbitset.load();
283 auto idx = (bitset & audioRenderMask) >> audioRenderShift;
284 auto ptr = &audioSnapshots[idx];
285 return ptr;
286 }
287 inline static bool NewAudioAvailable(uint8_t currentBitset) {
288 return (currentBitset & audioAvailableMask); // 0 = false, any other = true
289 }
290#endif
291
292 private:
293
294 void Tick();
295
296 float currentScale = 0.01f;
297
298 Ref<World> renderWorld;
299
300 ConcurrentQueue<Function<void(void)>> main_tasks;
301
302 locked_hashset<Ref<World>,SpinLock> loadedWorlds;
303#if !RVE_SERVER
304 Array<AudioSnapshot, 3> audioSnapshots;
305 constexpr static uint8_t
306 audioCurrentShift = 0, audioInactiveShift = 2, audioRenderShift = 4, audioAvailableShift = 6,
307 audioCurrentMask = 0b00000011,
308 audioInactiveMask = (audioCurrentMask << audioInactiveShift),
309 audioRenderMask = (audioCurrentMask << audioRenderShift),
310 audioAvailableMask = 1 << audioAvailableShift
311 ;
312
313 std::atomic<uint8_t> audioswapbitset = (0 << audioCurrentShift) | (1 << audioInactiveShift) | (2 << audioRenderShift);
314#endif
315 protected:
316#if !RVE_SERVER
317 RGLDevicePtr device;
318 std::unique_ptr<Window> window;
319 RenderViewCollection mainWindowView;
320
321 std::vector<RenderViewCollection> xrRenderViewCollections;
322#endif
323
324 virtual AppConfig OnConfigure(int argc, char** argv) { return AppConfig{}; }
325#if !RVE_SERVER
326 //plays the audio generated in worlds
327 std::unique_ptr<AudioPlayer> player;
328#endif
329
335 virtual void OnStartup(int argc, char** argv) {}
339 virtual int OnShutdown() { return 0; };
340
341 //last frame time, frame delta time, framerate scale, maximum frame time
342 timePoint lastFrameTime;
343 timeDiff deltaTimeMicroseconds{0};
344 const timeDiff maxTimeStep = std::chrono::milliseconds((long)1000);
345
346 double time = 0;
347 public:
348#if !RVE_SERVER
349 auto GetDevice() {
350 return device;
351 }
352 const auto& GetMainWindow() const{
353 return window;
354 }
355#endif
356 };
357}
358
359
Definition App.hpp:43
virtual void OnDropAudioWorklets(uint32_t ndropped)
Definition App_priv.hpp:629
double GetCurrentTime()
Definition App.hpp:97
int run(int argc, char **argv)
Definition App_priv.hpp:121
virtual void OnFatal(const std::string_view msg)
Definition App.hpp:63
virtual int OnShutdown()
Definition App.hpp:339
float CurrentTPS()
Definition App_priv.hpp:477
void AddReplaceWorld(Ref< World > oldWorld, Ref< World > newWorld)
Definition App_priv.hpp:545
void RemoveWorld(Ref< World > world)
Definition App_priv.hpp:521
void SetRenderedWorld(Ref< World > newWorld)
Definition App_priv.hpp:486
virtual void OnStartup(int argc, char **argv)
Definition App.hpp:335
constexpr void DispatchMainThread(const T &f)
Definition App.hpp:150
void SetWindowTitle(const char *title)
Definition App_priv.hpp:612
void AddWorld(Ref< World > world)
Definition App_priv.hpp:504
void Quit()
Definition App_priv.hpp:554
void RemoveAllWorlds()
Definition App_priv.hpp:533
Definition InputManager.hpp:137
Definition NetworkManager.hpp:15
Definition World.hpp:181
Definition concurrentqueue.h:747
uint8 uint8_t
Definition fwd.hpp:103
Definition Animation.hpp:6
Definition App.hpp:25
Definition App.hpp:213