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 }