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