1 module gfm.sdl2.surface; 2 3 import bindbc.sdl; 4 5 import gfm.sdl2.sdl; 6 7 /// SDL Surface wrapper. 8 /// A SDL2Surface might own the SDL_Surface* handle or not. 9 final class SDL2Surface 10 { 11 public 12 { 13 /// Whether a SDL Surface is owned by the wrapper or borrowed. 14 enum Owned 15 { 16 NO, // Not owned. 17 YES // Owned. 18 } 19 20 /// Create from an existing SDL_Surface* handle. 21 this(SDL2 sdl2, SDL_Surface* surface, Owned owned) 22 { 23 assert(surface !is null); 24 _sdl2 = sdl2; 25 _surface = surface; 26 _handleOwned = owned; 27 } 28 29 /// Create a new RGBA surface. Both pixels data and handle are owned. 30 /// See_also: $(LINK http://wiki.libsdl.org/SDL_CreateRGBSurface) 31 /// Throws: $(D SDL2Exception) on error. 32 this(SDL2 sdl2, int width, int height, int depth, 33 uint Rmask, uint Gmask, uint Bmask, uint Amask) 34 { 35 _sdl2 = sdl2; 36 _surface = SDL_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask); 37 if (_surface is null) 38 _sdl2.throwSDL2Exception("SDL_CreateRGBSurface"); 39 _handleOwned = Owned.YES; 40 } 41 42 /// Create surface from RGBA data. Pixels data is <b>not</b> and not owned. 43 /// See_also: clone, $(WEB wiki.libsdl.org/SDL_CreateRGBSurfaceFrom,SDL_CreateRGBSurfaceFrom) 44 /// Throws: $(D SDL2Exception) on error. 45 this(SDL2 sdl2, void* pixels, int width, int height, int depth, int pitch, 46 uint Rmask, uint Gmask, uint Bmask, uint Amask) 47 { 48 _sdl2 = sdl2; 49 _surface = SDL_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask); 50 if (_surface is null) 51 _sdl2.throwSDL2Exception("SDL_CreateRGBSurfaceFrom"); 52 _handleOwned = Owned.YES; 53 } 54 55 /// Releases the SDL resource. 56 ~this() 57 { 58 if (_surface !is null) 59 { 60 debug ensureNotInGC("SDL2Surface"); 61 if (_handleOwned == Owned.YES) 62 SDL_FreeSurface(_surface); 63 _surface = null; 64 } 65 } 66 67 /// Converts the surface to another format. 68 /// See_also: $(LINK http://wiki.libsdl.org/SDL_ConvertSurface) 69 /// Returns: A new surface. 70 SDL2Surface convert(const(SDL_PixelFormat)* newFormat) 71 { 72 SDL_Surface* surface = SDL_ConvertSurface(_surface, newFormat, 0); 73 if (surface is null) 74 _sdl2.throwSDL2Exception("SDL_ConvertSurface"); 75 assert(surface != _surface); // should not be the same handle 76 return new SDL2Surface(_sdl2, surface, Owned.YES); 77 } 78 79 /// Returns: A copy of the surface, useful for taking ownership of not-owned pixel data. 80 /// See_also: $WEB(wiki.libsdl.org/SDL_CreateRGBSurfaceFrom,SDL_CreateRGBSurfaceFrom) 81 SDL2Surface clone() 82 { 83 return convert(pixelFormat()); 84 } 85 86 /// Returns: Width of the surface in pixels. 87 @property int width() const 88 { 89 return _surface.w; 90 } 91 92 /// Returns: Height of the surface in pixels. 93 @property int height() const 94 { 95 return _surface.h; 96 } 97 98 /// Returns: Pointer to surface data. 99 /// You must lock the surface before accessng it. 100 ubyte* pixels() 101 { 102 return cast(ubyte*) _surface.pixels; 103 } 104 105 /// Get the surface pitch (number of bytes between lines). 106 size_t pitch() 107 { 108 return _surface.pitch; 109 } 110 111 /// Lock the surface, allow to use pixels(). 112 /// Throws: $(D SDL2Exception) on error. 113 void lock() 114 { 115 if (SDL_LockSurface(_surface) != 0) 116 _sdl2.throwSDL2Exception("SDL_LockSurface"); 117 } 118 119 /// Unlock the surface. 120 void unlock() 121 { 122 SDL_UnlockSurface(_surface); 123 } 124 125 /// Returns: SDL handle. 126 SDL_Surface* handle() 127 { 128 return _surface; 129 } 130 131 /// Returns: SDL_PixelFormat which describe the surface. 132 SDL_PixelFormat* pixelFormat() 133 { 134 return _surface.format; 135 } 136 137 /// 138 struct RGBA 139 { 140 ubyte r, g, b, a; 141 } 142 143 /// Get a surface pixel color. 144 /// Bugs: must be locked when using this method. Slow! 145 RGBA getRGBA(int x, int y) 146 { 147 // crash if out of image 148 if (x < 0 || x >= width()) 149 assert(0); 150 151 if (y < 0 || y >= height()) 152 assert(0); 153 154 SDL_PixelFormat* fmt = _surface.format; 155 156 ubyte* pixels = cast(ubyte*)_surface.pixels; 157 int pitch = _surface.pitch; 158 159 uint* pixel = cast(uint*)(pixels + y * pitch + x * fmt.BytesPerPixel); 160 ubyte r, g, b, a; 161 SDL_GetRGBA(*pixel, fmt, &r, &g, &b, &a); 162 return RGBA(r, g, b, a); 163 } 164 165 /// Enable the key color as the transparent key. 166 /// See_also: $(LINK https://wiki.libsdl.org/SDL_SetColorKey) 167 /// Throws: $(D SDL2Exception) on error. 168 void setColorKey(bool enable, uint key) 169 { 170 if (0 != SDL_SetColorKey(this._surface, enable ? SDL_TRUE : SDL_FALSE, key)) 171 _sdl2.throwSDL2Exception("SDL_SetColorKey"); 172 } 173 174 /// Enable the (r, g, b, a) key color as the transparent key. 175 /// See_also: $(LINK https://wiki.libsdl.org/SDL_SetColorKey) $(https://wiki.libsdl.org/SDL_MapRGBA) 176 /// Throws: $(D SDL2Exception) on error. 177 void setColorKey(bool enable, ubyte r, ubyte g, ubyte b, ubyte a = 0) 178 { 179 uint key = SDL_MapRGBA(cast(const)this._surface.format, r, g, b, a); 180 this.setColorKey(enable, key); 181 } 182 183 /// Perform a fast surface copy of given source surface to this destination surface. 184 /// See_also: $(LINK http://wiki.libsdl.org/SDL_BlitSurface) 185 /// Throws: $(D SDL2Exception) on error. 186 void blit(SDL2Surface source, SDL_Rect srcRect, SDL_Rect dstRect) 187 { 188 if (0 != SDL_BlitSurface(source._surface, &srcRect, _surface, &dstRect)) 189 _sdl2.throwSDL2Exception("SDL_BlitSurface"); 190 } 191 192 /// Perform a scaled surface copy of given source surface to this destination surface. 193 /// See_also: $(LINK http://wiki.libsdl.org/SDL_BlitScaled) 194 /// Throws: $(D SDL2Exception) on error. 195 void blitScaled(SDL2Surface source, SDL_Rect srcRect, SDL_Rect dstRect) 196 { 197 if (0 != SDL_BlitScaled(source._surface, &srcRect, _surface, &dstRect)) 198 _sdl2.throwSDL2Exception("SDL_BlitScaled"); 199 } 200 } 201 202 package 203 { 204 SDL2 _sdl2; 205 SDL_Surface* _surface; 206 Owned _handleOwned; 207 } 208 }