1 module cat.wheel.graphics;
2 
3 import std.conv : to;
4 import std.string;
5 import bindbc.sdl;
6 
7 import cat.wheel.except;
8 import cat.wheel.structs;
9 
10 /**
11  * Represents a window managed by SDL
12  */
13 class Window {
14 public:
15 
16 	/**
17 	 * Constructs a new wrapped SDL_Window struct.
18 	 * Params:
19 	 *   title = The title of the window, default ""
20 	 *   x = The initial x position of the window on the screen, from the left
21 	 *   y = The initial y position of the window on the screen, from the top
22 	 *   w = The initial width of the window
23 	 *   h = The initial height of the window
24 	 *   flags = A number of window flags to initialise the window with
25 	 */
26 	this(
27 		string title = "",
28 		int x = SDL_WINDOWPOS_UNDEFINED,
29 		int y = SDL_WINDOWPOS_UNDEFINED,
30 		int w = 0,
31 		int h = 0,
32 		SDL_WindowFlags flags = cast(SDL_WindowFlags) 0)
33 	{
34 		_window = SDL_CreateWindow(title.toStringz(), x, y, w, h, flags).objCheck;
35 	}
36 
37 	~this() nothrow {
38 		SDL_DestroyWindow(_window);
39 	}
40 
41 	/**
42 	 * The x position of the managed window
43 	 */
44 	@property int x() nothrow {
45 		int *x;
46 		SDL_GetWindowPosition(_window, x, null);
47 		return *x;
48 	}
49 
50 	///
51 	@property void x(int x) nothrow {
52 		SDL_SetWindowPosition(_window, x, this.y);
53 	}
54 
55 	/**
56 	 * The y position of the managed window
57 	 */
58 	@property int y() nothrow {
59 		int *y;
60 		SDL_GetWindowPosition(_window, null, y);
61 		return *y;
62 	}
63 
64 	///
65 	@property void y(int y) nothrow {
66 		SDL_SetWindowPosition(_window, this.x, y);
67 	}
68 
69 	/**
70 	 * The width of the managed window
71 	 */
72 	@property int width() nothrow {
73 		int *w;
74 		SDL_GetWindowSize(_window, w, null);
75 		return *w;
76 	}
77 
78 	///
79 	@property void width(int w) nothrow {
80 		SDL_SetWindowSize(_window, w, height);
81 	}
82 
83 	/**
84 	 * The height of the managed window
85 	 */
86 	@property int height() nothrow {
87 		int *h;
88 		SDL_GetWindowSize(_window, null, h);
89 		return *h;
90 	}
91 
92 	///
93 	@property void height(int h) nothrow {
94 		SDL_SetWindowSize(_window, width, h);
95 	}
96 
97 	/**
98 	 * The title of the managed window
99 	 */
100 	@property string title() nothrow {
101 		return _title;
102 	}
103 
104 	///
105 	@property void title(string t) nothrow {
106 		_title = t;
107 		SDL_SetWindowTitle(_window, _title.toStringz());
108 	}
109 
110 	/**
111 	 * The wrapped window
112 	 */
113 	@property SDL_Window* window() nothrow {
114 		return _window;
115 	}
116 
117 private:
118 	SDL_Window* _window;
119 	string _title;
120 }
121 
122 /// Wrapper for an SDL_Surface
123 struct Surface {
124 	SDL_Surface *sdl;
125 
126 	~this() {
127 		if (sdl != null) SDL_FreeSurface(sdl);
128 	}
129 }
130 
131 class Graphics {
132 public:
133 
134 	/**
135 	 * Creates a new wrapped SDL_Renderer
136 	 * Params:
137 	 *   w = The window to create the renderer for
138 	 *   flags = The flags to look for when initialising a renderer
139 	 *   index = The index of the renderer to initialise, leave blank (-1) for the first matching the specified flags
140 	 */
141 	this(Window w, SDL_RendererFlags flags = cast(SDL_RendererFlags) 0, int index = -1) {
142 		_renderer = SDL_CreateRenderer(w._window, index, flags).objCheck;
143 	}
144 
145 	/**
146 	 * Creates a software SDL renderer
147 	 * Params:
148 	 *   s = The surface for this renderer to draw to
149 	 */
150 	this(Surface s) {
151 		_renderer = SDL_CreateSoftwareRenderer(s.sdl).objCheck;
152 	}
153 
154 	~this() {
155 		SDL_DestroyRenderer(_renderer);
156 	}
157 
158 	void drawPoint(Vector2 pos) {
159 		SDL_RenderDrawPoint(_renderer, pos.x, pos.y).check;
160 	}
161 
162 	void drawPoints(Vector2[] points) {
163 		SDL_Point[] sdl = new SDL_Point[points.length];
164 		for (int i = 0; i < points.length; i++) {
165 			sdl[i] = cast(SDL_Point) points[i];
166 		}
167 
168 		SDL_RenderDrawPoints(_renderer, sdl.ptr, points.length.to!int).check;
169 	}
170 
171 	void drawLine(Vector2 pos1, Vector2 pos2) {
172 		SDL_RenderDrawLine(_renderer, pos1.x, pos1.y, pos2.x, pos2.y).check;
173 	}
174 
175 	void drawLines(Vector2[2][] lines) {
176 		SDL_Point[] sdl = new SDL_Point[lines.length * 2];
177 		for (int i = 0; i < lines.length * 2; i++) {
178 			sdl[i] = cast(SDL_Point) lines[i/2][i%2];
179 		}
180 
181 		SDL_RenderDrawLines(_renderer, sdl.ptr, sdl.length.to!int).check;
182 	}
183 
184 	void drawRect(Rect rect) {
185 		const(SDL_Rect) c = rect.sdl;
186 		SDL_RenderDrawRect(_renderer, &c).check;
187 	}
188 
189 	void drawRects(Rect[] rects) {
190 		SDL_Rect[] sdl;
191 		for (int i = 0; i < rects.length; i++) {
192 			sdl[i] = rects[i].sdl;
193 		}
194 
195 		const(SDL_Rect)[] sdlc = sdl;
196 		SDL_RenderDrawRects(_renderer, sdlc.ptr, sdl.length.to!int).check;
197 	}
198 
199 	void fillRect(Rect rect) {
200 		const(SDL_Rect) c = rect.sdl;
201 		SDL_RenderFillRect(_renderer, &c).check;
202 	}
203 
204 	void fillRects(Rect[] rects) {
205 		SDL_Rect[] sdl;
206 		for (int i = 0; i < rects.length; i++) {
207 			sdl[i] = rects[i].sdl;
208 		}
209 
210 		const(SDL_Rect)[] sdlc = sdl;
211 		SDL_RenderFillRects(_renderer, sdlc.ptr, sdl.length.to!int).check;
212 	}
213 
214 	void drawTexture(SDL_Texture* t, Rect src, Rect dest) {
215 		SDL_RenderCopy(_renderer, t, &src.sdl, &dest.sdl);
216 	}
217 
218 	SDL_Texture* createTextureFrom(Surface s) {
219 		return SDL_CreateTextureFromSurface(_renderer, s.sdl).objCheck;
220 	}
221 
222 	void render() {
223 		SDL_RenderPresent(_renderer);
224 	}
225 
226 	void clear() {
227 		SDL_RenderClear(_renderer).check;
228 	}
229 
230 	///
231 	@property clipRect() nothrow {
232 		return _clipRect;
233 	}
234 
235 	///
236 	@property clipRect(Rect clip) nothrow {
237 		_clipRect = clip;
238 		return SDL_RenderSetClipRect(_renderer, &_clipRect.sdl);
239 	}
240 
241 	///
242 	@property color() nothrow {
243 		return _drawColour;
244 	}
245 
246 	///
247 	@property color(Color c) nothrow {
248 		_drawColour = c;
249 		return SDL_SetRenderDrawColor(_renderer, _drawColour.r, _drawColour.g, _drawColour.b, _drawColour.a);
250 	}
251 
252 	/// The renderer
253 	@property renderer() nothrow {
254 		return _renderer;
255 	}
256 
257 private:
258 	SDL_Renderer* _renderer;
259 
260 	Rect _clipRect;
261 	Color _drawColour;
262 }