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         /// Blits a rectangle from a texture and apply rotation/reflection.
211         /// See_also: $(LINK http://wiki.libsdl.org/SDL_RenderCopyEx)
212         /// Throws: $(D SDL2Exception) on error.
213         void copyEx(SDL2Texture texture, SDL_Rect srcRect, SDL_Rect dstRect, double rotangle, SDL_Point* rotcenter, SDL_RendererFlip flip)
214         {
215             if (0 != SDL_RenderCopyEx(_renderer, texture._handle, &srcRect, &dstRect, rotangle, rotcenter, flip))
216                 _sdl2.throwSDL2Exception("SDL_RenderCopyEx");
217         }
218 
219         /// Returns: Renderer information.
220         /// See_also: $(LINK http://wiki.libsdl.org/SDL_GetRendererInfo)
221         /// Throws: $(D SDL2Exception) on error.
222         SDL2RendererInfo info()
223         {
224             return _info;
225         }
226     }
227 
228     package
229     {
230         SDL2 _sdl2;
231         SDL_Renderer* _renderer;
232         SDL2RendererInfo _info;
233     }
234 
235     private
236     {
237         void readCapabilities()
238         {
239             SDL_RendererInfo info;
240             int res = SDL_GetRendererInfo(_renderer, &info);
241             if (res != 0)
242                 _sdl2.throwSDL2Exception("SDL_GetRendererInfo");
243             _info = new SDL2RendererInfo(info);
244         }
245     }
246 }
247 
248 /// SDL Renderer information.
249 final class SDL2RendererInfo
250 {
251     public
252     {
253         this(SDL_RendererInfo info)
254         {
255             _info = info;
256         }
257 
258         /// Returns: Renderer name.
259         const(char)[] name()
260         {
261             return fromStringz(_info.name);
262         }
263 
264         /// Returns: true if this renderer is software.
265         bool isSoftware()
266         {
267             return (_info.flags & SDL_RENDERER_SOFTWARE) != 0;
268         }
269 
270         /// Returns: true if this renderer is accelerated.
271         bool isAccelerated()
272         {
273             return (_info.flags & SDL_RENDERER_ACCELERATED) != 0;
274         }
275 
276         /// Returns: true if this renderer can render to a texture.
277         bool hasRenderToTexture()
278         {
279             return (_info.flags & SDL_RENDERER_TARGETTEXTURE) != 0;
280         }
281 
282         /// Returns: true if this renderer support vertical synchronization.
283         bool isVsyncEnabled()
284         {
285             return (_info.flags & SDL_RENDERER_PRESENTVSYNC) != 0;
286         }
287 
288         /// Returns: Pretty string describing the renderer.
289         override string toString()
290         {
291             string res = format("renderer: %s [flags:", name());
292             if (isSoftware()) res ~= " software";
293             if (isAccelerated()) res ~= " accelerated";
294             if (hasRenderToTexture()) res ~= " render-to-texture";
295             if (isVsyncEnabled()) res ~= " vsync";
296             res ~= "]\n";
297             res ~= format("max. texture: %sx%s", _info.max_texture_width, _info.max_texture_height);
298             return res;
299         }
300     }
301 
302     private
303     {
304         SDL_RendererInfo _info;
305     }
306 }