1 /**
2  * Copyright:       Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved
3  * Authors:         $(Gabriel Gheorghe)
4  * License:         $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007)
5  * Source:          $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/core/engine.d)
6  * Documentation:
7  * Coverage:
8 **/
9 module liberty.core.engine;
10 
11 import bindbc.glfw;
12 
13 import liberty.audio.backend;
14 import liberty.audio.buffer.factory;
15 import liberty.material.impl;
16 import liberty.input.impl;
17 import liberty.logger;
18 import liberty.camera;
19 import liberty.core.platform;
20 import liberty.scene;
21 import liberty.time;
22 import liberty.input.event;
23 import liberty.graphics.engine;
24 import liberty.graphics.buffer.factory;
25 
26 /**
27  * Core engine class containing engine base static functions.
28 **/
29 final abstract class CoreEngine {
30   private {
31     static EngineState engineState = EngineState.None;
32     static bool vsync;
33   }
34 
35   ///
36   static Scene scene;
37 
38   /**
39    * Initialize core engine features.
40   **/
41   static void initialize() {
42     Logger.initialize;
43     
44     // Set engine state to "starting"
45     changeState(EngineState.Starting);
46 
47     // Initialize other classes    
48     Platform.initialize;
49     AudioBackend.initialize;
50     GfxEngine.initialize;
51     Input.initialize;
52 
53     // Set engine state to "started"
54     changeState(EngineState.Started);
55   }
56 
57   /**
58    * Deinitialize core engine features.
59   **/
60   static void deinitialize() {
61     // Set engine state to "stopping"
62     changeState(EngineState.Stopping);
63 
64     // Deinitialize other classes
65     Platform.deinitialize;
66     IGfxBufferFactory.release;
67     IAudioBufferFactory.release;
68 
69     // Set engine state to "stopped"
70     changeState(EngineState.Stopped);
71 
72     Logger.deinitialize;
73   }
74 
75   /**
76    * Start the main loop of the application.
77   **/
78   static void run() {
79     // Set engine state to "running"
80     changeState(EngineState.Running);
81 
82     // Main loop
83     while (engineState != EngineState.ShouldQuit) {
84       // Process time
85       Time.processTime();
86 
87       // Update input and pull events
88       Input.update();
89       glfwPollEvents();
90       Platform.getWindow().resizeFrameBuffer();
91 
92       switch (engineState) with (EngineState) {
93         case Running:
94           scene.update;
95           scene.camera.preset.runImplicitProcess(scene.camera);
96 
97           //Input
98           //  .getMousePicker()
99           //  .update(scene.camera(), scene.getTree().getChild!Terrain("DemoTerrain"));
100 
101           break;
102         case Paused:
103           break; // TODO.
104         default:
105           Logger.warning("Unreachable.", typeof(this).stringof);
106           break;
107       }
108 
109       // Clear the screen
110       GfxEngine.backend.clearScreen;
111       
112       // Render to the screen
113       CoreEngine.scene.render;
114       
115       glfwSwapBuffers(Platform.getWindow.getHandle);
116 
117       if (Platform.getWindow.shouldClose)
118         changeState(EngineState.ShouldQuit);
119 
120       EventManager.updateLastMousePosition;
121     }
122 
123     // Main loop ended so engine shutdowns
124     deinitialize();
125   }
126 
127   /**
128    * Pause the entire application.
129   **/
130   static void pause() {
131     if (this.engineState == EngineState.Running) {
132       changeState(EngineState.Paused);
133     } else {
134       Logger.warning("Engine is not running", typeof(this).stringof);
135     }
136   }
137 
138   /**
139    * Resume the entire application.
140   **/
141   static void resume() {
142     if (this.engineState == EngineState.Paused) {
143       changeState(EngineState.Running);
144     } else {
145       Logger.warning("Engine is not paused", typeof(this).stringof);
146     }
147   }
148 
149   /**
150    * Shutdown the entire application.
151   **/
152   static void shutDown() {
153     engineState = EngineState.ShouldQuit;
154   }
155 
156   /**
157    * Force shutdown the entire application.
158   **/
159   static void forceShutDown(bool failure = false) {
160     import core.stdc.stdlib : exit;
161     deinitialize();
162     exit(failure);
163   }
164 
165   /**
166    *
167   **/
168   static void enableVSync() {
169     glfwSwapInterval(1);
170     vsync = true;
171   }
172 
173   /**
174    *
175   **/
176   static void disableVSync() {
177     glfwSwapInterval(0);
178     vsync = false;
179   }
180 
181   /**
182    *
183   **/
184   static bool isVSyncEnabled()  {
185     return vsync;
186   }
187 
188   package static void changeState(EngineState engineState) {
189     this.engineState = engineState;
190     Logger.info("Engine state changed to " ~ engineState, typeof(this).stringof);
191   }
192 }
193 
194 version (unittest)
195   /**
196    *
197   **/
198   mixin template EngineRun() {}
199 else
200   /**
201    *
202   **/
203   mixin template EngineRun(alias startFun, alias endFun) {
204     int main() {
205       CoreEngine.initialize();
206       startFun();
207       CoreEngine.run();
208       endFun();
209       return 0;
210     }
211   }
212 
213 /**
214  * Engine state enumeration.
215 **/
216 enum EngineState : string {
217   /**
218    * Engine is totally inactive.
219   **/
220   None = "None",
221 
222   /**
223    * Engine is starting.
224   **/
225   Starting = "Starting",
226 
227   /**
228    * Engine just started.
229   **/
230   Started = "Started",
231 
232   /**
233    * Engine is stopping.
234   **/
235   Stopping = "Stopping",
236 
237   /**
238    * Engine just stopped.
239   **/
240   Stopped = "Stopped",
241 
242   /**
243    * Engine is running.
244   **/
245   Running = "Running",
246 
247   /**
248    * Engine is paused.
249   **/
250   Paused = "Paused",
251 
252   /**
253    * Engine is in process of quiting.
254   **/
255   ShouldQuit = "ShouldQuit"
256 }