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