1 /// main YSGE module containing everything you need to make a game
2 module ysge.project;
3 
4 import std.file;
5 import std.path;
6 import std.string;
7 
8 public import bindbc.sdl;
9 public import ysge.util;
10 public import ysge.scene;
11 public import ysge.types;
12 public import ysge.gameObject;
13 public import ysge.objects.tileMap;
14 public import ysge.objects.simpleBox;
15 public import ysge.uiBase;
16 public import ysge.ui.text;
17 public import ysge.ui.button;
18 public import ysge.ui.terminal;
19 
20 /// used when something goes wrong in the project
21 class ProjectException : Exception {
22 	this(string msg, string file = __FILE__, size_t line = __LINE__) {
23 		super(msg, file, line);
24 	}
25 }
26 
27 /// main project class used for the game as a whole
28 class Project {
29 	bool          running; /// while true, update functions are called
30 	SDL_Window*   window;
31 	SDL_Renderer* renderer;
32 	TTF_Font*     font;
33 	Scene[]       scenes;
34 	Scene         currentScene;
35 	bool          usingLogicalRes; /// DON'T MODIFY!!!!
36 	Vec2!int      logicalRes; /// DON'T MODIFY!!!!
37 	Vec2!int      mousePos;
38 	ulong         frames; /// how many frames have passed since the game was started
39 
40 	/// called once at the start
41 	abstract void Init();
42 
43 	/// creates the window
44 	void InitWindow(string name, int w, int h) {
45 		SDLSupport support;
46 
47 		version (Windows) {
48 			support = loadSDL(cast(char*) (dirName(thisExePath()) ~ "/sdl2.dll"));
49 		}
50 		else {
51 			support = loadSDL();
52 		}
53 		
54 		if (support != sdlSupport) {
55 			throw new ProjectException("Failed to load SDL");
56 		}
57 	
58 		window = SDL_CreateWindow(
59 			toStringz(name), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
60 			w, h, SDL_WINDOW_RESIZABLE
61 		);
62 
63 		if (window is null) {
64 			throw new ProjectException("Failed to create window");
65 		}
66 
67 		renderer = SDL_CreateRenderer(
68 			window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
69 		);
70 
71 		if (renderer is null) {
72 			throw new ProjectException("Failed to create renderer");
73 		}
74 	}
75 
76 	/// initialises the text library
77 	void InitText() {
78 		SDLTTFSupport support;
79 	
80 		version (Windows) {
81 			support = loadSDLTTF(cast(char*) (dirName(thisExePath()) ~ "/sdl2_ttf.dll"));
82 		}
83 		else {
84 			support = loadSDLTTF();
85 		}
86 	
87 		if (support < SDLTTFSupport.v2_0_12) {
88 			throw new ProjectException("Failed to load SDL_TTF library");
89 		}
90 
91 		if (TTF_Init() < 0) {
92 			throw new ProjectException("Failed to initialise SDL_TTF");
93 		}
94 	}
95 
96 	void LoadFontFile(string path, int pointSize) {
97 		font = TTF_OpenFont(toStringz(path), pointSize);
98 
99 		if (font is null) {
100 			throw new ProjectException("Failed to load font");
101 		}
102 	}
103 
104 	void LoadFontData(ubyte[] data) {
105 		auto rw = SDL_RWFromMem(data.ptr, cast(int) data.length);
106 		font = TTF_OpenFontRW(rw, 1, 16);
107 
108 		if (font is null) {
109 			throw new ProjectException("Failed to load font");
110 		}
111 	}
112 
113 	/// gets the resolution of the window
114 	Vec2!int GetResolution() {
115 		if (usingLogicalRes) {
116 			return logicalRes;
117 		}
118 		else {
119 			Vec2!int ret;
120 
121 			SDL_GetWindowSize(window, &ret.x, &ret.y);
122 
123 			return ret;
124 		}
125 	}
126 
127 	/// sets the logical resolution of the window
128 	void SetResolution(uint w, uint h) {
129 		SDL_RenderSetLogicalSize(renderer, w, h);
130 		usingLogicalRes = true;
131 		logicalRes      = Vec2!int(w, h);
132 	}
133 
134 	/// gets the directory the game executable is in
135 	string GetGameDirectory() {
136 		return dirName(thisExePath());
137 	}
138 
139 	/// checks if a key is pressed
140 	bool KeyPressed(SDL_Scancode key) {
141 		auto keys = SDL_GetKeyboardState(null);
142 
143 		return keys[key]? true : false;
144 	}
145 
146 	/// adds a scene to the project scene array
147 	void AddScene(Scene scene) {
148 		scenes ~= scene;
149 	}
150 
151 	/// sets the current scene to a scene from the project scene array
152 	void SetScene(Scene scene) {
153 		currentScene = scene;
154 		currentScene.Init(this);
155 	}
156 
157 	/// sets the current scene to a scene from the project scene array
158 	void SetScene(size_t index) {
159 		currentScene = scenes[index];
160 		currentScene.Init(this);
161 	}
162 
163 	/// runs the game
164 	void Run() {
165 		running = true;
166 		Init();
167 
168 		if (currentScene is null) {
169 			throw new ProjectException("Scene not set");
170 		}
171 
172 		if (font is null) {
173 			throw new ProjectException("Font not loaded");
174 		}
175 
176 		while (running) {
177 			++ frames;
178 		
179 			currentScene.UpdateObjects(this);
180 			currentScene.Update(this);
181 			currentScene.UpdateCamera(this);
182 			currentScene.Render(this);
183 
184 			SDL_Event e;
185 			while (SDL_PollEvent(&e)) {
186 				switch (e.type) {
187 					case SDL_QUIT: {
188 						running = false;
189 						return;
190 					}
191 					case SDL_MOUSEMOTION: {
192 						mousePos = Vec2!int(e.motion.x, e.motion.y);
193 						break;
194 					}
195 					default: {
196 						if (currentScene.HandleUIEvent(this, e)) {
197 							continue;
198 						}
199 					
200 						currentScene.HandleEvent(this, e);
201 						break;
202 					}
203 				}
204 			}
205 		}
206 	}
207 }