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 }