1 module gfm.sdl2.renderer;
2 
3 import std..string;
4 
5 import bindbc.sdl;
6 
7 import std.experimental.logger;
8 
9 import gfm.sdl2.sdl,
10        gfm.sdl2.window,
11        gfm.sdl2.texture,
12        gfm.sdl2.surface;
13 
14 /// SDL Renderer wrapper.
15 final class SDL2Renderer
16 {
17     public
18     {
19         /// Creates a SDL renderer which targets a window.
20         /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateRenderer)
21         /// Throws: $(D SDL2Exception) on error.
22         this(SDL2Window window, int flags = 0)
23         {
24             _sdl2 = window._sdl2;
25             _renderer = SDL_CreateRenderer(window._window, -1, cast(SDL_RendererFlags)flags);
26             if (_renderer is null)
27                 _sdl2.throwSDL2Exception("SDL_CreateRenderer");
28 
29             readCapabilities();
30         }
31 
32         /// Create a software renderer which targets a surface.
33         /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateSoftwareRenderer)
34         /// Throws: $(D SDL2Exception) on error.
35         this(SDL2Surface surface)
36         {
37             _sdl2 = surface._sdl2;
38             _renderer = SDL_CreateSoftwareRenderer(surface._surface);
39             if (_renderer is null)
40                 _sdl2.throwSDL2Exception("SDL_CreateSoftwareRenderer");
41 
42             readCapabilities();
43         }
44 
45         /// Releases the SDL ressource.
46         /// See_also: $(LINK http://wiki.libsdl.org/SDL_DestroyRenderer)
47         ~this()
48         {
49             if (_renderer !is null)
50             {
51                 debug ensureNotInGC("SDL2Renderer");
52                 SDL_DestroyRenderer(_renderer);
53                 _renderer = null;
54             }
55         }
56 
57         /// Clear the current rendering target with the drawing color.
58         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderClear)
59         /// Throws: $(D SDL2Exception) on error.
60         void clear()
61         {
62             if (0 != SDL_RenderClear(_renderer))
63                 _sdl2.throwSDL2Exception("SDL_RenderClear");
64         }
65 
66         /// Update the screen with rendering performed.
67         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderPresent)
68         void present()
69         {
70             SDL_RenderPresent(_renderer);
71         }
72 
73         /// Sets the color used for drawing operations.
74         /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetRenderDrawColor)
75         /// Throws: $(D SDL2Exception) on error.
76         void setColor(int r, int g, int b, int a = 255)
77         {
78             if (0 != SDL_SetRenderDrawColor(_renderer, cast(ubyte)r, cast(ubyte)g, cast(ubyte)b, cast(ubyte)a))
79                 _sdl2.throwSDL2Exception("SDL_SetRenderDrawColor");
80         }
81 
82         /// Sets the window drawing area.
83         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetViewport)
84         /// Throws: $(D SDL2Exception) on error.
85         void setViewport(int x, int y, int w, int h)
86         {
87             SDL_Rect r = SDL_Rect(x, y, w, h);
88             if (0 != SDL_RenderSetViewport(_renderer, &r))
89                 _sdl2.throwSDL2Exception("SDL_RenderSetViewport");
90         }
91 
92         /// Sets the whole window as drawing area.
93         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetViewport)
94         /// Throws: $(D SDL2Exception) on error.
95         void setViewportFull()
96         {
97             if (0 != SDL_RenderSetViewport(_renderer, null))
98                 _sdl2.throwSDL2Exception("SDL_RenderSetViewport");
99         }
100 
101         /// Sets the scale of the renderer.
102         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetScale)
103         /// Throws: $(D SDL2Exception) on error.
104         void setScale(float x, float y)
105         {
106             if (0 != SDL_RenderSetScale(_renderer, x, y))
107                 _sdl2.throwSDL2Exception("SDL_RenderSetScale");
108         }
109 
110         /// Sets a device independent resolution of the renderer.
111         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetLogicalSize)
112         /// Throws: $(D SDL2Exception) on error.
113         void setLogicalSize(int w, int h)
114         {
115             if (0 != SDL_RenderSetLogicalSize(_renderer, w, h))
116                 _sdl2.throwSDL2Exception("SDL_RenderSetLogicalSize");
117         }
118 
119         /// Sets SDL blend mode.
120         /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetRenderDrawBlendMode)
121         /// Throws: $(D SDL2Exception) on error.
122         void setBlend(int blendMode)
123         {
124             if (0 != SDL_SetRenderDrawBlendMode(_renderer, cast(SDL_BlendMode)blendMode))
125                 _sdl2.throwSDL2Exception("SDL_SetRenderDrawBlendMode");
126         }
127 
128         /// Draw a line.
129         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawLine)
130         /// Throws: $(D SDL2Exception) on error.
131         void drawLine(int x1, int y1, int x2, int y2)
132         {
133             if (0 != SDL_RenderDrawLine(_renderer, x1, y1, x2, y2))
134                 _sdl2.throwSDL2Exception("SDL_RenderDrawLine");
135 
136         }
137 
138         /// Draw several lines at once.
139         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawLines)
140         /// Throws: $(D SDL2Exception) on error.
141         void drawLines(SDL_Point[] points)
142         {
143             if (0 != SDL_RenderDrawLines(_renderer, points.ptr, cast(int)(points.length)))
144                 _sdl2.throwSDL2Exception("SDL_RenderDrawLines");
145         }
146 
147         /// Draw a point.
148         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawPoint)
149         /// Throws: $(D SDL2Exception) on error.
150         void drawPoint(int x, int y)
151         {
152             if (0 != SDL_RenderDrawPoint(_renderer, x, y))
153                 _sdl2.throwSDL2Exception("SDL_RenderDrawPoint");
154         }
155 
156         /// Draw several point at once.
157         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawPoints)
158         /// Throws: $(D SDL2Exception) on error.
159         void drawPoints(SDL_Point[] points)
160         {
161             if (0 != SDL_RenderDrawPoints(_renderer, points.ptr, cast(int)(points.length)))
162                 _sdl2.throwSDL2Exception("SDL_RenderDrawPoints");
163         }
164 
165         /// Draw a rectangle outline.
166         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawRect)
167         /// Throws: $(D SDL2Exception) on error.
168         void drawRect(int x, int y, int width, int height)
169         {
170             SDL_Rect r = SDL_Rect(x, y, width, height);
171             if (0 != SDL_RenderDrawRect(_renderer, &r))
172                 _sdl2.throwSDL2Exception("SDL_RenderDrawRect");
173         }
174 
175         /// Draw a filled rectangle.
176         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderFillRect)
177         /// Throws: $(D SDL2Exception) on error.
178         void fillRect(int x, int y, int width, int height)
179         {
180             SDL_Rect r = SDL_Rect(x, y, width, height);
181             if (0 != SDL_RenderFillRect(_renderer, &r))
182                 _sdl2.throwSDL2Exception("SDL_RenderFillRect");
183         }
184 
185         /// Blit a rectangle from a texture.
186         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderCopy)
187         /// Throws: $(D SDL2Exception) on error.
188         void copy(SDL2Texture texture, SDL_Rect srcRect, SDL_Rect dstRect)
189         {
190             if (0 != SDL_RenderCopy(_renderer, texture._handle, &srcRect, &dstRect))
191                 _sdl2.throwSDL2Exception("SDL_RenderCopy");
192         }
193 
194         /// Draws a whole texture.
195         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderCopy)
196         /// Throws: $(D SDL2Exception) on error.
197         void copy(SDL2Texture texture, int x, int y)
198         {
199             int w = texture.width();
200             int h = texture.height();
201             SDL_Rect source = SDL_Rect(0, 0, w, h);
202             SDL_Rect dest = SDL_Rect(x, y, w, h);
203             copy(texture, source, dest);
204         }
205 
206         /// Blits a rectangle from a texture and apply rotation/reflection.
207         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderCopyEx)
208         /// Throws: $(D SDL2Exception) on error.
209         void copyEx(SDL2Texture texture, SDL_Rect srcRect, SDL_Rect dstRect, double rotangle, SDL_Point* rotcenter, SDL_RendererFlip flip)
210         {
211             if (0 != SDL_RenderCopyEx(_renderer, texture._handle, &srcRect, &dstRect, rotangle, rotcenter, flip))
212                 _sdl2.throwSDL2Exception("SDL_RenderCopyEx");
213         }
214 
215         /// Set a texture as the current rendering target.
216         /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetRenderTarget)
217         /// Throws: $(D SDL2Exception) on error.
218         void setRenderTarget(SDL2Texture texture)
219         {
220             if (0 != SDL_SetRenderTarget(_renderer, texture is null ? cast(SDL_Texture*)0 : texture._handle))
221                 _sdl2.throwSDL2Exception("SDL_SetRenderTarget");
222         }
223 
224         /// Returns: Renderer information.
225         /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetRendererInfo)
226         /// Throws: $(D SDL2Exception) on error.
227         SDL2RendererInfo info()
228         {
229             return _info;
230         }
231 
232         /// Returns: SDL handle.
233         SDL_Renderer* handle()
234         {
235             return _renderer;
236         }
237     }
238 
239     package
240     {
241         SDL2 _sdl2;
242         SDL_Renderer* _renderer;
243         SDL2RendererInfo _info;
244     }
245 
246     private
247     {
248         void readCapabilities()
249         {
250             SDL_RendererInfo info;
251             int res = SDL_GetRendererInfo(_renderer, &info);
252             if (res != 0)
253                 _sdl2.throwSDL2Exception("SDL_GetRendererInfo");
254             _info = new SDL2RendererInfo(info);
255         }
256     }
257 }
258 
259 /// SDL Renderer information.
260 final class SDL2RendererInfo
261 {
262     public
263     {
264         this(SDL_RendererInfo info)
265         {
266             _info = info;
267         }
268 
269         /// Returns: Renderer name.
270         const(char)[] name()
271         {
272             return fromStringz(_info.name);
273         }
274 
275         /// Returns: true if this renderer is software.
276         bool isSoftware()
277         {
278             return (_info.flags & SDL_RENDERER_SOFTWARE) != 0;
279         }
280 
281         /// Returns: true if this renderer is accelerated.
282         bool isAccelerated()
283         {
284             return (_info.flags & SDL_RENDERER_ACCELERATED) != 0;
285         }
286 
287         /// Returns: true if this renderer can render to a texture.
288         bool hasRenderToTexture()
289         {
290             return (_info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
291         }
292 
293         /// Returns: true if this renderer support vertical synchronization.
294         bool isVsyncEnabled()
295         {
296             return (_info.flags & SDL_RENDERER_PRESENTVSYNC) != 0;
297         }
298 
299         /// Returns: the maximum supported texture width
300         int maxTextureWidth()
301         {
302             return _info.max_texture_width;
303         }
304 
305         /// Returns: the maximum supported texture height
306         int maxTextureHeight()
307         {
308             return _info.max_texture_height;
309         }
310 
311         /// Returns: Pretty string describing the renderer.
312         override string toString()
313         {
314             string res = format("renderer: %s [flags:", name());
315             if (isSoftware()) res ~= " software";
316             if (isAccelerated()) res ~= " accelerated";
317             if (hasRenderToTexture()) res ~= " render-to-texture";
318             if (isVsyncEnabled()) res ~= " vsync";
319             res ~= "]\n";
320             res ~= format("max. supported texture size: %sx%s", maxTextureWidth(), maxTextureHeight());
321             return res;
322         }
323     }
324 
325     private
326     {
327         SDL_RendererInfo _info;
328     }
329 }