1 /*
2  * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, graphics.draw module
5  */
6 
7 module PixelPerfectEngine.graphics.draw;
8 
9 import std.stdio;
10 import std.math;
11 import std.conv;
12 
13 import PixelPerfectEngine.graphics.bitmap;
14 import compose = CPUblit.composing;
15 import draw = CPUblit.draw;
16 import bmfont;
17 public import PixelPerfectEngine.graphics.fontsets;
18 public import PixelPerfectEngine.graphics.common;
19 //import system.etc;
20 /**
21  * Draws into a 8bit bitmap.
22  */
23 public class BitmapDrawer{
24 	public Bitmap8Bit output;
25 	public ubyte brushTransparency;
26 	///Creates the object alongside its output.
27 	public this(int x, int y){
28 		output = new Bitmap8Bit(x, y);
29 
30 	}
31 	///Draws a single line.
32 	public void drawLine(int xa, int xb, int ya, int yb, ubyte color){
33 		draw.drawLine(xa, ya, xb, yb, color, output.getPtr(), output.width);
34 	}
35 	///Draws a line using a brush.
36 	public void drawLine(int xa, int xb, int ya, int yb, Bitmap8Bit brush){
37 		if(xa == xb){
38 
39 			if(ya < yb){
40 				for(int j ; j < (yb - ya) ; j++){
41 					insertBitmap(xa, ya + j, brush);
42 				}
43 			}else{
44 				for(int j ; j > (yb - ya) ; j--){
45 					insertBitmap(xa, ya + j, brush);
46 				}
47 			}
48 			xa++;
49 			xb++;
50 
51 		}else if(ya == yb){
52 
53 			if(xa > xb){
54 				for(int j ; j < (xa - xb) ; j++){
55 					insertBitmap(xa + j, ya, brush);
56 				}
57 			}else{
58 				for(int j ; j > (xa - xb) ; j--){
59 					insertBitmap(xa + j, ya, brush);
60 				}
61 			}
62 			ya++;
63 			yb++;
64 
65 		}else{
66 			if(xa < xb){
67 				if(ya < yb){
68 					int xy = to!int(sqrt(to!double((xb - xa) * (xb - xa)) + ((yb - ya) * (yb - ya))));
69 
70 					for(int j ; j < xb - xa ; j++){
71 						int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j))));
72 						insertBitmap(xa + j, ya + y, brush);
73 					}
74 
75 				}else{
76 					int xy = to!int(sqrt(to!double((xb - xa) * (xb - xa)) + ((ya - yb) * (ya - yb))));
77 
78 					for(int j ; j < xb - xa ; j++){
79 						int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j))));
80 						insertBitmap(xa + j, ya - y, brush);
81 					}
82 
83 				}
84 			}else{
85 				if(ya < yb){
86 					int xy = to!int(sqrt(to!double((xa - xb) * (xa - xb)) + ((yb - ya) * (yb - ya))));
87 
88 					for(int j ; j > xb - xa ; j--){
89 						int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j))));
90 						insertBitmap(xa + j, ya + y, brush);
91 					}
92 
93 				}else{
94 					int xy = to!int(sqrt(to!double((xa - xb) * (xa - xb)) + ((ya - yb) * (ya - yb))));
95 
96 					for(int j ; j > xb - xa ; j--){
97 						int y = to!int(sqrt(to!double(xy * xy) - ((xa + j)*(xa + j))));
98 						insertBitmap(xa + j, ya - y, brush);
99 					}
100 
101 				}
102 			}
103 		}
104 	}
105 	///Inserts a bitmap using blitter.
106 	public void insertBitmap(int x, int y, Bitmap8Bit bitmap){
107 		ubyte* psrc = bitmap.getPtr, pdest = output.getPtr;
108 		pdest += x + output.width * y;
109 		int length = bitmap.width;
110 		for(int iy ; iy < bitmap.height ; iy++){
111 			compose.blitter(psrc,pdest,length);
112 			psrc += length;
113 			pdest += output.width;
114 		}
115 	}
116 	///Inserts a color letter.
117 	public void insertColorLetter(int x, int y, Bitmap8Bit bitmap, ubyte color){
118 		ubyte* psrc = bitmap.getPtr, pdest = output.getPtr;
119 		pdest += x + output.width * y;
120 		int length = bitmap.width;
121 		for(int iy ; iy < bitmap.height ; iy++){
122 			compose.textBlitter(psrc,pdest,length,color);
123 			psrc += length;
124 			pdest += output.width;
125 		}
126 	}
127 	///Inserts a midsection of the bitmap defined by slice
128 	public void insertBitmapSlice(int x, int y, Bitmap8Bit bitmap, Coordinate slice){
129 		ubyte* psrc = bitmap.getPtr, pdest = output.getPtr;
130 		pdest += x + output.width * y;
131 		int bmpWidth = bitmap.width;
132 		psrc += slice.left + bmpWidth * slice.top;
133 		int length = slice.width;
134 		for(int iy ; iy < slice.height ; iy++){
135 			compose.blitter(psrc,pdest,length);
136 			psrc += bmpWidth;
137 			pdest += output.width;
138 		}
139 	}
140 	///Inserts a midsection of the bitmap defined by slice as a color letter
141 	public void insertColorLetter(int x, int y, Bitmap8Bit bitmap, ubyte color, Coordinate slice){
142 		ubyte* psrc = bitmap.getPtr, pdest = output.getPtr;
143 		pdest += x + output.width * y;
144 		int bmpWidth = bitmap.width;
145 		psrc += slice.left + bmpWidth * slice.top;
146 		int length = slice.width;
147 		for(int iy ; iy < slice.height ; iy++){
148 			compose.textBlitter(psrc,pdest,length,color);
149 			psrc += bmpWidth;
150 			pdest += output.width;
151 		}
152 	}
153 	///Draws a rectangle.
154 	public void drawRectangle(int xa, int xb, int ya, int yb, ubyte color){
155 		drawLine(xa, xa, ya, yb, color);
156 		drawLine(xb, xb, ya, yb, color);
157 		drawLine(xa, xb, ya, ya, color);
158 		drawLine(xa, xb, yb, yb, color);
159 	}
160 
161 	public void drawRectangle(int xa, int xb, int ya, int yb, Bitmap8Bit brush){
162 		xa = xa + brush.width;
163 		ya = ya + brush.height;
164 		xb = xb - brush.width;
165 		yb = yb - brush.height;
166 		drawLine(xa, xa, ya, yb, brush);
167 		drawLine(xb, xb, ya, yb, brush);
168 		drawLine(xa, xb, ya, ya, brush);
169 		drawLine(xa, xb, yb, yb, brush);
170 	}
171 	///Draws a filled rectangle.
172 	public void drawFilledRectangle(int xa, int xb, int ya, int yb, ubyte color){
173 		draw.drawFilledRectangle(xa, ya, xb, yb, color, output.getPtr(), output.width);
174 	}
175 	///Fills the area with a pattern.
176 	public void patternFill(int xa, int ya, int xb, int yb, Bitmap8Bit pattern){
177 
178 	}
179 	///Draws texts. (deprecated, will be removed after Version 1.0.0)
180 	public deprecated void drawText(int x, int y, wstring text, Bitmap8Bit[wchar] fontSet, int style = 0){
181 		int length;
182 		for(int i ; i < text.length ; i++){
183 			length += fontSet[text[i]].width;
184 		}
185 		//writeln(text);
186 		if(style == 0){
187 			x = x - (length / 2);
188 			y -= fontSet['a'].height / 2;
189 		}
190 		foreach(wchar c ; text){
191 
192 			insertBitmap(x, y, fontSet[c]);
193 			x = x + fontSet[c].width;
194 		}
195 	}
196 	///Draws text to the given point.
197 	public void drawText(int x, int y, dstring text, Fontset!(Bitmap8Bit) fontset, uint style = 0){
198 		int length = fontset.getTextLength(text);
199 		//writeln(text);
200 		/+if(style == 0){
201 			x = x - (length / 2);
202 			y -= fontset.getSize() / 2;
203 		}else if(style == 2){
204 			y -= fontset.getSize();
205 		}+/
206 		if(style & FontFormat.HorizCentered)
207 			x = x - (length / 2);
208 		if(style & FontFormat.VertCentered)
209 			y -= fontset.getSize() / 2;
210 		foreach(dchar c ; text){
211 			const Font.Char chinfo = fontset.chars[c];
212 			const Coordinate letterSlice = Coordinate(chinfo.x, chinfo.y, chinfo.x + chinfo.width, chinfo.y + chinfo.height);
213 			insertBitmapSlice(x + chinfo.xoffset, y + chinfo.yoffset, fontset.pages[chinfo.page], letterSlice);
214 			x += chinfo.xadvance;
215 		}
216 	}
217 	///Draws colored text from monocromatic font.
218 	public void drawColorText(int x, int y, dstring text, Fontset!(Bitmap8Bit) fontset, ubyte color, uint style = 0){
219 		//color = 1;
220 		int length = fontset.getTextLength(text);
221 		if(style & FontFormat.HorizCentered)
222 			x = x - (length / 2);
223 		if(style & FontFormat.VertCentered)
224 			y -= fontset.getSize() / 2;
225 		if(style & FontFormat.RightJustified)
226 			x -= length;
227 		int fontheight = fontset.getSize();
228 		foreach(dchar c ; text){
229 			const Font.Char chinfo = fontset.chars[c];
230 			const Coordinate letterSlice = Coordinate(chinfo.x, chinfo.y, chinfo.x + chinfo.width, chinfo.y + chinfo.height);
231 			insertColorLetter(x + chinfo.xoffset, y + chinfo.yoffset, fontset.pages[chinfo.page], color, letterSlice);
232 			x += chinfo.xadvance;
233 		}
234 	}
235 
236 }
237 
238 enum FontFormat : uint{
239 	HorizCentered			=	0x1,
240 	VertCentered			=	0x2,
241 	RightJustified			=	0x10,
242 }