1 // Written in the D programming language.
2 /++
3  + Authors: KanzakiKino
4  + Copyright: KanzakiKino 2018
5  + License: LGPL-3.0
6 ++/
7 module g4d.util.bitmap;
8 import gl3n.linalg;
9 import std.algorithm,
10        std.conv;
11 import core.stdc.stdlib,
12        core.stdc..string;
13 
14 /// A class of bitmap.
15 class Bitmap ( _Type = ubyte, size_t _LengthPerPixel = 4 )
16 {
17     /// Type of the number that shows color.
18     alias Type = _Type;
19 
20     /// Length to show the color of pixel.
21     enum  LengthPerPixel = _LengthPerPixel;
22 
23     protected Type* _data;
24     /// Readonly pointer to data.
25     const @property data () { return _data; }
26 
27     protected size_t _width, _rows;
28     /// Width of the bitmap.
29     const @property width () { return _width; }
30     /// Height of the bitmap.
31     const @property rows  () { return _rows; }
32 
33     /// Size of the bitmap.
34     const @property size  ()
35     {
36         return vec2i( width.to!int, rows.to!int );
37     }
38 
39     /// Length of the bitmap data.
40     const @property dataLength ()
41     {
42         return _width*_rows*LengthPerPixel;
43     }
44     /// Size of the bitmap data in byte.
45     const @property dataByteSize ()
46     {
47         return dataLength * Type.sizeof;
48     }
49 
50     ///
51     this ( vec2i sz )
52     {
53         _data = null;
54         resize( sz );
55         clear();
56     }
57     ///
58     this ( vec2i sz, Type* src )
59     {
60         this( sz );
61         memcpy( _data, src, dataByteSize );
62     }
63     ///
64     this ( vec2i sz, Type[] src )
65     {
66         this( sz );
67         memcpy( _data, src.ptr, dataByteSize );
68     }
69 
70     ///
71     ~this ()
72     {
73         dispose();
74     }
75     /// Releases all memories.
76     void dispose ()
77     {
78         if ( _data ) {
79             free( _data );
80             _data = null;
81         }
82         _width = 0;
83         _rows  = 0;
84     }
85 
86     protected void resize ( vec2i sz )
87     {
88         dispose();
89         _width = sz.x.to!uint;
90         _rows  = sz.y.to!uint;
91         _data  = cast(Type*)malloc( dataByteSize );
92     }
93 
94     /// Creates resized bitmap with the same format.
95     const auto conservativeResize ( vec2i sz )
96     {
97         enum lpp = LengthPerPixel;
98 
99         const srcw = width, srch = rows;
100         const src  = data;
101 
102         auto  result = new Bitmap!(Type,lpp)( sz );
103         const dstw   = result.width, dsth = result.rows;
104         auto  dst    = result._data;
105 
106         size_t dstx = 0, dsty = 0,
107                srci = 0, dsti = 0;
108 
109         for ( dsty = 0; dsty < dsth; dsty++ ) {
110             for ( dstx = 0; dstx < dstw; dstx++ ) {
111                 if ( dstx >= srcw || dsty >= srch ) {
112                     static foreach ( j; 0..lpp ) {
113                         dst[dsti++] = 0;
114                     }
115                 } else {
116                     static foreach ( j; 0..lpp ) {
117                         dst[dsti++] = src[srci++];
118                     }
119                 }
120             }
121         }
122         return result;
123     }
124 
125     /// Modifies a part of the bitmap.
126     void overwrite ( vec2i offset, typeof(this) bmp )
127     {
128         enum lpp = LengthPerPixel;
129 
130         const srcl = offset.x, srct = offset.y;
131         const srcr = srcl+bmp.width, srcb = srct+bmp.rows;
132         const src  = bmp.data;
133 
134         const dstw = width, dsth = rows;
135         auto  dst  = _data;
136 
137         assert( srcl >= 0 && srct >= 0 );
138         assert( srcr <= dstw && srcb <= dsth );
139 
140         size_t dstx = srcl, dsty = srct,
141                srci = 0, dsti = 0;
142 
143         for ( dsty = srct; dsty < srcb; dsty++ ) {
144             dsti = (dsty*dstw + srcl)*lpp;
145             for ( dstx = srcl; dstx < srcr; dstx++ ) {
146                 static foreach ( j; 0..lpp ) {
147                     dst[dsti++] = src[srci++];
148                 }
149             }
150         }
151     }
152 
153     /// Fills the bitmap data with 0.
154     void clear ()
155     {
156         memset( _data, 0, dataByteSize );
157     }
158 
159     /// To prove this is bitmap.
160     enum this_is_a_bitmap_class_of_g4d = true;
161 }
162 
163 ///
164 alias BitmapA    = Bitmap!(ubyte,1);
165 ///
166 alias BitmapRGB  = Bitmap!(ubyte,3);
167 ///
168 alias BitmapRGBA = Bitmap!(ubyte,4);
169 
170 ///
171 alias BitmapAf    = Bitmap!(float,1);
172 ///
173 alias BitmapRGBf  = Bitmap!(float,3);
174 ///
175 alias BitmapRGBAf = Bitmap!(float,4);
176 
177 /// Checks if T is bitmap.
178 enum isBitmap(T) =
179     __traits(hasMember,T,"this_is_a_bitmap_class_of_g4d");