1 module armos.types.color; 2 import armos.math; 3 4 /++ 5 +/ 6 struct BaseColor(T, T Limit){ 7 alias C = BaseColor!(T, Limit); 8 9 public{ 10 /// Upper limit of each channel. 11 enum T limit = Limit; 12 13 /// Red Channel. 14 T r = limit; 15 16 /// Green Channel. 17 T g = limit; 18 19 /// Blue Channel. 20 T b = limit; 21 22 /// Alpha Channel. 23 T a = limit; 24 25 /++ 26 16進数のカラーコードで色を指定します. 27 +/ 28 this(in int hexColor, in float alpha = limit){ 29 char r255 = (hexColor >> 16) & 0xff; 30 char g255 = (hexColor >> 8) & 0xff; 31 char b255 = (hexColor >> 0) & 0xff; 32 import std.conv:to; 33 r = (r255.to!float*limit/255.0f).to!T; 34 g = (g255.to!float*limit/255.0f).to!T; 35 b = (b255.to!float*limit/255.0f).to!T; 36 a = cast(T)alpha; 37 } 38 39 /++ 40 RGBAで色を指定します.透明度は省略可能です. 41 +/ 42 this(in float red, in float green, in float blue, in float alpha = limit){ 43 assert(red <= limit); 44 assert(green <= limit); 45 assert(blue <= limit); 46 assert(alpha <= limit); 47 r = armos.math.clamp(cast(T)red, T(0), limit); 48 g = armos.math.clamp(cast(T)green, T(0), limit); 49 b = armos.math.clamp(cast(T)blue, T(0), limit); 50 a = armos.math.clamp(cast(T)alpha, T(0), limit); 51 } 52 53 this(V)(V v)if(isVector!(V) && V.dimention == 4){ 54 import std.conv; 55 r = (v.x.to!float * limit.to!float).to!T; 56 g = (v.y.to!float * limit.to!float).to!T; 57 b = (v.z.to!float * limit.to!float).to!T; 58 a = (v.w.to!float * limit.to!float).to!T; 59 } 60 61 /++ 62 色の加算を行います. 63 +/ 64 C opAdd(in C color)const{ 65 import std.conv; 66 67 C result; 68 float alphaPercentageL = this.a.to!float/limit.to!float; 69 float alphaPercentageR = color.a.to!float/color.limit.to!float; 70 import std.math; 71 72 result.r = fmax(fmin( this.r.to!float * alphaPercentageL + color.r.to!float * alphaPercentageR, this.limit), float(0)).to!T; 73 result.g = fmax(fmin( this.g.to!float * alphaPercentageL + color.g.to!float * alphaPercentageR, this.limit), float(0)).to!T; 74 result.b = fmax(fmin( this.b.to!float * alphaPercentageL + color.b.to!float * alphaPercentageR, this.limit), float(0)).to!T; 75 return result; 76 } 77 unittest{ 78 alias C = BaseColor!(char, 255); 79 immutable colorL = C(128, 64, 0, 255); 80 immutable colorR = C(128, 0, 64, 255); 81 assert(colorL + colorR == C(255, 64, 64, 255)); 82 } 83 84 /++ 85 色の減算を行います. 86 +/ 87 C opSub(in C color)const{ 88 import std.conv; 89 C result; 90 float alphaPercentageL = this.a.to!float/limit.to!float; 91 float alphaPercentageR = color.a.to!float/color.limit.to!float; 92 import std.math; 93 94 result.r = fmax(fmin( this.r.to!float * alphaPercentageL - color.r.to!float * alphaPercentageR, this.limit), float(0)).to!T; 95 result.g = fmax(fmin( this.g.to!float * alphaPercentageL - color.g.to!float * alphaPercentageR, this.limit), float(0)).to!T; 96 result.b = fmax(fmin( this.b.to!float * alphaPercentageL - color.b.to!float * alphaPercentageR, this.limit), float(0)).to!T; 97 return result; 98 } 99 unittest{ 100 alias C = BaseColor!(char, 255); 101 immutable colorL = C(128, 64, 64, 255); 102 immutable colorR = C(128, 0, 32, 255); 103 assert(colorL - colorR == C(0, 64, 32, 255)); 104 } 105 106 /++ 107 色をHSBで指定します. 108 Params: 109 hue = [0, 255] 110 saturation = [0, 255] 111 value = [0, 255] 112 +/ 113 C hsb(Hue, Saturation, Value)(in Hue hue, in Saturation saturation, in Value value)if(__traits(isArithmetic, Hue, Saturation, Value)){ 114 import std.math; 115 import std.conv; 116 immutable float castedLimit = limit.to!float; 117 immutable float h = hue.to!float*360.0f/castedLimit; 118 immutable int hi = ( floor(h / 60.0f) % 6 ).to!int; 119 immutable f = (h / 60.0f) - floor(h / 60.0f); 120 immutable p = round(value * (1.0f - (saturation / castedLimit))); 121 immutable q = round(value * (1.0f - (saturation / castedLimit) * f)); 122 immutable t = round(value * (1.0f - (saturation / castedLimit) * (1.0f - f))); 123 float red, green, blue; 124 switch (hi) { 125 case 0: 126 red = value, green = t, blue = p; 127 break; 128 case 1: 129 red = q, green = value, blue = p; 130 break; 131 case 2: 132 red = p, green = value, blue = t; 133 break; 134 case 3: 135 red = p, green = q, blue = value; 136 break; 137 case 4: 138 red = t, green = p, blue = value; 139 break; 140 case 5: 141 red = value, green = p, blue = q; 142 break; 143 default: 144 break; 145 } 146 147 r = red.to!T; 148 g = green.to!T; 149 b = blue.to!T; 150 return this; 151 } 152 unittest{ 153 import std.conv; 154 auto cColor = BaseColor!(char, 255)(128, 0, 0, 255); 155 cColor.hsb(0, 255, 255); 156 assert(cColor.r.to!int == 255); 157 assert(cColor.g.to!int == 0); 158 assert(cColor.b.to!int == 0); 159 160 cColor.hsb(255, 255, 255); 161 assert(cColor.r.to!int == 255); 162 assert(cColor.g.to!int == 0); 163 assert(cColor.b.to!int == 0); 164 // import std.stdio; 165 // cColor.r.to!int.writeln; 166 // cColor.g.to!int.writeln; 167 // cColor.b.to!int.writeln; 168 169 cColor.hsb(255.0/3.0, 255.0, 255.0); 170 assert(cColor.r.to!int == 0); 171 assert(cColor.g.to!int == 255); 172 assert(cColor.b.to!int == 0); 173 } 174 175 F opCast(F)()const if(!isVector!F && is(F == BaseColor!(typeof( F.r ), F.limit))){ 176 import std.conv:to; 177 F castedColor= F(0, 0, 0, 0); 178 float c = cast(float)castedColor.limit / cast(float)limit; 179 alias CT = typeof(F.r); 180 castedColor.r = cast(CT)( cast(float)r*c ); 181 castedColor.g = cast(CT)( cast(float)g*c ); 182 castedColor.b = cast(CT)( cast(float)b*c ); 183 castedColor.a = cast(CT)( cast(float)a*c ); 184 return castedColor; 185 } 186 unittest{ 187 import std.stdio; 188 import std.math; 189 auto cColor = BaseColor!(char, 255)(128, 0, 0, 255); 190 assert(approxEqual( ( cast(BaseColor!(float, 1.0f))cColor ).r, 128.0/255.0 )); 191 192 auto fColor = BaseColor!(float, 1.0f)(0.5, 0.0, 0.0, 1.0); 193 assert(approxEqual( ( cast(BaseColor!(char, 255))cColor ).r, 128)); 194 } 195 196 197 CastType opCast(CastType)()const if(isVector!CastType && CastType.dimention == 4 && is(CastType.elementType == T)){ 198 return CastType!(T, 4)(r, g, b, a); 199 } 200 }//public 201 202 private{ 203 }//private 204 }//struct BaseColor 205 206 /++ 207 色を表すstructです. 208 最小値は0,最大値は1です. 209 +/ 210 alias BaseColor!(float, 1.0f) Color; 211 unittest{ 212 assert(__traits(compiles, (){ 213 auto color = Color(); 214 })); 215 } 216 217 /++ 218 色を表すstructです.浮動小数点型で値を持ちます. 219 220 最小値は0.0,最大値は1.0です. 221 +/ 222 deprecated alias BaseColor!(float, 1.0f) FloatColor; 223 unittest{ 224 assert(__traits(compiles, (){ 225 auto color = FloatColor(); 226 })); 227 }