1 module Engine.Core;
2 
3 import derelict.glfw3.glfw3;
4 import derelict.opengl3.gl;
5 public import gl3n.linalg;
6 import Engine.Entity;
7 import std.datetime;
8 import std.stdio;
9 import Engine.Input;
10 import Engine.Coroutine;
11 import Engine.Camera;
12 import Engine.Shader;
13 import Engine.Batch;
14 import std.parallelism;
15 import Engine.Options;
16 import Engine.System;
17 import Engine.Systems.UpdateSystem;
18 import Engine.Systems.AwakeSystem;
19 import Engine.Systems.StartSystem;
20 import Engine.Systems.BatchSystem;
21 import std.algorithm;
22 
23 public class Core
24 {	
25 	public static GLFWwindow* window;
26 	package static Entity[] entities;
27 	
28 	package static System[] systems;
29 	public shared static auto width = 800;
30 	public shared static auto height = 600;
31 	static Camera camera;
32 	static Shader shader;
33 
34 	public shared static double DeltaTime;
35 
36 	public static size_t EntitiesCount() {
37 		return entities.length;
38 	}
39 
40 	public static void AddEntity(Entity entity) {
41 		entities ~= entity;
42 		entity.arrayIndex = entities.length-1;
43 		entity.onActive();
44 		foreach (s; systems) {
45 			s.onEntityEnter(entity);
46 		}
47 	}
48 
49 	
50 	public static void AddSystem(System s) {
51 		systems ~= s;
52 		sort!"a.timing < b.timing"(systems);
53 		s.start();
54 		foreach (e; entities) {
55 			s.onEntityEnter(e);
56 		}
57 	}
58 
59 	public static bool RemoveSystem(System system) {
60 		foreach (index,s; systems) {
61 			if (system == s) {
62 				systems[index] = systems[systems.length-1];
63 				systems.length--;
64 				sort!"a.timing < b.timing"(systems);
65 				return true;
66 			}
67 		}
68 		return false;
69 	}
70 
71 	
72 	
73 
74 	public static void RemoveEntity(Entity entity) {
75 		if (entity.inScene) {
76 			foreach (s; systems) {
77 				s.onEntityLeave(entity);
78 			}
79 			auto index = entity.arrayIndex;
80 			auto replaceEntity = entities[entities.length-1];
81 			entities[index] = replaceEntity;
82 			replaceEntity.arrayIndex = index;
83 			entity.arrayIndex = -1;
84 			entities[entities.length-1] = null; //no idea how array resize works, but lets do it safe
85 			entities.length--;
86 		}
87 	}
88 
89 	public static void Start()
90 	{
91 		entities = new Entity[100];
92 		entities.length = 0;
93 
94 		systems ~= new AwakeSystem();
95 		systems ~= new StartSystem();
96 		systems ~= new UpdateSystem();
97 		systems ~= new BatchSystem();
98 
99 		
100 		DerelictGLFW3.load();
101 		DerelictGL3.load();
102 		
103 
104 		if(!glfwInit()) 
105 			throw new Exception("glfwInit failure");
106 
107 		
108 
109 		glfwWindowHint(GLFW_VERSION_MAJOR, 2); // Use OpenGL Core v3.2
110 		glfwWindowHint(GLFW_VERSION_MINOR, 1);
111 
112 		
113 		window = glfwCreateWindow(width,height,"SpaceSim",null,null);
114 		if (!window)
115 			throw new Exception("Failed to create window."); 
116 		
117 		
118 
119 		glfwMakeContextCurrent(window);
120 		DerelictGL3.reload(); 
121 
122 		glfwSwapInterval(0);		
123 		Input.Initialize();
124 		
125 		if (glMapBufferRange is null) {
126 			Options.useMapBufferRange = false;
127 		}
128 
129 		glDisable(GL_CULL_FACE);
130 		glClearDepth(1);
131 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
132 		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
133 		glDepthFunc(GL_NEVER);
134 		glEnable(GL_BLEND);
135 		glDepthMask(true);
136 		initShaders();
137 		
138 		//glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
139 		//glLineWidth(5);
140 
141 		foreach (s; systems) {
142 			s.start();
143 		}
144 	}
145 
146 	private static void initShaders() {
147 		const auto vertexSource = q"[
148 			#version 120
149 			// Input vertex data, different for all executions of this shader.
150 			attribute vec2 uv;
151 			attribute vec4 color;
152 			attribute vec3 vertex;
153 			attribute mat3 models;
154 			//uniform mat4 model;
155 			uniform mat4 projection;
156 			uniform mat4 view;
157 			varying vec2 UV;
158 			varying vec4 Color;
159 			//uniform sampler2D transforms;
160 
161 			const float PI = 3.14159265358979323846264 / 180.0;
162 
163 			void main(){
164 			vec3 rot = models[1]*PI;
165 
166 			mat3 rotm = mat3(1,0,0,
167 			0,cos(rot.x),-sin(rot.x),
168 			0,sin(rot.x),cos(rot.x))
169 			*
170 			mat3(cos(rot.y),0,sin(rot.y),
171 			0,1,0,
172 			-sin(rot.y),0,cos(rot.y))
173 			*
174 			mat3(cos(rot.z),-sin(rot.z),0,
175 			sin(rot.z),cos(rot.z),0,
176 			0,0,1);
177 
178 			vec3 pos = (rotm*(vertex*models[2]))+models[0];
179 
180 			gl_Position =  projection * view * vec4(pos, 1.0);
181 			UV = uv;
182 			Color = color;
183 			}
184 			]";	
185 
186 		
187 		const auto fragSource = q"[
188 			#version 120
189 			varying vec2 UV; 
190 			varying vec4 Color;
191 			uniform sampler2D texture;
192 
193 			void main()
194 			{
195 			gl_FragColor = texture2D(texture, UV) * Color;
196 			}
197 			]";	
198 
199 		shader = new Shader(vertexSource, fragSource);
200 		Core.shader = shader;
201 	}
202 
203 	public static void Terminate()
204 	{
205 		glfwTerminate() ; 
206 	}
207 
208 	public static void Run()
209 	{
210 		StopWatch sw;
211 		sw.start();
212 		while (!glfwWindowShouldClose(window)) 
213 		{ 		
214 			DeltaTime = cast(double)sw.peek().nsecs / 1000000000;	
215 			sw.reset();
216 
217 			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
218 
219 			StopWatch t1;
220 			t1.start();
221 
222 			t1.stop();
223 			//writeln("START", cast(double)sw.peek().nsecs / 1000000000);
224 
225 			t1.start();
226 			foreach (s; systems) {
227 				s.process();
228 			}
229 			t1.stop();
230 			//writeln("Update ", cast(double)sw.peek().nsecs / 1000000);
231 
232 			RunCoroutines();
233 
234 			//writeln("Draw ", cast(double)sw.peek().nsecs / 1000000000);
235 			//import core.memory;
236 			Input.Update();
237 			//GC.enable();
238 			glfwSwapBuffers(window);
239 			glfwPollEvents();
240 			//GC.disable();
241 		}
242 	}
243 }
244