1 module polyplex.core.window;
2 import polyplex.utils.sdlbool;
3 public import polyplex.core.render;
4 static import polyplex;
5 
6 import derelict.sdl2.sdl;
7 import derelict.sdl2.image;
8 import polyplex.math;
9 import polyplex.utils.logging;
10 import std.stdio;
11 import std..string;
12 import std.conv;
13 
14 
15 public enum WindowPosition {
16 	Center = -1,
17 	Undefined = 0
18 }
19 
20 public class GameWindow {
21 	private int width;
22 	private int height;
23     private SDL_Window* window;
24 	private Renderer renderer;
25 	private string start_title;
26 	private Rectangle start_bounds;
27 
28 	public @property int Width() { return this.width; }
29 	public @property int Height() { return this.height; }
30 
31 	public @property Renderer Backend() { return this.renderer; }
32 
33 	/*
34 		Gets whenever the window is visible
35 	*/
36     public @property bool Visible() { return (this.window != null); }
37 
38 	//Resizing
39 	public @property bool AllowResizing() {
40 		SDL_WindowFlags flags = SDL_GetWindowFlags(window);
41 		return ((flags & SDL_WINDOW_RESIZABLE) > 0);
42 	}
43 	public @property void AllowResizing(bool allow) { SDL_SetWindowResizable(this.window, ToSDL(allow)); }
44 
45 	//Vertical Syncronization
46 	public @property VSyncState VSync() {
47 		return renderer.VSync;
48 	}
49 	public @property void VSync(VSyncState allow) { renderer.VSync = allow; }
50 
51 
52 	//Borderless
53 	public @property bool Borderless() {
54 		SDL_WindowFlags flags = SDL_GetWindowFlags(window);
55 		return ((flags & SDL_WINDOW_BORDERLESS) > 0);
56 	}
57 
58 	public @property void Borderless(bool i) { SDL_SetWindowBordered(this.window, ToSDL(!i)); }
59 
60 	//Title
61 	public @property string Title() { return to!string(SDL_GetWindowTitle(this.window)); }
62 	public @property void Title(string t) { return SDL_SetWindowTitle(this.window, t.toStringz); }
63 
64 	//Brightness
65 	public @property float Brightness() { return SDL_GetWindowBrightness(this.window); }
66 	public @property void Brightness(float b) { SDL_SetWindowBrightness(this.window, b); }
67 
68 	//Backend
69 	public @property polyplex.GraphicsBackend GLBackend() { return polyplex.ChosenBackend; }
70 
71 	//Fullscreen
72 	public @property bool Fullscreen() {
73 		SDL_WindowFlags flags = SDL_GetWindowFlags(window);
74 		return ((flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) > 0);
75 	}
76 
77 	public @property void Fullscreen(bool i) {
78 		if (!i) {
79 			//Windowed.
80 			SDL_SetWindowFullscreen(this.window, 0);
81 			return;
82 		}
83 		if (Borderless) {
84 			//Fullscreen Borderless
85 			SDL_SetWindowFullscreen(this.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
86 			return;
87 		}
88 		//Fullscreen
89 		SDL_SetWindowFullscreen(this.window, SDL_WINDOW_FULLSCREEN);
90 	}
91 
92 	//Renderer
93 	public @property Renderer Drawing() { return this.renderer; }
94 
95 	/*
96 		Returns the raw placement of the window.
97 		Use RealPlacement if you want your application to be dpi aware.
98 	*/
99 	public @property Rectangle Placement() {
100 		int x, y;
101 		SDL_GetWindowPosition(this.window, &x, &y);
102 		return new Rectangle(x, y, width, height);
103 	}
104 
105 	/**
106 		Returns the position of the window.
107 	*/
108 	public @property Vector2 Position() {
109 		Rectangle r = Placement();
110 		return Vector2(r.X, r.Y);
111 	}
112 
113 	/**
114 		Allows you to set the position of the window.
115 	*/
116 	public @property void Position(Vector2 pos) {
117 		SDL_SetWindowPosition(this.window, cast(int)pos.X, cast(int)pos.Y);
118 	}
119 
120     this(string name, Rectangle bounds) {
121         if (!SDL_Init(SDL_INIT_EVERYTHING) < 0) {
122             Logger.Fatal("Initialization of SDL2 failed!...\n{0}", SDL_GetError());
123         }
124 
125 		//Set info.
126         this.start_bounds = bounds;
127 		this.start_title = name;
128 
129 		//Cap info.
130 		if (this.start_bounds is null) this.start_bounds = new Rectangle(WindowPosition.Undefined, WindowPosition.Undefined, 640, 480);
131 		if (this.start_bounds.X == WindowPosition.Center) this.start_bounds.X = SDL_WINDOWPOS_CENTERED;
132 		if (this.start_bounds.Y == WindowPosition.Center) this.start_bounds.Y = SDL_WINDOWPOS_CENTERED;
133 		if (this.start_bounds.X == WindowPosition.Undefined) this.start_bounds.X = SDL_WINDOWPOS_UNDEFINED;
134 		if (this.start_bounds.Y == WindowPosition.Undefined) this.start_bounds.Y = SDL_WINDOWPOS_UNDEFINED;
135 		if (this.start_bounds.Width == WindowPosition.Undefined) this.start_bounds.Width = 640;
136 		if (this.start_bounds.Height == WindowPosition.Undefined) this.start_bounds.Height = 480;
137     }
138 
139 	this (Rectangle bounds) {
140 		this("My Game", bounds);
141 	}
142 
143 	this() {
144 		this(new Rectangle(WindowPosition.Undefined, WindowPosition.Undefined, 640, 480));
145 	}
146 
147     ~this() {
148 		if (this.window != null) Close();
149         SDL_Quit();
150     }
151 
152 	/**
153 		Triggers an window info update.
154 	*/
155 	void UpdateInfo() {
156 		SDL_GetWindowSize(this.window, &this.width, &this.height);
157 	}
158 
159 	/**
160 		Closes the window.
161 	*/
162 	void Close() {
163 		SDL_DestroyWindow(this.window);
164 		IMG_Quit();
165 		//Explicitly destroy window.
166 		destroy(this.window);
167 	}
168 
169 	/**
170 		Puts the window in focus (ONLY WORKS ON SOME PLATFORMS!)
171 	*/
172 	void Focus() {
173 		SDL_RaiseWindow(this.window);
174 	}
175 
176 	/**
177 		TODO
178 		Sets the icon for the window.
179 	*/
180 	void SetIcon() {
181 		//TODO: When rendering is there, set icon.
182 	}
183 
184 	/**
185 		Swaps the rendering buffer.
186 	*/
187 	void SwapBuffers() {
188 		this.renderer.SwapBuffers();
189 	}
190 
191 	/**
192 		Shows the window.
193 	*/
194     void Show() {
195 		Logger.Debug("Spawning window...");
196 		if (polyplex.ChosenBackend == polyplex.GraphicsBackend.Vulkan) this.window = SDL_CreateWindow(this.start_title.dup.ptr, this.start_bounds.X, this.start_bounds.Y, this.start_bounds.Width, this.start_bounds.Height, SDL_WINDOW_VULKAN);
197 		else this.window = SDL_CreateWindow(this.start_title.toStringz, this.start_bounds.X, this.start_bounds.Y, this.start_bounds.Width, this.start_bounds.Height, SDL_WINDOW_OPENGL);
198 		this.renderer = CreateBackendRenderer(this);
199 		this.renderer.Init(this.window);
200 		if (this.window == null) {
201 			destroy(this.window);
202 			Logger.Fatal("Window creation error: {0}", SDL_GetError());
203 		}
204 		// Enable VSync by default.
205 		VSync = VSyncState.VSync;
206 		// Focus window
207 		this.Focus();
208     }
209 }