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 }