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 6 * Documentation: 7 * Coverage: 8 */ 9 module liberty.core.engine; 10 import liberty.graphics.renderer; 11 import liberty.core.input; 12 import liberty.core.scenegraph; 13 import liberty.graphics.opengl; 14 import derelict.sdl2.sdl; 15 import liberty.core.input; 16 import liberty.math; 17 import liberty.graphics.postprocessing; 18 import std.math, std.random; 19 import derelict.util.loader; 20 import liberty.core.imaging; 21 import liberty.core.time : time; 22 import liberty.core.model : Models; 23 import liberty.graphics.material : Materials; 24 import liberty.core.system; 25 import liberty.core.utils : Singleton, IService; 26 /// 27 class CoreEngineException : Exception { 28 /// 29 @safe pure nothrow this(string message, string file = __FILE__, size_t line = __LINE__, Throwable next = null) { 30 super(message, file, line, next); 31 } 32 } 33 private { 34 Platform _platformApi; 35 SDL2Window _mainWindow; 36 } 37 /// 38 Platform platform() { 39 return _platformApi; 40 } 41 /// 42 SDL2Window mainWindow() { 43 return _mainWindow; 44 } 45 /// 46 struct WindowInfo { 47 /// 48 string title = "Liberty Engine " ~ import("ENGINE.VER"); 49 /// 50 int width = 1280; 51 /// 52 int height = 720; 53 /// 54 double ratio() { return width / cast(double)height; } 55 } 56 /// 57 class CoreEngine : Singleton!CoreEngine, IService { 58 private { 59 bool _serviceRunning; 60 float _deltaTime = 0.0f; 61 float lastFrame = 0.0f; 62 WindowInfo _windowInfo; 63 Scene _activeScene; 64 Image _imageAPI; // TODO. 65 } 66 /// 67 void activeScene(Scene scene) nothrow { // TODO: package. 68 _activeScene = scene; 69 } 70 /// 71 Scene activeScene() nothrow { 72 return _activeScene; 73 } 74 /// 75 Platform platform() { return _platformApi; } 76 /// 77 SDL2Window mainWindow() { return _mainWindow; } 78 /// 79 Image imageAPI() { return _imageAPI; } 80 /// Start CoreEngine service. 81 void startService() @trusted { 82 version (__Logger__) { 83 Logger.startService(); 84 } 85 GraphicsEngine.get.startService(); 86 _initWindow(); 87 _mainWindow.title = _windowInfo.title; 88 _imageAPI = new Image(); // TODO. 89 Materials.get.load(); 90 Models.get.load(); 91 _serviceRunning = true; 92 } 93 /// Stop CoreEngine service. 94 void stopService() @trusted { 95 GraphicsEngine.get.stopService(); 96 version (__Logger__) { 97 Logger.stopService(); 98 } 99 collectGarbage(); 100 _serviceRunning = false; 101 } 102 /// Restart CoreEngine service. 103 void restartService() @trusted { 104 stopService(); 105 startService(); 106 } 107 /// Returns true if CoreEngine service is running. 108 bool isServiceRunning() pure nothrow const @safe @nogc { 109 return _serviceRunning; 110 } 111 /// 112 void windowInfo(WindowInfo win_info = WindowInfo()) { 113 _windowInfo = win_info; 114 } 115 /// 116 void windowInfo(int width, int height) { 117 _windowInfo.width = width; 118 _windowInfo.height = height; 119 } 120 /// 121 WindowInfo windowInfo() nothrow @safe @nogc @property { 122 return _windowInfo; 123 } 124 /// 125 void runMainLoop() { 126 while(!_platformApi.shouldQuit()) { 127 if (_shouldQuitOnKey && Input.get.isKeyDown(KeyCode.Esc)) { 128 break; 129 } 130 Input.get._isMouseMoving = false; 131 Input.get._isMouseWheeling = false; 132 _platformApi.processEvents(); 133 const float currentFrame = time(); 134 _deltaTime = currentFrame - lastFrame; 135 lastFrame = currentFrame; 136 if (_activeScene.isRegistered()) { 137 _activeScene.update(_deltaTime); 138 _activeScene.process(); 139 GraphicsEngine.get.render(); 140 } 141 } 142 } 143 bool _shouldQuitOnKey; 144 /// 145 void shouldQuitOnKey(KeyCode key) { 146 _shouldQuitOnKey = true; 147 } 148 /// 149 float deltaTime() nothrow { 150 return _deltaTime; 151 } 152 private void _initWindow() { 153 _platformApi = new Platform(SharedLibVersion(2, 0, 6)); 154 _platformApi.subSystemInit(SDL_INIT_VIDEO); 155 _platformApi.subSystemInit(SDL_INIT_EVENTS); 156 version (__OpenGL__) { 157 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 158 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); 159 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 160 _mainWindow = new SDL2Window( 161 _platformApi, 162 SDL_WINDOWPOS_CENTERED, 163 SDL_WINDOWPOS_CENTERED, 164 _windowInfo.width, 165 _windowInfo.height, 166 SDL_WINDOW_OPENGL 167 ); 168 GraphicsEngine.get.backend.reload(); 169 } else version (__Vulkan__) { 170 _mainWindow = new SDL2Window( 171 _platformApi, 172 SDL_WINDOWPOS_CENTERED, 173 SDL_WINDOWPOS_CENTERED, 174 _windowInfo.width, 175 _windowInfo.height, 176 SDL_WINDOW_VULKAN 177 ); 178 } 179 } 180 /// 181 void gcEnabled(bool enabled = true) { 182 import core.memory : GC; 183 enabled ? GC.enable() : GC.disable(); 184 } 185 /// 186 void collectGarbage() { 187 import core.memory : GC; 188 GC.collect(); 189 } 190 } 191 /// 192 immutable NativeServices = q{ 193 void main() { 194 CoreEngine.get.startService(); 195 initSettings(); 196 initScene(); 197 CoreEngine.get.runMainLoop(); 198 CoreEngine.get.stopService(); 199 } 200 };