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