1 /** 2 This module introduces some Image implementations. 3 */ 4 module gfm.image.bitmap; 5 6 import std.c..string, 7 std.math; 8 9 import gfm.core.alignedbuffer, 10 gfm.core.memory, 11 gfm.math.vector; 12 13 import gfm.image.image; 14 15 /** 16 Simple planar image implementing the Image concept. 17 A Bitmap is mostly a triplet of (base address + dimension + stride). 18 Data can be owned or not. 19 */ 20 deprecated("Use ae.utils.graphics.image.Image instead") struct Bitmap(T) 21 { 22 nothrow: 23 public 24 { 25 alias T element_t; 26 27 /// Creates a Bitmap with owned memory. 28 this(vec2i dimension) nothrow 29 { 30 _data = alignedMalloc(dimension.x * dimension.y * T.sizeof, 64); 31 _dimension = dimension; 32 _stride = dimension.x * T.sizeof; 33 _owned = true; 34 } 35 36 /// Creates a Bitmap from borrowed memory. 37 this(T* data, vec2i dimension, ptrdiff_t stride) nothrow 38 { 39 _data = data; 40 _dimension = dimension; 41 _stride = stride; 42 _owned = false; 43 } 44 45 /// Creates a Bitmap from borrowed contiguous memory. 46 this(T* data, vec2i dimension) nothrow 47 { 48 this(data, dimension, dimension.x * T.sizeof); 49 } 50 51 /// Creates with a buffer whose lifetime should be greater than this. 52 this(AlignedBuffer!ubyte buffer, vec2i dimension) nothrow 53 { 54 size_t bytesNeeded = dimension.x * dimension.y * T.sizeof; 55 buffer.resize(bytesNeeded); 56 57 this(cast(T*)(buffer.ptr), dimension); 58 } 59 60 ~this() 61 { 62 if (_owned) 63 alignedFree(_data); 64 } 65 66 // postblit needed to duplicate owned data 67 this(this) nothrow 68 { 69 if (_owned) 70 { 71 size_t sizeInBytes = _dimension.x * _dimension.y * T.sizeof; 72 void* oldData = _data; 73 _data = alignedMalloc(sizeInBytes, 64); 74 memcpy(_data, oldData, sizeInBytes); 75 } 76 } 77 78 auto opAssign(Bitmap other) nothrow 79 { 80 _data = other._data; 81 _dimension = other._dimension; 82 _stride = other._stride; 83 _owned = other._owned; 84 return this; 85 } 86 87 /// Returns: A sub-bitmap from a Bitmap. 88 Bitmap subImage(vec2i position, vec2i dimension) 89 { 90 assert(contains(position)); 91 assert(contains(position + dimension - 1)); 92 93 return Bitmap(address(position.x, position.y), dimension, _stride); 94 } 95 96 @property 97 { 98 T* ptr() 99 { 100 return cast(T*) _data; 101 } 102 103 const(T)* ptr() const 104 { 105 return cast(T*) _data; 106 } 107 108 vec2i dimension() const pure 109 { 110 return _dimension; 111 } 112 113 /// Returns: Width of image in pixels. 114 int width() const pure 115 { 116 return _dimension.x; 117 } 118 119 /// Returns: Height of image in pixels. 120 int height() const pure 121 { 122 return _dimension.y; 123 } 124 125 } 126 127 T get(int i, int j) const pure 128 { 129 return *(address(i, j)); 130 } 131 132 void set(int i, int j, T e) 133 { 134 *(address(i, j)) = e; 135 } 136 137 bool isDense() const pure 138 { 139 return (_stride == _dimension.x * T.sizeof); 140 } 141 142 bool contains(vec2i point) 143 { 144 return (cast(uint)(point.x) < cast(uint)(_dimension.x)) 145 && (cast(uint)(point.y) < cast(uint)(_dimension.y)); 146 } 147 148 /// copy another Bitmap of same type and dimension 149 void copy(Bitmap source) 150 { 151 assert(dimension == source.dimension); 152 if (isDense() && source.isDense()) 153 { 154 size_t bytes = dimension.x * dimension.y * T.sizeof; 155 memcpy(_data, source._data, bytes); 156 } 157 else if(_stride == source._stride) 158 { 159 size_t bytes = _stride * dimension.y; 160 memcpy(_data, source._data, bytes); 161 } 162 else 163 { 164 void* dest = _data; 165 void* src = source._data; 166 size_t lineSize = abs(_stride); 167 168 for (size_t j = 0; j < dimension.y; ++j) 169 { 170 memcpy(dest, src, lineSize); 171 dest += _stride; 172 src += source._stride; 173 } 174 } 175 } 176 } 177 178 private 179 { 180 vec2i _dimension; 181 void* _data; 182 ptrdiff_t _stride; // in bytes 183 bool _owned; 184 185 T* address(int i, int j) pure 186 { 187 return cast(T*)(_data + _stride * j + T.sizeof * i); 188 } 189 190 const(T)* address(int i, int j) const pure // :| where is inout(this)? 191 { 192 return cast(T*)(_data + _stride * j + T.sizeof * i); 193 } 194 } 195 } 196 197 static assert(isImage!(Bitmap!int)); 198 static assert(isImage!(Bitmap!vec4ub)); 199 200 201 /** 202 A TiledBitmap is like a Bitmap but pixels are organized in tiles. 203 */ 204 deprecated("Use ae.utils.graphics.image.Image instead") 205 struct TiledBitmap(T, size_t tileWidth, size_t tileHeight) 206 { 207 static assert(tileWidth >= 1 && isPowerOf2(tileWidth)); 208 static assert(tileHeight >= 1 && isPowerOf2(tileHeight)); 209 210 nothrow: 211 public 212 { 213 enum tileSize = tileWidth * tileHeight; 214 alias T element_t; 215 alias T[tileSize] tile_t; 216 217 Bitmap!tile_t tiles; // a Bitmap of tiles 218 219 /// Create with owned memory, dimension is given in tiles 220 this(vec2i dimension) 221 { 222 tiles = Bitmap!tile_t(dimension); 223 } 224 225 T get(int i, int j) const pure 226 { 227 return *(address(i, j)); 228 } 229 230 void set(int i, int j, T e) 231 { 232 *(address(i, j)) = e; 233 } 234 235 @property 236 { 237 T* ptr() 238 { 239 return tiles.ptr; 240 } 241 242 const(T)* ptr() const 243 { 244 return tiles.ptr; 245 } 246 247 vec2i dimension() const pure 248 { 249 return tiles.dimension * vec2i(tileWidth, tileHeight); 250 } 251 252 int width() const pure 253 { 254 return tiles.width * tileWidth; 255 } 256 257 int height() const pure 258 { 259 return tiles.height * tileHeight; 260 } 261 } 262 } 263 264 private 265 { 266 enum X_MASK = tileWidth - 1, 267 Y_MASK = tileHeight - 1, 268 X_SHIFT = ilog2(tileWidth), 269 Y_SHIFT = ilog2(tileHeight); 270 271 T* address(int i, int j) pure 272 { 273 tile_t* tile = tiles.address(i >> X_SHIFT, j >> Y_SHIFT); 274 size_t tileIndex = tileWeight * (i & X_MASK) + (j & Y_MASK); 275 return tile.ptr + tileIndex; 276 } 277 278 const(T)* address(int i, int j) const pure 279 { 280 tile_t* tile = tiles.address(i >> X_SHIFT, j >> Y_SHIFT); 281 size_t tileIndex = tileWeight * (i & X_MASK) + (j & Y_MASK); 282 return tile.ptr + tileIndex; 283 } 284 } 285 }