1 module rip.concepts.ranges;
2 
3 private
4 {
5 	import std.algorithm;
6 	import std.stdio;
7 	import std.range;
8 
9 	import rip.concepts.color;
10 	import rip.concepts.surface;
11 	import rip.concepts.templates;
12 }
13 
14 /++
15 +  	Creates surface from input range of pixels
16 +	Params:
17 +		r  			= input range
18 +		width		= width of new surface
19 +		height		= height of new surface
20 +	Returns:
21 		Created surface
22 +/
23 Surface toSurface(Range)(Range r, size_t width, size_t height)
24 	if (isPixelRange!Range)
25 {
26 	Surface surface = new Surface(width, height);
27 
28 	auto s = width * height;
29 
30 	foreach(i; 0..s) {
31 		surface[i] = r.front;
32 		r.popFront();
33 	}
34 
35 	return surface;
36 }
37 
38 auto createSurfaceRange(Surface surface) {
39 	struct SurfaceRange {
40 		Surface surface;
41 		uint i;
42 
43 		this(Surface surface, uint i = 0) {
44 			this.surface = surface;
45 			this.i = i;
46 		}
47 
48 		RGBColor front() {
49 			return surface[i];
50 		}
51 
52 		void popFront() {
53 			i++;
54 		}
55 
56 		bool empty() {
57 			return i == surface.getArea!uint; 
58 		}
59 
60 		auto length() {
61 			return surface.getArea!size_t;
62 		}
63 
64 		auto save() {
65 			return SurfaceRange(surface, i);
66 		}
67 	}
68 
69 	return SurfaceRange(surface);
70 }
71 /++
72 +  	Creates biderectional range from other range of pixels
73 +	Params:
74 +		r  			= input range
75 +	Returns:
76 		Biderectional range
77 +/
78 auto createPixels(Range)(Range r)
79 {
80 	struct PixelRange
81 	{
82 		private RGBColor[] pixels;
83 
84 		this(Range)(Range r)
85 			if (is(ElementType!Range == RGBColor))
86 		{
87 			pixels = r.array;
88 		}
89 
90 		@property
91 		{
92 			RGBColor back()
93 			{
94 				return pixels.back;
95 			}
96 
97 			bool empty()
98 			{
99 				return pixels.empty;
100 			}
101 
102 			RGBColor front()
103 			{
104 				return pixels.front;
105 			}
106 		}
107 
108 		void popFront()
109 		{
110 			pixels.popFront();
111 		}
112 
113 		void popBack()
114 		{
115 			pixels.popBack();
116 		}
117 
118 		PixelRange save()
119 		{
120 			return this;
121 		}
122 	}
123 
124 	return PixelRange(r);
125 }
126 
127 /++
128 +  	Lazy and fast version of createFences.
129 +	P.S. FOR DETAILS SEE SOURCE
130 +	Params:
131 +		surface 		= input surface
132 +		width			= fence width
133 +		height			= fence height
134 +	Returns:
135 +		Biderectional range of pixels range[width * height]
136 +/
137 auto createFencesNew(T, U)(Surface surface, T width, U height) {
138 
139 		/++
140 		+  	Struct for calculation one fence
141 		+/
142 		struct Fence {
143 			uint surfacePixelIndex;
144 			uint processedIndex = 0;
145 
146 			uint x, y;
147 			uint halfFenceWidth, halfFenceHeight;
148 
149 			/+
150 			+	Calculate and return pixel
151 			+	Params:
152 			+		index 		= index of pixel
153 			+	Returns:
154 					RGBColor
155 			+/
156 
157 			auto opIndex(uint index) {
158 				uint h = cast(int)(index % width);
159 				uint w = cast(int)(index / width);
160 
161 				auto indexW = x + (halfFenceWidth - w);
162 				auto indexH = y + (halfFenceHeight - h);
163 
164 				if ((indexW < 0) || (indexH >= surface.getArea!int)) {
165 					return new RGBColor(255, 255, 255);
166 				}
167 				else {
168 					return surface[indexW, indexH];
169 				}
170 			}
171 
172 			/+
173 			+	Params:
174 			+		surfacePixelIndex 		= index of main pixel for fence
175 			+		halfFenceWidth 			= ...
176 			+		halfFenceHeight 		= ...
177 			+	Returns:
178 			+		RGBColor
179 			+/
180 			this(	uint surfacePixelIndex,
181 					uint halfFenceWidth, uint halfFenceHeight) {
182 
183 				this.surfacePixelIndex = surfacePixelIndex;
184 				this.halfFenceWidth = halfFenceWidth;
185 				this.halfFenceHeight = halfFenceHeight;
186 
187 				x = surfacePixelIndex % surface.getWidth!uint;
188 				y = surfacePixelIndex / surface.getWidth!uint;
189 			}
190 
191 
192 			auto front() {
193 				return this.opIndex(processedIndex);
194 			}
195 
196 			void popFront() {
197 				processedIndex++;
198 			}
199 
200 			bool empty() {
201 				return processedIndex == width * height;
202 			}
203 		}
204 
205 		struct FenceRange {
206 			int processedIndex = 0;
207 
208 			Surface _surface;
209 			uint halfFenceWidth, halfFenceHeight;
210 
211 			this(Surface _surface) {
212 				this._surface = _surface;
213 
214 				halfFenceWidth = cast(uint) width / 2;
215 				halfFenceHeight = cast(uint) height / 2;
216 			}
217 
218 			Fence front() {
219 				return Fence(	processedIndex,
220 								halfFenceWidth, halfFenceHeight);
221 			}
222 
223 			void popFront() {
224 				processedIndex++;
225 			}
226 
227 			bool empty() {
228 				return processedIndex == surface.getArea!int;
229 			}
230 		}
231 
232 		return FenceRange(surface);
233 }
234 
235 /++
236 +  	Returns fences range from surface
237 +	P.S. FOR DETAILS SEE SOURCE
238 +	Params:
239 +		surface 		= input surface
240 +		width			= fence width
241 +		height			= fence height
242 +	Returns:
243 		Biderectional range of pixels range[width * height]
244 +/
245 auto createFences(T, U)(Surface surface, T width, U height)
246 {
247 	alias Range = typeof(createPixels([RGBColor.init]));
248 
249 	struct FenceRange(T, U, Range)
250 		if (allArithmetic!(T, U))
251 	{
252 		private Range[] pixelsRange;
253 
254 		this(T, U)(Surface surface, T width, U height)
255 			if (allArithmetic!(T, U))
256 		{
257 			int halfFenceWidth = cast(int) width / 2;
258 			int halfFenceHeight = cast(int) height / 2;
259 
260 			for (int i = 0; i < surface.getHeight!int; i++)
261 			{
262 				for (int j = 0; j < surface.getWidth!int; j++)
263 				{
264 					ElementType!Range[] fenceAccumulator;
265 
266 					for (int w = 0; w < cast(int) width; w++)
267 					{
268 						for (int h = 0; h < cast(int) height; h++)
269 						{
270 							auto indexW = j + (halfFenceWidth - w);
271 							auto indexH = i + (halfFenceHeight - h);
272 							if ((indexW < 0) || (indexH >= surface.getArea!int))
273 							{
274 								fenceAccumulator ~= new RGBColor(0, 0, 0);
275 							}
276 							else
277 							{
278 								fenceAccumulator ~= surface[indexW, indexH];
279 							}
280 						}
281 					}
282 
283 					pixelsRange ~= createPixels(fenceAccumulator);
284 				}
285 			}
286 		}
287 
288 		@property
289 		{
290 			Range back()
291 			{
292 				return pixelsRange.back;
293 			}
294 
295 			bool empty()
296 			{
297 				return (pixelsRange.length == 0);
298 			}
299 
300 			Range front()
301 			{
302 				return pixelsRange.front;
303 			}
304 		}
305 
306 		void popFront()
307 		{
308 			pixelsRange.popFront;
309 		}
310 
311 		void popBack()
312 		{
313 			pixelsRange.popBack;
314 		}
315 	}
316 
317 	return FenceRange!(T, U, Range)(surface, width, height);
318 }