1 module unexpected.rando.palette; 2 3 import reversineer; 4 import magicalrainbows.formats; 5 import std.random : Random, uniform; 6 7 import unexpected.rando.common; 8 9 enum ColourRandomizationLevel { 10 randomHue, 11 shiftHue, 12 multHue, 13 shiftInverseHue, 14 multInverseHue, 15 randomSaturation, 16 shiftSaturation, 17 multSaturation, 18 shiftInverseSaturation, 19 multInverseSaturation, 20 randomValue, 21 shiftValue, 22 multValue, 23 shiftInverseValue, 24 multInverseValue, 25 absurd, 26 extreme 27 } 28 29 T[] randomizePalette(T)(T[] input, ColourRandomizationLevel randomizationLevel, uint seed) { 30 import std.algorithm.iteration : map; 31 import std.algorithm.comparison : min; 32 import std.array : array; 33 import std.random : Random, uniform01; 34 35 auto rand = Random(seed); 36 const randomConstantH0 = rand.uniform01(); 37 const randomConstantH1 = rand.uniform01(); 38 const randomConstantH2 = rand.uniform01(); 39 const randomConstantS0 = rand.uniform01(); 40 const randomConstantS1 = rand.uniform01(); 41 const randomConstantS2 = rand.uniform01(); 42 const randomConstantV0 = rand.uniform01(); 43 const randomConstantV1 = rand.uniform01(); 44 const randomConstantV2 = rand.uniform01(); 45 HSVA!float genRandomHSV(HSVA!float input, ColourRandomizationLevel level) { 46 bool shiftHue; 47 bool multHue; 48 bool randomizeHue; 49 bool invertHue; 50 bool shiftSaturation; 51 bool multSaturation; 52 bool randomizeSaturation; 53 bool invertSaturation; 54 bool shiftValue; 55 bool multValue; 56 bool randomizeValue; 57 bool invertValue; 58 bool useRGB; 59 final switch (randomizationLevel) { 60 case ColourRandomizationLevel.shiftHue: 61 shiftHue = true; 62 break; 63 case ColourRandomizationLevel.multHue: 64 multHue = true; 65 break; 66 case ColourRandomizationLevel.shiftInverseHue: 67 invertHue = true; 68 shiftHue = true; 69 break; 70 case ColourRandomizationLevel.multInverseHue: 71 invertHue = true; 72 multHue = true; 73 break; 74 case ColourRandomizationLevel.randomHue: 75 randomizeHue = true; 76 break; 77 case ColourRandomizationLevel.randomSaturation: 78 randomizeSaturation = true; 79 break; 80 case ColourRandomizationLevel.shiftSaturation: 81 shiftSaturation = true; 82 break; 83 case ColourRandomizationLevel.multSaturation: 84 multSaturation = true; 85 break; 86 case ColourRandomizationLevel.shiftInverseSaturation: 87 invertSaturation = true; 88 shiftSaturation = true; 89 break; 90 case ColourRandomizationLevel.multInverseSaturation: 91 invertSaturation = true; 92 multSaturation = true; 93 break; 94 case ColourRandomizationLevel.randomValue: 95 randomizeValue = true; 96 break; 97 case ColourRandomizationLevel.shiftValue: 98 shiftValue = true; 99 break; 100 case ColourRandomizationLevel.multValue: 101 multValue = true; 102 break; 103 case ColourRandomizationLevel.shiftInverseValue: 104 invertValue = true; 105 shiftValue = true; 106 break; 107 case ColourRandomizationLevel.multInverseValue: 108 invertValue = true; 109 multValue = true; 110 break; 111 case ColourRandomizationLevel.absurd: 112 randomizeHue = true; 113 randomizeSaturation = true; 114 randomizeValue = true; 115 break; 116 case ColourRandomizationLevel.extreme: 117 useRGB = true; 118 break; 119 } 120 if (useRGB) { 121 return RGB888( 122 rand.uniform!ubyte(), 123 rand.uniform!ubyte(), 124 rand.uniform!ubyte() 125 ).toHSVA!float; 126 } else { 127 float hue = input.hue; 128 float saturation = input.saturation; 129 float value = input.value; 130 if (randomizeHue) { 131 hue = randomConstantH0; 132 } 133 if (randomizeSaturation) { 134 saturation = randomConstantS0; 135 } 136 if (randomizeValue) { 137 value = randomConstantV0; 138 } 139 if (shiftHue) { 140 hue += randomConstantH1; 141 } 142 if (invertHue) { 143 hue = 1.0 - hue; 144 } 145 if (invertSaturation) { 146 saturation = 1.0 - saturation; 147 } 148 if (invertValue) { 149 value = 1.0 - value; 150 } 151 if (multHue) { 152 hue *= randomConstantH2 * 2.0; 153 } 154 if (shiftSaturation) { 155 hue += randomConstantS1; 156 } 157 if (multSaturation) { 158 hue *= randomConstantS2 * 2.0; 159 } 160 if (shiftValue) { 161 value += randomConstantV1; 162 } 163 if (multValue) { 164 value *= randomConstantV2 * 2.0; 165 } 166 return HSVA!float(hue % 1.0, saturation % 1.0, value % 1.0, input.alpha); 167 } 168 } 169 return input.map!(x => x.toHSVA!float).map!(x => genRandomHSV(x, randomizationLevel)).map!(x => x.toRGB!(T, float)).array; 170 } 171 172 void randomizePalette(Palette paletteOptions, T)(ref T field, ref Random rng, ref uint seed, const Options options) { 173 if (!paletteOptions.shareSeed) { 174 seed = rng.uniform!uint; 175 } 176 const start = paletteOptions.dontSkipFirst ? 0 : 1; 177 field[start .. $] = randomizePalette(field[start .. $], options.colourRandomizationStyle, seed); 178 }