1 module CPUblit.draw;
2 
3 import CPUblit.colorspaces;
4 /**
5  * Draws a line using a fixed point method. Is capable of drawing lines diagonally.
6  */
7 public void drawLine(T)(int x0, int y0, int x1, int y1, T color, T* dest, size_t destWidth) @nogc nothrow pure {
8 	if(x1 < x0){
9 		const int k = x1;
10 		x1 = x0;
11 		x0 = k;
12 	}
13 	if(y1 < y0){
14 		const int k = y1;
15 		y1 = y0;
16 		y0 = k;
17 	}
18 	const int dx = x1 - x0;
19 	const int dy = y1 - y0;
20 	if(!dx || !dy){
21 		if(!dy){
22 			sizediff_t offset = destWidth * y1;
23 			for(int x = x0; x <= x1; x++){
24 				dest[offset + x] = color;
25 			}
26 		}else{
27 			sizediff_t offset = destWidth * y0 + x0;
28 			for(int y = y0; y <= y1; y++){
29 				dest[offset] = color;
30 				offset += destWidth;
31 			}
32 		}
33 	}else if(dx>=dy){
34 		int D = 2*dy - dx;
35 		int y = y0;
36 		for(int x = x0 ; x <= x1 ; x++){
37 			dest[destWidth * y + x] = color;
38 			if(D > 0){
39 				y += 1;
40 				D -= 2 * dx;
41 			}
42 			D += 2 * dx;
43 		}
44 	}else{
45 		int D = 2 * dx - dy;
46 		int x = x0;
47 		for(int y = y0 ; y <= y1 ; y++){
48 			dest[destWidth * y + x] = color;
49 			if(D > 0){
50 				x += 1;
51 				D -= 2 * dy;
52 			}
53 			D += 2 * dy;
54 		}
55 	}
56 }
57 /**
58  * Draws a line with the given pattern.
59  */
60 public void drawLinePattern(T)(int x0, int y0, int x1, int y1, T[] pattern, T* dest, size_t destWidth) @nogc nothrow pure {
61 	if(x1 < x0){
62 		const int k = x1;
63 		x1 = x0;
64 		x0 = k;
65 	}
66 	if(y1 < y0){
67 		const int k = y1;
68 		y1 = y0;
69 		y0 = k;
70 	}
71 	const int dx = x1 - x0;
72 	const int dy = y1 - y0;
73 	size_t patternPos;
74 	if(!dx || !dy){
75 		if(!dy){
76 			sizediff_t offset = destWidth * y1;
77 			for(int x = x0 ; x <= x1 ; x++){
78 				dest[offset + x] = pattern[(patternPos++) % pattern.length];
79 				
80 			}
81 		}else{
82 			sizediff_t offset = destWidth * y0 + x0;
83 			for(int y = y0 ; y <= y1 ; y++){
84 				dest[offset] = pattern[(patternPos++) % pattern.length];
85 				
86 				offset += destWidth;
87 			}
88 		}
89 	}else if(dx>=dy){
90 		int D = 2 * dy - dx;
91 		int y = y0;
92 		for(int x = x0 ; x <= x1 ; x++){
93 			dest[destWidth * y + x] = pattern[(patternPos++) % pattern.length];
94 			//patternPos = patternPos + 1 < pattern.length ? patternPos + 1 : 0;
95 			if(D > 0){
96 				y += 1;
97 				D -= 2 * dx;
98 			}
99 			D += 2 * dx;
100 		}
101 	}else{
102 		int D = 2 * dx - dy;
103 		int x = x0;
104 		for(int y = y0 ; y <= y1 ; y++){
105 			dest[destWidth * y + x] = pattern[(patternPos++) % pattern.length];
106 			//patternPos = patternPos + 1 < pattern.length ? patternPos + 1 : 0;
107 			if(D > 0){
108 				x += 1;
109 				D -= 2 * dy;
110 			}
111 			D += 2 * dy;
112 		}
113 	}
114 }
115 /**
116  * Draws a rectangle.
117  */
118 public void drawRectangle(T)(int x0, int y0, int x1, int y1, T color, T*dest, size_t destWidth) @nogc nothrow pure {
119 	/+static if(!(T.stringof == "ubyte" || T.stringof == "ushort" || T.stringof == "uint" || T.stringof == "Color32Bit")) {
120 		static assert(0, "Template parameter '" ~ T.stringof ~ "' is not supported!");
121 	}+/
122 	drawLine(x0,y0,x0,y1,color,dest,destWidth);
123 	drawLine(x0,y0,x1,y0,color,dest,destWidth);
124 	drawLine(x1,y0,x1,y1,color,dest,destWidth);
125 	drawLine(x0,y1,x1,y1,color,dest,destWidth);
126 }
127 /**
128  * Draws a filled rectangle.
129  */
130 public void drawFilledRectangle(T) (int x0, int y0, int x1, int y1, T color, T* dest, size_t destWidth) @nogc nothrow 
131 		pure {
132 	import core.stdc..string : memset;
133 	import core.stdc.wchar_ : wmemset;
134 	if(x1 < x0){
135 		const int k = x1;
136 		x1 = x0;
137 		x0 = k;
138 	}
139 	if(y1 < y0){
140 		const int k = y1;
141 		y1 = y0;
142 		y0 = k;
143 	}
144 	int width = x1 - x0;
145 	dest += x0;
146 	for (int y = y0 ; y <= y1 ; y++) {
147 		static if (is(T == ubyte)) {
148 			memset(dest + (y * destWidth), color, width);
149 		} else static if (is(T == ushort)) {
150 			T* dest0 = dest + (y * destWidth);
151 			for (int x ; x < width ; x++) {
152 				dest0[x] = color;
153 			}
154 		} else static if (is(T == uint)) {
155 			wmemset(dest + (y * destWidth), color, width);
156 		}
157 	}
158 }
159 /**
160  * Flood fills a bitmap at the given point.
161  */
162 public void floodFill(T)(int x0, int y0, T color, T* dest, size_t destWidth, size_t destLength, 
163 		T transparencyIndex = T.init) @nogc nothrow pure {
164 	//check for boundaries of the bitmap
165 	if(x0 > 0 && y0 > 0){
166 		const size_t yOffset = y0 * destWidth;
167 		if(x0 < destWidth && yOffset < destLength){
168 			//check if the current pixel is "transparent"
169 			T* p = dest + yOffset + x0;
170 			if(transparencyIndex == *(p)){
171 				*p = color;
172 				floodFill(x0 + 1, y0, color, dest, destWidth, destLength, transparencyIndex);
173 				floodFill(x0 - 1, y0, color, dest, destWidth, destLength, transparencyIndex);
174 				floodFill(x0, y0 + 1, color, dest, destWidth, destLength, transparencyIndex);
175 				floodFill(x0, y0 - 1, color, dest, destWidth, destLength, transparencyIndex);
176 			}
177 		}
178 	}
179 }
180 unittest{
181 	import std.conv : to;
182 	{	//test if only the first line is being drawn.
183 		ubyte[256*256] virtualImage;
184 		drawLine(0, 0, 255, 0, 0xFF, virtualImage.ptr, 256);
185 		for(int x ; x < 256 ; x++){
186 			assert(virtualImage[x] == 0xFF);
187 		}
188 		for(int x ; x < 256 ; x++){
189 			assert(virtualImage[256 + x] == 0x00);
190 		}
191 	}
192 	{	//test if only the first row is being drawn.
193 		ubyte[256*256] virtualImage;
194 		drawLine(0, 0, 0, 255, 0xFF, virtualImage.ptr, 256);
195 		for(int y ; y < 256 ; y++){
196 			assert(virtualImage[256 * y] == 0xFF);
197 		}
198 		for(int y ; y < 256 ; y++){
199 			assert(virtualImage[(256 * y) + 1] == 0x00);
200 		}
201 	}
202 	{	//test if only the first line is being drawn.
203 		ubyte[256*256] virtualImage;
204 		ubyte[3] pattern = [0x20,0xFF,0x33];
205 		drawLinePattern(0, 0, 255, 0, pattern, virtualImage.ptr, 256);
206 		for(int x ; x < 256 ; x++){
207 			assert(virtualImage[x] == pattern[x%3], "Error at position " ~ to!string(x));
208 		}
209 		for(int x ; x < 256 ; x++){
210 			assert(virtualImage[256 + x] == 0x00);
211 		}
212 	}
213 	
214 }