1 module magicalrainbows.gradient; 2 3 import magicalrainbows.formats; 4 import magicalrainbows.utils; 5 6 struct Gradient { 7 ulong index; 8 ulong count; 9 RGB888 start; 10 RGB888 end; 11 RGB888 front; 12 void popFront() @safe pure { 13 popFrontN(1); 14 } 15 void popFrontN(size_t steps) @safe pure { 16 index += steps; 17 double redInc = ((cast(double)end.red - cast(double)start.red) / cast(double)(count-1)); 18 double greenInc = ((cast(double)end.green - cast(double)start.green) / cast(double)(count-1)); 19 double blueInc = ((cast(double)end.blue - cast(double)start.blue) / cast(double)(count-1)); 20 front.red = cast(ubyte)(start.red + redInc * index); 21 front.green = cast(ubyte)(start.green + greenInc * index); 22 front.blue = cast(ubyte)(start.blue + blueInc * index); 23 } 24 bool empty() @safe pure { 25 return index >= count; 26 } 27 this(T)(T from, T to, ulong steps) if(isColourFormat!T){ 28 count = steps; 29 start = front = from.convert!RGB888; 30 end = to.convert!RGB888; 31 } 32 } 33 /// 34 @safe pure unittest { 35 import std.algorithm; 36 import std.range; 37 bool closeEnough(Range1, Range2)(Range1 a, Range2 b) { 38 bool similar(uint v, uint v2) { 39 return !!v.among(v2 - 1, v2, v2 + 1); 40 } 41 foreach (pair; zip(a,b)) { 42 if (!similar(pair[0].red, pair[1].red) || !similar(pair[0].green, pair[1].green) || !similar(pair[0].blue, pair[1].blue)) { 43 return false; 44 } 45 } 46 return true; 47 } 48 assert(closeEnough(Gradient(RGB888(255,0,0), RGB888(0,0,255), 20), 49 only( 50 RGB888(255, 0, 0), 51 RGB888(241, 0, 13), 52 RGB888(228, 0, 26), 53 RGB888(214, 0, 40), 54 RGB888(201, 0, 53), 55 RGB888(187, 0, 67), 56 RGB888(174, 0, 80), 57 RGB888(161, 0, 93), 58 RGB888(147, 0, 107), 59 RGB888(134, 0, 120), 60 RGB888(120, 0, 134), 61 RGB888(107, 0, 147), 62 RGB888(93, 0, 161), 63 RGB888(80, 0, 174), 64 RGB888(67, 0, 187), 65 RGB888(53, 0, 201), 66 RGB888(40, 0, 214), 67 RGB888(26, 0, 228), 68 RGB888(13, 0, 241), 69 RGB888(0, 0, 254) 70 ) 71 )); 72 }