1 module gfm.sdl2.surface; 2 3 import derelict.sdl2.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 /// Throws: $(D SDL2Exception) on error. 31 this(SDL2 sdl2, int width, int height, int depth, 32 uint Rmask, uint Gmask, uint Bmask, uint Amask) 33 { 34 _sdl2 = sdl2; 35 _surface = SDL_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask); 36 if (_surface is null) 37 _sdl2.throwSDL2Exception("SDL_CreateRGBSurface"); 38 _handleOwned = Owned.YES; 39 } 40 41 /// Create surface from RGBA data. Pixels data is <b>not</b> and not owned. 42 /// See_also: clone, $(WEB wiki.libsdl.org/SDL_CreateRGBSurfaceFrom,SDL_CreateRGBSurfaceFrom) 43 /// Throws: $(D SDL2Exception) on error. 44 this(SDL2 sdl2, void* pixels, int width, int height, int depth, int pitch, 45 uint Rmask, uint Gmask, uint Bmask, uint Amask) 46 { 47 _sdl2 = sdl2; 48 _surface = SDL_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask); 49 if (_surface is null) 50 _sdl2.throwSDL2Exception("SDL_CreateRGBSurfaceFrom"); 51 _handleOwned = Owned.YES; 52 } 53 54 ~this() 55 { 56 close(); 57 } 58 59 /// Releases the SDL resource. 60 void close() 61 { 62 if (_surface !is null) 63 { 64 if (_handleOwned == Owned.YES) 65 SDL_FreeSurface(_surface); 66 _surface = null; 67 } 68 } 69 70 /// Converts the surface to another format. 71 /// Returns: A new surface. 72 SDL2Surface convert(const(SDL_PixelFormat)* newFormat) 73 { 74 SDL_Surface* surface = SDL_ConvertSurface(_surface, newFormat, 0); 75 if (surface is null) 76 _sdl2.throwSDL2Exception("SDL_ConvertSurface"); 77 assert(surface != _surface); // should not be the same handle 78 return new SDL2Surface(_sdl2, surface, Owned.YES); 79 } 80 81 /// Returns: A copy of the surface, useful for taking ownership of not-owned pixel data. 82 /// See_also: $WEB(wiki.libsdl.org/SDL_CreateRGBSurfaceFrom,SDL_CreateRGBSurfaceFrom) 83 SDL2Surface clone() 84 { 85 return convert(pixelFormat()); 86 } 87 88 /// Returns: Width of the surface in pixels. 89 @property int width() const 90 { 91 return _surface.w; 92 } 93 94 /// Returns: Height of the surface in pixels. 95 @property int height() const 96 { 97 return _surface.h; 98 } 99 100 /// Returns: Pointer to surface data. 101 /// You must lock the surface before accessng it. 102 ubyte* pixels() 103 { 104 return cast(ubyte*) _surface.pixels; 105 } 106 107 /// Get the surface pitch (number of bytes between lines). 108 size_t pitch() 109 { 110 return _surface.pitch; 111 } 112 113 /// Lock the surface, allow to use pixels(). 114 /// Throws: $(D SDL2Exception) on error. 115 void lock() 116 { 117 if (SDL_LockSurface(_surface) != 0) 118 _sdl2.throwSDL2Exception("SDL_LockSurface"); 119 } 120 121 /// Unlock the surface. 122 void unlock() 123 { 124 SDL_UnlockSurface(_surface); 125 } 126 127 /// Returns: SDL handle. 128 SDL_Surface* handle() 129 { 130 return _surface; 131 } 132 133 /// Returns: SDL_PixelFormat which describe the surface. 134 SDL_PixelFormat* pixelFormat() 135 { 136 return _surface.format; 137 } 138 139 struct RGBA 140 { 141 ubyte r, g, b, a; 142 } 143 144 /// Get a surface pixel color. 145 /// Bugs: must be locked when using this method. Slow! 146 RGBA getRGBA(int x, int y) 147 { 148 // crash if out of image 149 if (x < 0 || x >= width()) 150 assert(0); 151 152 if (y < 0 || y >= height()) 153 assert(0); 154 155 SDL_PixelFormat* fmt = _surface.format; 156 157 ubyte* pixels = cast(ubyte*)_surface.pixels; 158 int pitch = _surface.pitch; 159 160 uint* pixel = cast(uint*)(pixels + y * pitch + x * fmt.BytesPerPixel); 161 ubyte r, g, b, a; 162 SDL_GetRGBA(*pixel, fmt, &r, &g, &b, &a); 163 return RGBA(r, g, b, a); 164 } 165 } 166 167 package 168 { 169 SDL2 _sdl2; 170 SDL_Surface* _surface; 171 Owned _handleOwned; 172 } 173 }