1 module gfm.sdl2.renderer;
2 
3 import std.string;
4 
5 import derelict.sdl2.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, 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         void close()
48         {
49             if (_renderer !is null)
50             {
51                 SDL_DestroyRenderer(_renderer);
52                 _renderer = null;
53             }
54         }
55 
56         ~this()
57         {
58             close();
59         }
60 
61         /// Clear the current rendering target with the drawing color.
62         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderClear)
63         /// Throws: $(D SDL2Exception) on error.
64         void clear()
65         {
66             if (0 != SDL_RenderClear(_renderer))
67                 _sdl2.throwSDL2Exception("SDL_RenderClear");
68         }
69 
70         /// Update the screen with rendering performed.
71         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderPresent)
72         void present()
73         {
74             SDL_RenderPresent(_renderer);
75         }
76 
77         /// Sets the color used for drawing operations.
78         /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetRenderDrawColor)
79         /// Throws: $(D SDL2Exception) on error.
80         void setColor(int r, int g, int b, int a = 255)
81         {
82             if (0 != SDL_SetRenderDrawColor(_renderer, cast(ubyte)r, cast(ubyte)g, cast(ubyte)b, cast(ubyte)a))
83                 _sdl2.throwSDL2Exception("SDL_SetRenderDrawColor");
84         }
85 
86         /// Sets the window drawing area.
87         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetViewport)
88         /// Throws: $(D SDL2Exception) on error.
89         void setViewport(int x, int y, int w, int h)
90         {
91             SDL_Rect r = SDL_Rect(x, y, w, h);
92             if (0 != SDL_RenderSetViewport(_renderer, &r))
93                 _sdl2.throwSDL2Exception("SDL_RenderSetViewport");
94         }
95 
96         /// Sets the whole window as drawing area.
97         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetViewport)
98         /// Throws: $(D SDL2Exception) on error.
99         void setViewportFull()
100         {
101             if (0 != SDL_RenderSetViewport(_renderer, null))
102                 _sdl2.throwSDL2Exception("SDL_RenderSetViewport");
103         }
104 
105         /// Sets the scale of the renderer.
106         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetScale)
107         /// Throws: $(D SDL2Exception) on error.
108         void setScale(float x, float y)
109         {
110             if (0 != SDL_RenderSetScale(_renderer, x, y))
111                 _sdl2.throwSDL2Exception("SDL_RenderSetScale");
112         }
113 
114         /// Sets a device independent resolution of the renderer.
115         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderSetLogicalSize)
116         /// Throws: $(D SDL2Exception) on error.
117         void setLogicalSize(int w, int h)
118         {
119             if (0 != SDL_RenderSetLogicalSize(_renderer, w, h))
120                 _sdl2.throwSDL2Exception("SDL_RenderSetLogicalSize");
121         }
122 
123         /// Sets SDL blend mode.
124         /// See_also: $(LINK http://wiki.libsdl.org/SDL_SetRenderDrawBlendMode)
125         /// Throws: $(D SDL2Exception) on error.
126         void setBlend(int blendMode)
127         {
128             if (0 != SDL_SetRenderDrawBlendMode(_renderer, blendMode))
129                 _sdl2.throwSDL2Exception("SDL_SetRenderDrawBlendMode");
130         }
131 
132         /// Draw a line.
133         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawLine)
134         /// Throws: $(D SDL2Exception) on error.
135         void drawLine(int x1, int y1, int x2, int y2)
136         {
137             if (0 != SDL_RenderDrawLine(_renderer, x1, y1, x2, y2))
138                 _sdl2.throwSDL2Exception("SDL_RenderDrawLine");
139 
140         }
141 
142         /// Draw several lines at once.
143         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawLines)
144         /// Throws: $(D SDL2Exception) on error.
145         void drawLines(SDL_Point[] points)
146         {
147             if (0 != SDL_RenderDrawLines(_renderer, points.ptr, cast(int)(points.length)))
148                 _sdl2.throwSDL2Exception("SDL_RenderDrawLines");
149         }
150 
151         /// Draw a point.
152         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawPoint)
153         /// Throws: $(D SDL2Exception) on error.
154         void drawPoint(int x, int y)
155         {
156             if (0 != SDL_RenderDrawPoint(_renderer, x, y))
157                 _sdl2.throwSDL2Exception("SDL_RenderDrawPoint");
158         }
159 
160         /// Draw several point at once.
161         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawPoints)
162         /// Throws: $(D SDL2Exception) on error.
163         void drawPoints(SDL_Point[] points)
164         {
165             if (0 != SDL_RenderDrawPoints(_renderer, points.ptr, cast(int)(points.length)))
166                 _sdl2.throwSDL2Exception("SDL_RenderDrawPoints");
167         }
168 
169         /// Draw a rectangle outline.
170         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderDrawRect)
171         /// Throws: $(D SDL2Exception) on error.
172         void drawRect(int x, int y, int width, int height)
173         {
174             SDL_Rect r = SDL_Rect(x, y, width, height);
175             if (0 != SDL_RenderDrawRect(_renderer, &r))
176                 _sdl2.throwSDL2Exception("SDL_RenderDrawRect");
177         }
178 
179         /// Draw a filled rectangle.
180         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderFillRect)
181         /// Throws: $(D SDL2Exception) on error.
182         void fillRect(int x, int y, int width, int height)
183         {
184             SDL_Rect r = SDL_Rect(x, y, width, height);
185             if (0 != SDL_RenderFillRect(_renderer, &r))
186                 _sdl2.throwSDL2Exception("SDL_RenderFillRect");
187         }
188 
189         /// Blit a rectangle from a texture.
190         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderCopy)
191         /// Throws: $(D SDL2Exception) on error.
192         void copy(SDL2Texture texture, SDL_Rect srcRect, SDL_Rect dstRect)
193         {
194             if (0 != SDL_RenderCopy(_renderer, texture._handle, &srcRect, &dstRect))
195                 _sdl2.throwSDL2Exception("SDL_RenderCopy");
196         }
197 
198         /// Draws a whole texture.
199         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderCopy)
200         /// Throws: $(D SDL2Exception) on error.
201         void copy(SDL2Texture texture, int x, int y)
202         {
203             int w = texture.width();
204             int h = texture.height();
205             SDL_Rect source = SDL_Rect(0, 0, w, h);
206             SDL_Rect dest = SDL_Rect(x, y, w, h);
207             copy(texture, source, dest);
208         }
209 
210         /// Returns: Renderer information.
211         /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetRendererInfo)
212         /// Throws: $(D SDL2Exception) on error.
213         SDL2RendererInfo info()
214         {
215             return _info;
216         }
217     }
218 
219     package
220     {
221         SDL2 _sdl2;
222         SDL_Renderer* _renderer;
223         SDL2RendererInfo _info;
224     }
225 
226     private
227     {
228         void readCapabilities()
229         {
230             SDL_RendererInfo info;
231             int res = SDL_GetRendererInfo(_renderer, &info);
232             if (res != 0)
233                 _sdl2.throwSDL2Exception("SDL_GetRendererInfo");
234             _info = new SDL2RendererInfo(info);
235         }
236     }
237 }
238 
239 /// SDL Renderer information.
240 final class SDL2RendererInfo
241 {
242     public
243     {
244         this(SDL_RendererInfo info)
245         {
246             _info = info;
247         }
248 
249         /// Returns: Renderer name.
250         const(char)[] name()
251         {
252             return fromStringz(_info.name);
253         }
254 
255         /// Returns: true if this renderer is software.
256         bool isSoftware()
257         {
258             return (_info.flags & SDL_RENDERER_SOFTWARE) != 0;
259         }
260 
261         /// Returns: true if this renderer is accelerated.
262         bool isAccelerated()
263         {
264             return (_info.flags & SDL_RENDERER_ACCELERATED) != 0;
265         }
266 
267         /// Returns: true if this renderer can render to a texture.
268         bool hasRenderToTexture()
269         {
270             return (_info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
271         }
272 
273         /// Returns: true if this renderer support vertical synchronization.
274         bool isVsyncEnabled()
275         {
276             return (_info.flags & SDL_RENDERER_PRESENTVSYNC) != 0;
277         }
278 
279         /// Returns: Pretty string describing the renderer.
280         override string toString()
281         {
282             string res = format("renderer: %s [flags:", name());
283             if (isSoftware()) res ~= " software";
284             if (isAccelerated()) res ~= " accelerated";
285             if (hasRenderToTexture()) res ~= " render-to-texture";
286             if (isVsyncEnabled()) res ~= " vsync";
287             res ~= "]\n";
288             res ~= format("max. texture: %sx%s", _info.max_texture_width, _info.max_texture_height);
289             return res;
290         }
291     }
292 
293     private
294     {
295         SDL_RendererInfo _info;
296     }
297 }