1 module d2d.rendering.bitmap; 2 3 import d2d; 4 5 /// Thin wrap around SDL_Surface including loading [png, webp, tiff, bmp] using SDL_Image. 6 class Bitmap : IVerifiable, IDisposable 7 { 8 private SDL_Surface* _handle; 9 10 /// Handle to the `SDL_Surface*`. 11 public @property SDL_Surface* surface() 12 { 13 return _handle; 14 } 15 16 /// Checks if the handle is not null. 17 public @property bool valid() 18 { 19 return _handle !is null; 20 } 21 22 /// Width of this bitmap. Returns 0 if invalid. 23 public @property int width() 24 { 25 if (!valid) 26 return 0; 27 return _handle.w; 28 } 29 30 /// Height of this bitmap. Returns 0 if invalid. 31 public @property int height() 32 { 33 if (!valid) 34 return 0; 35 return _handle.h; 36 } 37 38 private this(SDL_Surface * surface) 39 { 40 _handle = surface; 41 } 42 43 /// Creates a new width x height bitmap with a specified bit depth. 44 public this(int width, int height, int depth = 24, int redChannel = 0, int greenChannel = 0, int blueChannel = 0, int alphaChannel = 0) 45 { 46 _handle = SDL_CreateRGBSurface(0, width, height, depth, redChannel, greenChannel, blueChannel, alphaChannel); 47 } 48 49 public ~this() 50 { 51 dispose(); 52 } 53 54 /// Creates a new width x height bitmap with a specified bit depth containing pixel data. 55 public this(void[] pixels, int width, int height, int depth = 24, int redChannel = 0, int greenChannel = 0, int blueChannel = 0, int alphaChannel = 0) 56 { 57 _handle = SDL_CreateRGBSurfaceFrom(pixels.ptr, width, height, depth, width * (depth >> 3), redChannel, greenChannel, blueChannel, alphaChannel); 58 } 59 60 /// Creates a bitmap from a `SDL_Surface*`. 61 public static Bitmap fromSurface(SDL_Surface* surface) 62 { 63 return new Bitmap(surface); 64 } 65 66 /// Loads a png/webp/tiff/bmp from a file on the filesystem. 67 public static Bitmap load(string file) 68 { 69 Bitmap bmp = new Bitmap(IMG_Load(file.toStringz())); 70 71 if (!bmp.valid) 72 throw new Exception(cast(string) IMG_GetError().fromStringz()); 73 74 return bmp; 75 } 76 77 /// Deallocates the memory and invalidates `this`. 78 public void dispose() 79 { 80 if (valid) 81 { 82 SDL_FreeSurface(_handle); 83 _handle = null; 84 } 85 } 86 87 /// Saves the bitmap to a .bmp file. 88 public void save(string file) 89 { 90 SDL_SaveBMP(_handle, file.toStringz()); 91 } 92 93 /// Copies the bitmap and creates a new bitmap in the given pixelformat. 94 public Bitmap convert(const SDL_PixelFormat* format) 95 { 96 return new Bitmap(SDL_ConvertSurface(_handle, format, 0)); 97 } 98 99 /// Gets the rgb hex from the color based on the bitmap format. 100 public uint mapRGB(Color color) 101 { 102 return SDL_MapRGB(_handle.format, color.R, color.G, color.B); 103 } 104 105 /// Gets the rgb hex from the color based on the bitmap format. 106 public uint mapRGBA(ubyte r, ubyte g, ubyte b, ubyte a) 107 { 108 return SDL_MapRGBA(_handle.format, r, g, b, a); 109 } 110 111 /// Fills the entire bitmap with one color. 112 public void fill(Color color) 113 { 114 SDL_FillRect(_handle, null, mapRGB(color)); 115 } 116 117 /// Fills a rectangle with one color. 118 public void fill(int x, int y, int width, int height, Color color) 119 { 120 SDL_FillRect(_handle, new SDL_Rect(x, y, width, height), mapRGB(color)); 121 } 122 123 /// Gets the RGB color at position x, y. (0, 0) is top left. 124 public Color getPixel(int x, int y) 125 { 126 ubyte r, g, b; 127 SDL_GetRGB((cast(uint*) _handle.pixels)[x + y * width], _handle.format, &r, &g, &b); 128 return Color(r, g, b); 129 } 130 131 /// Gets the RGBA color at position x, y as R, G, B, A ubyte array. (0, 0) is top left. 132 public ubyte[] getPixelRGBA(int x, int y) 133 { 134 ubyte r, g, b, a; 135 SDL_GetRGBA((cast(uint*) _handle.pixels)[x + y * width], _handle.format, &r, &g, &b, &a); 136 return [r, g, b, a]; 137 } 138 139 /// Sets the RGB color at position x, y. (0, 0) is top left. 140 public void setPixel(int x, int y, Color color) 141 { 142 (cast(uint*) _handle.pixels)[x + y * width] = mapRGB(color); 143 } 144 145 /// Sets the RGBA color at position x, y. (0, 0) is top left. 146 public void setPixelRGBA(int x, int y, ubyte r, ubyte g, ubyte b, ubyte a) 147 { 148 (cast(uint*) _handle.pixels)[x + y * width] = mapRGBA(r, g, b, a); 149 } 150 }