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