1 module gfm.sdl2.surface; 2 3 import derelict.sdl2.sdl; 4 5 import gfm.math.vector, 6 gfm.sdl2.sdl; 7 8 /// SDL Surface wrapper. 9 /// A SDL2Surface might own the SDL_Surface* handle or not. 10 final class SDL2Surface 11 { 12 public 13 { 14 /// Whether a SDL Surface is owned by the wrapper or borrowed. 15 enum Owned 16 { 17 NO, // Not owned. 18 YES // Owned. 19 } 20 21 /// Create from an existing SDL_Surface* handle. 22 this(SDL2 sdl2, SDL_Surface* surface, Owned owned) 23 { 24 assert(surface !is null); 25 _sdl2 = sdl2; 26 _surface = surface; 27 _handleOwned = owned; 28 } 29 30 /// Create a new RGBA surface. Both pixels data and handle are owned. 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 /// Returns: A new surface. 73 SDL2Surface convert(const(SDL_PixelFormat)* newFormat) 74 { 75 SDL_Surface* surface = SDL_ConvertSurface(_surface, newFormat, 0); 76 if (surface is null) 77 _sdl2.throwSDL2Exception("SDL_ConvertSurface"); 78 assert(surface != _surface); // should not be the same handle 79 return new SDL2Surface(_sdl2, surface, Owned.YES); 80 } 81 82 /// Returns: A copy of the surface, useful for taking ownership of not-owned pixel data. 83 /// See_also: $WEB(wiki.libsdl.org/SDL_CreateRGBSurfaceFrom,SDL_CreateRGBSurfaceFrom) 84 SDL2Surface clone() 85 { 86 return convert(pixelFormat()); 87 } 88 89 /// Returns: Width of the surface in pixels. 90 @property int width() const 91 { 92 return _surface.w; 93 } 94 95 /// Returns: Height of the surface in pixels. 96 @property int height() const 97 { 98 return _surface.h; 99 } 100 101 /// Returns: Pointer to surface data. 102 /// You must lock the surface before accessng it. 103 ubyte* pixels() 104 { 105 return cast(ubyte*) _surface.pixels; 106 } 107 108 /// Get the surface pitch (number of bytes between lines). 109 size_t pitch() 110 { 111 return _surface.pitch; 112 } 113 114 /// Lock the surface, allow to use pixels(). 115 /// Throws: $(D SDL2Exception) on error. 116 void lock() 117 { 118 if (SDL_LockSurface(_surface) != 0) 119 _sdl2.throwSDL2Exception("SDL_LockSurface"); 120 } 121 122 /// Unlock the surface. 123 void unlock() 124 { 125 SDL_UnlockSurface(_surface); 126 } 127 128 /// Returns: SDL handle. 129 SDL_Surface* handle() 130 { 131 return _surface; 132 } 133 134 /// Returns: SDL_PixelFormat which describe the surface. 135 SDL_PixelFormat* pixelFormat() 136 { 137 return _surface.format; 138 } 139 140 /// Get a surface pixel color. 141 /// Bugs: must be locked when using this method. Slow! 142 vec4ub getRGBA(int x, int y) 143 { 144 // crash if out of image 145 if (x < 0 || x >= width()) 146 assert(0); 147 148 if (y < 0 || y >= height()) 149 assert(0); 150 151 SDL_PixelFormat* fmt = _surface.format; 152 153 ubyte* pixels = cast(ubyte*)_surface.pixels; 154 int pitch = _surface.pitch; 155 156 uint* pixel = cast(uint*)(pixels + y * pitch + x * fmt.BytesPerPixel); 157 ubyte r, g, b, a; 158 SDL_GetRGBA(*pixel, fmt, &r, &g, &b, &a); 159 return vec4ub(r, g, b, a); 160 } 161 } 162 163 package 164 { 165 SDL2 _sdl2; 166 SDL_Surface* _surface; 167 Owned _handleOwned; 168 } 169 }