1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Graphics.Renderer; 25 26 private { 27 import derelict.sdl2.sdl; 28 29 import Dgame.Math.Rect; 30 import Dgame.Graphics.Surface; 31 import Dgame.Graphics.Color; 32 import Dgame.Graphics.RendererTexture; 33 import Dgame.Window.Window; 34 import Dgame.Internal.Unique; 35 } 36 37 /** 38 * Renderer support (hardware) accelerated rendering. 39 * 40 * Author: rschuett 41 */ 42 final class Renderer { 43 /** 44 * Supported BlendModes 45 */ 46 enum BlendMode { 47 None = SDL_BLENDMODE_NONE, /** no blending */ 48 Blend = SDL_BLENDMODE_BLEND, /** dst = (src * A) + (dst * (1-A)) */ 49 Add = SDL_BLENDMODE_ADD, /** dst = (src * A) + dst */ 50 Mod = SDL_BLENDMODE_MOD, /** dst = src * dst */ 51 } 52 53 /** 54 * Supported Flags 55 */ 56 enum Flags { 57 Software = SDL_RENDERER_SOFTWARE, /** the renderer is a software fallback */ 58 HwAccel = SDL_RENDERER_ACCELERATED, /** the renderer uses hardware acceleration */ 59 VSync = SDL_RENDERER_PRESENTVSYNC, /** present is synchronized with the refresh rate */ 60 TargetTexture = SDL_RENDERER_TARGETTEXTURE /** the renderer supports rendering to texture */ 61 } 62 63 /** 64 * Flags 65 */ 66 const Flags flags; 67 68 private: 69 unique_ptr!(SDL_Renderer) _target; 70 71 ushort _width; 72 ushort _height; 73 74 private: 75 /** 76 * CTor 77 */ 78 this(SDL_Renderer* renderer, ushort w, ushort h) in { 79 assert(renderer !is null, "Renderer is null."); 80 } body { 81 this._target = make_unique(renderer, (SDL_Renderer* re) => SDL_DestroyRenderer(re)); 82 83 this._width = w; 84 this._height = h; 85 86 SDL_RendererInfo renderInfo; 87 if (SDL_GetRendererInfo(renderer, &renderInfo) == 0) 88 this.flags = cast(Flags) renderInfo.flags; 89 else 90 throw new Exception("Could not detect Renderer Flags."); 91 } 92 93 /** 94 * Set a texture as the current rendering target. 95 */ 96 bool setTarget(SDL_Texture* tex, ushort w, ushort h) { 97 this._width = w; 98 this._height = h; 99 100 return SDL_SetRenderTarget(this._target, tex) == 0; 101 } 102 103 public: 104 /** 105 * Use this function to get the renderer associated with the window. 106 */ 107 static Renderer getFrom(Window win) { 108 SDL_Window* window = SDL_GetWindowFromID(win.id); 109 110 return new Renderer(SDL_GetRenderer(window), win.width, win.height); 111 } 112 113 /** 114 * Use this function to get the number of 2D rendering drivers available for the current display. 115 */ 116 static int countDrivers() { 117 return SDL_GetNumRenderDrivers(); 118 } 119 120 /** 121 * Use this function to create a 2D rendering context for a window. 122 */ 123 this(Window win, Flags flags) { 124 SDL_Window* window = SDL_GetWindowFromID(win.id); 125 126 this(SDL_CreateRenderer(window, -1, flags), win.width, win.height); 127 } 128 129 /** 130 * Use this function to create a 2D software rendering context for a Surface. 131 */ 132 this(ref Surface srfc) { 133 this(SDL_CreateSoftwareRenderer(srfc.ptr), srfc.width, srfc.height); 134 } 135 136 @disable 137 void opAssign(Renderer rhs); 138 139 /** 140 * Returns the width 141 */ 142 @property 143 ushort width() const pure nothrow { 144 return this._width; 145 } 146 147 /** 148 * Returns the height 149 */ 150 @property 151 ushort height() const pure nothrow { 152 return this.height; 153 } 154 155 /** 156 * Use this function to update the screen with rendering performed. 157 */ 158 void present() { 159 SDL_RenderPresent(this._target); 160 } 161 162 /** 163 * Use this function to set the blend mode for a texture, used by 'copy'. 164 */ 165 void setBlendMode(BlendMode bmode) { 166 SDL_SetRenderDrawBlendMode(this._target, bmode); 167 } 168 169 /** 170 * Use this function to get the blend mode used for texture copy operations. 171 */ 172 BlendMode getBlendMode() { 173 SDL_BlendMode blendMode; 174 SDL_GetRenderDrawBlendMode(this._target, &blendMode); 175 176 return cast(BlendMode) blendMode; 177 } 178 179 /** 180 * Use this function to set the color used for drawing operations (clear). 181 */ 182 void setDrawColor(ref const Color col) { 183 this.setDrawColor(col.red, col.green, col.blue, col.alpha); 184 } 185 186 /** 187 * Rvalue version 188 */ 189 void setDrawColor(const Color col) { 190 this.setDrawColor(col); 191 } 192 193 /** 194 * Use this function to set the color used for drawing operations (clear). 195 */ 196 void setDrawColor(ubyte r, ubyte g, ubyte b, ubyte a) { 197 SDL_SetRenderDrawColor(this._target, r, g, b, a); 198 } 199 200 /** 201 * Use this function to create a texture for a rendering context. 202 */ 203 RendererTexture createSoftTexture(ushort width, ushort height, RendererTexture.Access access) { 204 SDL_Texture* tex = SDL_CreateTexture(this._target, SDL_PIXELFORMAT_UNKNOWN, access, width, height); 205 206 return RendererTexture(tex, access); 207 } 208 209 /** 210 * Use this function to create a texture from an existing surface. 211 */ 212 RendererTexture createRendererTexture(ref Surface srfc, bool release = false, 213 RendererTexture.Access access = RendererTexture.Access.Static) 214 { 215 scope(exit) { 216 if (release) 217 srfc.free(); 218 } 219 220 if (access & RendererTexture.Access.Static) { 221 SDL_Texture* tex = SDL_CreateTextureFromSurface(this._target, srfc.ptr); 222 223 return RendererTexture(tex, access); 224 } 225 226 RendererTexture hw = this.createSoftTexture(srfc.width, srfc.height, access); 227 hw.update(srfc.pixels, null); 228 229 return hw; 230 } 231 232 /** 233 * Rvalue version 234 */ 235 RendererTexture createRendererTexture(Surface srfc, bool release = false, 236 RendererTexture.Access access = RendererTexture.Access.Static) 237 { 238 return this.createRendererTexture(srfc, release, access); 239 } 240 241 /** 242 * Set a Surface as the current rendering target. 243 */ 244 bool setTarget(ref Surface srfc) { 245 SDL_Texture* tex = SDL_CreateTextureFromSurface(this._target, srfc.ptr); 246 247 return this.setTarget(tex, srfc.width, srfc.height); 248 } 249 250 /** 251 * Set a SoftTexture as the current rendering target. 252 */ 253 bool setTarget(ref RendererTexture hw) { 254 return this.setTarget(hw.ptr, hw.width, hw.height); 255 } 256 257 /** 258 * Use this function to copy a portion of the texture to the current rendering target. 259 */ 260 bool copy(ref RendererTexture hw, const ShortRect* src = null, const ShortRect *dst = null) { 261 SDL_Rect a = void; 262 SDL_Rect b = void; 263 264 const SDL_Rect* _src = transfer(src, &a); 265 const SDL_Rect* _dst = transfer(dst, &b); 266 267 return SDL_RenderCopy(this._target, hw.ptr, _src, _dst) == 0; 268 } 269 270 /** 271 * Use this function to clear the current rendering target with the drawing color. 272 */ 273 void clear() { 274 SDL_RenderClear(this._target); 275 } 276 277 /** 278 * Use this function to set the drawing area for rendering on the current target. 279 */ 280 void setViewport(ref const ShortRect view) { 281 SDL_Rect a = void; 282 view.transferTo(&a); 283 284 SDL_RenderSetViewport(this._target, &a); 285 } 286 287 /** 288 * Rvalue version 289 */ 290 void setViewport(const ShortRect view) { 291 this.setViewport(view); 292 } 293 294 /** 295 * Use this function to get the drawing area for the current target. 296 */ 297 ShortRect getViewport() { 298 SDL_Rect a = void; 299 SDL_RenderGetViewport(this._target, &a); 300 301 return ShortRect(a); 302 } 303 304 /** 305 * Use this function to read pixels from the current rendering target. 306 * Note: This is a very slow operation, and should not be used frequently. 307 * Note: This method <b>allocates</b> GC memory. 308 * 309 * rect represents the area to read, or null for the entire render target 310 */ 311 void* readPixels(const ShortRect* rect) { 312 void[] pixels = new void[rect.width * rect.height * 4]; 313 314 SDL_Rect a = void; 315 const SDL_Rect* area = transfer(rect, &a); 316 317 SDL_RenderReadPixels(this._target, area, 0, &pixels[0], this._width * 4); 318 319 return &pixels[0]; 320 } 321 }