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