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 };