1 /* 2 * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license. 3 * 4 * Pixel Perfect Engine, graphics.bitmap module 5 */ 6 7 module PixelPerfectEngine.graphics.bitmap; 8 import std.bitmanip; 9 import PixelPerfectEngine.system.exc; 10 public import PixelPerfectEngine.system.advBitArray; 11 public import PixelPerfectEngine.graphics.common; 12 13 /** 14 * Bitmap attributes, mainly for layers. 15 */ 16 public struct BitmapAttrib{ 17 mixin(bitfields!( 18 bool, "horizMirror", 1, 19 bool, "vertMirror", 1, 20 ubyte, "priority", 6)); 21 @nogc public this(bool horizMirror, bool vertMirror, ubyte priority = 0){ 22 this.horizMirror = horizMirror; 23 this.vertMirror = vertMirror; 24 this.priority = priority; 25 } 26 } 27 28 /** 29 * Base bitmap functions, for enable the use of the same . 30 */ 31 abstract class ABitmap{ 32 private Color* palettePtr; ///Set this to either a portion of the master palette or to a self-defined place. Not used in 32 bit bitmaps. 33 private int iX; 34 private int iY; 35 /** 36 * Returns the width of the bitmap. 37 */ 38 @property @nogc public int width(){ 39 return iX; 40 } 41 /** 42 * Returns the height of the bitmap. 43 */ 44 @property @nogc public int height(){ 45 return iY; 46 } 47 abstract AdvancedBitArray generateStandardCollisionModel(); 48 /** 49 * Returns the palette pointer. 50 */ 51 @nogc public Color* getPalettePtr(){ 52 return palettePtr; 53 } 54 /** 55 * Sets the palette pointer. Make sure that you set it to a valid memory location. 56 */ 57 @nogc public void setPalettePtr(Color* p){ 58 palettePtr = p; 59 } 60 /** 61 * Returns the wordlength of the type 62 */ 63 abstract @nogc @property string wordLengthByString(); 64 /** 65 * Clears the whole bitmap to a transparent color. 66 */ 67 abstract @nogc void clear(); 68 } 69 /* 70 * S: Wordlength by usage. Possible values: 71 * - QB: QuadByte or 2Bit (currently unimplemented) 72 * - HB: HalfByte or 4Bit 73 * - B: Byte or 8Bit 74 * - HW: HalfWord or 16Bit 75 * - W: Word or 32Bit 76 * T: Type. Possible values: 77 * - ubyte: 8Bit or under 78 * - ushort: 16Bit 79 * - Color: 32Bit 80 */ 81 alias Bitmap4Bit = Bitmap!("HB",ubyte); 82 alias Bitmap8Bit = Bitmap!("B",ubyte); 83 alias Bitmap16Bit = Bitmap!("HW",ushort); 84 alias Bitmap32Bit = Bitmap!("W",Color); 85 /** 86 * Implements a bitmap with variable bit depth. Use the aliases to initialize them. 87 * Note for 16Bit bitmap: It's using the master palette, It's not implementing any 16 bit RGB or RGBA color space directly. Can implement such 88 * colorspaces via proper lookup tables. 89 * Note for 4Bit bitmap: It's width needs to be an even number (for rendering simplicity), otherwise it'll cause an exception. 90 */ 91 public class Bitmap(string S,T) : ABitmap{ 92 T[] pixels; 93 static if(S != "HB" && S != "QB"){ 94 /** 95 * Resizes the bitmap. 96 * NOTE: It's not for scaling. 97 */ 98 public void resize(int x, int y){ 99 pixels.length=x*y; 100 iX = x; 101 iY = y; 102 } 103 ///Returns the pixel at the given position. 104 @nogc public T readPixel(int x, int y){ 105 return pixels[x+(iX*y)]; 106 } 107 ///Writes the pixel at the given position. 108 @nogc public void writePixel(int x, int y, T color){ 109 pixels[x+(iX*y)]=color; 110 } 111 } 112 static if(S == "HB"){ 113 ///Creates an empty bitmap. 114 this(int x, int y, Color* palettePtr = null){ 115 if(x & 1) 116 x++; 117 iX=x; 118 iY=y; 119 pixels.length=(x*y)/2; 120 this.palettePtr = palettePtr; 121 } 122 ///Creates a bitmap from an array. 123 this(ubyte[] p, int x, int y, Color* palettePtr = null){ 124 if (p.length/2 < x * y || x & 1) 125 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 126 iX=x; 127 iY=y; 128 pixels=p; 129 this.palettePtr = palettePtr; 130 } 131 ///Returns the pixel at the given position. 132 @nogc public ubyte readPixel(int x, int y){ 133 if(x & 1) 134 return (pixels[x>>1+(iX*y)])>>4; 135 else 136 return pixels[x>>1+(iX*y)] & 0x0F; 137 } 138 ///Writes the pixel at the given position. 139 @nogc public void writePixel(int x, int y, ubyte color){ 140 if(x & 1) color<<=4; 141 x/=2; 142 pixels[x+(iX*y)]|= color; 143 } 144 public void resize(int x,int y){ 145 if(x & 1) 146 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 147 pixels.length=x*y; 148 iX = x; 149 iY = y; 150 } 151 152 }else static if(S == "B"){ 153 ///Creates an empty bitmap. 154 this(int x, int y, Color* palettePtr = null){ 155 if(x < 0 || y < 0) 156 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 157 iX=x; 158 iY=y; 159 pixels.length=x*y; 160 this.palettePtr = palettePtr; 161 } 162 ///Creates a bitmap from an array. 163 this(ubyte[] p, int x, int y, Color* palettePtr = null){ 164 if (p.length < x * y) 165 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 166 iX=x; 167 iY=y; 168 pixels=p; 169 this.palettePtr = palettePtr; 170 } 171 }else static if(S == "HW"){ 172 ///Creates an empty bitmap. 173 this(int x, int y){ 174 if(x < 0 || y < 0) 175 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 176 iX=x; 177 iY=y; 178 pixels.length=x*y; 179 } 180 ///Creates a bitmap from an array. 181 this(ushort[] p, int x, int y){ 182 if (p.length < x * y) 183 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 184 iX=x; 185 iY=y; 186 pixels=p; 187 } 188 }else static if(S == "W"){ 189 ///Creates an empty bitmap. 190 public this(int x, int y){ 191 if(x < 0 || y < 0) 192 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 193 iX = x; 194 iY = y; 195 pixels.length = x * y; 196 } 197 ///Creates a bitmap from an array. 198 public this(Color[] p, int x, int y){ 199 if (p.length < x * y) 200 throw new BitmapFormatException("Incorrect Bitmap size exception!"); 201 iX = x; 202 iY = y; 203 this.pixels = p; 204 } 205 }else static assert("Template argument \"" ~ bitmapType ~ "\" not supported!"); 206 static if(S == "B" || S == "HW"){ 207 /** 208 * Offsets all indexes in the bitmap by a certain value. Keeps zeroth index (usually for transparency) if needed. Useful when converting bitmaps. 209 */ 210 public @nogc void offsetIndexes(ushort offset, bool keepZerothIndex = true){ 211 for(int i ; i < pixels.length ; i++){ 212 if(!(pixels[i] == 0 && keepZerothIndex)){ 213 pixels[i] += offset; 214 } 215 } 216 } 217 } 218 static if(S == "W"){ 219 override public AdvancedBitArray generateStandardCollisionModel(){ 220 AdvancedBitArray result = new AdvancedBitArray(iX * iY); 221 for(int i ; i < iX * iY ; i++){ 222 Color pixel = readPixel(i, 0); 223 if(pixel.alpha != 0){ 224 result[i] = true; 225 } 226 } 227 return result; 228 } 229 override @nogc void clear(){ 230 for(int i ; i < pixels.length ; i++){ 231 pixels[i] = Color(0x0); 232 } 233 } 234 }else{ 235 override public AdvancedBitArray generateStandardCollisionModel(){ 236 AdvancedBitArray result = new AdvancedBitArray(iX * iY); 237 for(int i ; i < iX * iY ; i++){ 238 T pixel = readPixel(i, 0); 239 if(pixel != 0){ 240 result[i] = true; 241 } 242 } 243 return result; 244 } 245 override @nogc void clear(){ 246 for(int i ; i < pixels.length ; i++){ 247 pixels[i] = 0; 248 } 249 } 250 } 251 @nogc public T* getPtr(){ 252 return pixels.ptr; 253 } 254 override @nogc @property string wordLengthByString() { 255 return S; 256 } 257 258 } 259 260 261 /** 262 * Bypasses the transparency on color no.0, no.1 is set to red. 263 */ 264 /*static const Color[16] errorPalette; 265 266 public ABitmap generateDummyBitmap(int x, int y, wchar c){ 267 Color* p = errorPalette.ptr; 268 Bitmap4Bit result = new Bitmap4Bit(x, y, p); 269 270 return result; 271 }*/