ColorSpace.hx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package hrt.impl;
  2. import h3d.Vector;
  3. typedef ColorMode = {
  4. name: String,
  5. valueToARGB : (value : Vector, outColor : Color) -> Color,
  6. ARGBToValue : (color : Color, outVector: Vector) -> Vector
  7. };
  8. class Color {
  9. public var r : Int = 0;
  10. public var g : Int = 0;
  11. public var b : Int = 0;
  12. public var a : Int = 0;
  13. inline public function new(r:Int = 0, g:Int = 0, b:Int = 0, a:Int = 0) {
  14. this.r = r;
  15. this.g = g;
  16. this.b = b;
  17. this.a = a;
  18. }
  19. inline static public function fromInt(rgb: Int, withAlpha: Bool = true) : Color {
  20. return new Color(
  21. (rgb >> 16) & 0xFF,
  22. (rgb >> 8) & 0xFF,
  23. (rgb >> 0) & 0xFF,
  24. withAlpha ? (rgb >> 24) & 0xFF : 255
  25. );
  26. }
  27. }
  28. class ColorSpace {
  29. public static function iRGBtofRGB(color : Color, outVector: Vector) : Vector {
  30. if (outVector == null)
  31. outVector = new Vector();
  32. outVector.set(color.r/255.0, color.g/255.0, color.b/255.0, color.a/255.0);
  33. return outVector;
  34. }
  35. public static function fRGBtoiRGB(color : Vector, outColor : Color) {
  36. if (outColor == null)
  37. outColor = new Color();
  38. outColor.r = Std.int(color.r*255.0);
  39. outColor.g = Std.int(color.g*255.0);
  40. outColor.b = Std.int(color.b*255.0);
  41. outColor.a = Std.int(color.a*255.0);
  42. return outColor;
  43. }
  44. public static function iRGBtoHSV(color: Color, outVector: Vector = null) : Vector {
  45. var r = color.r / 255.0;
  46. var g = color.g / 255.0;
  47. var b = color.b / 255.0;
  48. var a = color.a / 255.0;
  49. var Cmax = Math.max(r, Math.max(g, b));
  50. var Cmin = Math.min(r, Math.min(g, b));
  51. var D = Cmax - Cmin;
  52. var H = if(D == 0) 0.0
  53. else if(Cmax == r) hxd.Math.ufmod((g - b)/D, 6) * 60.0
  54. else if (Cmax == g) ((b - r)/D + 2) * 60.0
  55. else ((r - g)/D + 4) * 60.0;
  56. H = H / 360.0;
  57. H = Math.min(Math.max(H, 0.0), 1.0);
  58. var S = if (Cmax == 0) 0 else D/Cmax;
  59. var V = Cmax;
  60. var A = a;
  61. if (outVector == null)
  62. outVector = new Vector();
  63. outVector.set(H, S, V, A);
  64. return outVector;
  65. }
  66. public static function HSVtoiRGB(hsv:Vector, outColor : Color) {
  67. if (outColor == null)
  68. outColor = new Color();
  69. var h = hsv.x * 360.0;
  70. var s = hsv.y;
  71. var v = hsv.z;
  72. var C = v * s;
  73. var X = C * (1 - Math.abs(hxd.Math.ufmod((h / 60.0),2) - 1));
  74. var m = v - C;
  75. var r = 0.0;
  76. var g = 0.0;
  77. var b = 0.0;
  78. if (h < 60) {r = C; g = X;}
  79. else if (h < 120) {r = X; g = C;}
  80. else if (h < 180) {g = C; b = X;}
  81. else if (h < 240) {g = X; b = C;}
  82. else if (h < 300) {r = X; b = C;}
  83. else {r = C; b = X;};
  84. outColor.r = Std.int(Math.round((r+m)*255));
  85. outColor.g = Std.int(Math.round((g+m)*255));
  86. outColor.b = Std.int(Math.round((b+m)*255));
  87. outColor.a = Std.int(hsv.w * 255);
  88. return outColor;
  89. }
  90. public static function iRGBtoHSL(color : Color, outVector: Vector = null) : Vector {
  91. var r = color.r / 255.0;
  92. var g = color.g / 255.0;
  93. var b = color.b / 255.0;
  94. var a = color.a / 255.0;
  95. var Cmax = Math.max(r, Math.max(g, b));
  96. var Cmin = Math.min(r, Math.min(g, b));
  97. var D = Cmax - Cmin;
  98. var H = if(D == 0) 0.0
  99. else if(Cmax == r) hxd.Math.ufmod((g - b)/D, 6) * 60.0
  100. else if (Cmax == g) ((b - r)/D + 2) * 60.0
  101. else ((r - g)/D + 4) * 60.0;
  102. H = H / 360.0;
  103. H = Math.min(Math.max(H, 0.0), 1.0);
  104. var L = (Cmax + Cmin) / 2;
  105. var S = if (D == 0) 0 else D / (1 - Math.abs(2 * L - 1));
  106. if (outVector == null)
  107. outVector = new Vector();
  108. outVector.set(H, S, L, a);
  109. return outVector;
  110. }
  111. public static function HSLtoiRGB(hsl : Vector, outColor : Color) {
  112. if (outColor == null)
  113. outColor = new Color();
  114. var h = hsl.x * 360.0;
  115. var s = hsl.y;
  116. var l = hsl.z;
  117. var C = (1 - Math.abs(2*l-1)) * s;
  118. var X = C * (1 - Math.abs(hxd.Math.ufmod((h / 60.0),2) - 1));
  119. var m = l - C/2.0;
  120. var r = 0.0;
  121. var g = 0.0;
  122. var b = 0.0;
  123. if (h < 60) {r = C; g = X;}
  124. else if (h < 120) {r = X; g = C;}
  125. else if (h < 180) {g = C; b = X;}
  126. else if (h < 240) {g = X; b = C;}
  127. else if (h < 300) {r = X; b = C;}
  128. else {r = C; b = X;};
  129. outColor.r = Std.int(Math.round((r+m)*255));
  130. outColor.g = Std.int(Math.round((g+m)*255));
  131. outColor.b = Std.int(Math.round((b+m)*255));
  132. outColor.a = Std.int(hsl.w * 255);
  133. return outColor;
  134. }
  135. public static function iRGBtoXYZ(color : Color, outVector: Vector = null) : Vector {
  136. outVector = iRGBtofRGB(color, outVector);
  137. inline function linearize(v:Float) : Float {
  138. return v <= 0.04045 ? v/12.92 : hxd.Math.pow((v + 0.055) / 1.055, 2.4);
  139. }
  140. outVector.x = linearize(outVector.x);
  141. outVector.y = linearize(outVector.y);
  142. outVector.z = linearize(outVector.z);
  143. var x = outVector.x * 0.4124 + outVector.y * 0.3576 + outVector.z * 0.1805;
  144. var y = outVector.x * 0.2126 + outVector.y * 0.7152 + outVector.z * 0.0722;
  145. var z = outVector.x * 0.0193 + outVector.y * 0.1192 + outVector.z * 0.9505;
  146. outVector.set(x,y,z,outVector.a);
  147. return outVector;
  148. }
  149. static var tmpVector : Vector = new Vector();
  150. public static function XYZtoiRGB(value: Vector, outColor : Color) : Color {
  151. if (outColor == null)
  152. outColor = new Color();
  153. var x = value.r * 0.9505;
  154. var y = value.g * 1.0;
  155. var z = value.b * 1.0890;
  156. var r = value.x * 3.2406 + value.y * -1.5372 + value.z * -0.4986;
  157. var g = value.x * -0.9689 + value.y * 1.8758 + value.z * 0.0415;
  158. var b = value.x * 0.0557 + value.y * -0.2040 + value.z * 1.0570;
  159. // var r = value.x * 2.36461385 + value.y * -0.89654057 + value.z * -0.46807328;
  160. // var g = value.x * -0.51516621 + value.y * 1.4264081 + value.z * 0.0887581;
  161. // var b = value.x * 0.0052037 + value.y * -0.01440816 + value.z * 1.00920446;
  162. inline function delinearize(v:Float) : Float {
  163. return hxd.Math.clamp(v <= 0.0031308 ? 12.92 * v : 1.055 * hxd.Math.pow(v, 1.0/2.4) - 0.055);
  164. }
  165. tmpVector.set(delinearize(r),delinearize(g),delinearize(b),value.a);
  166. return fRGBtoiRGB(tmpVector, outColor);
  167. }
  168. static final Xn = 95.0489;
  169. static final Yn = 100;
  170. static final Zn = 108.8840;
  171. public static function LABtoiRGB(value: Vector, outColor : Color) : Color {
  172. // lab -> XYZ
  173. inline function fn(t:Float) : Float {
  174. var d = 6.0/29.0;
  175. return t>d ? t*t*t : 3 * d * d * (t - 4.0 / 29.0);
  176. }
  177. var l = value.x * 100.0;
  178. var a = value.y * 255.0 - 128.0;
  179. var b = value.z * 255.0 - 128.0;
  180. tmpVector.x = Xn * fn((l + 16) / 116.0 + a / 500);
  181. tmpVector.y = Yn * fn((l + 16) / 116.0);
  182. tmpVector.z = Zn * fn((l + 16) / 116.0 - b / 200);
  183. tmpVector.x /= 100.0;
  184. tmpVector.y /= 100.0;
  185. tmpVector.z /= 100.0;
  186. return XYZtoiRGB(tmpVector, outColor);
  187. }
  188. public static function iRGBtoLAB(color : Color, outVector: Vector = null) : Vector {
  189. tmpVector = iRGBtoXYZ(color, tmpVector);
  190. inline function fn(t:Float) : Float {
  191. var d = 6.0/29.0;
  192. return (t > d * d * d) ? hxd.Math.pow(t, 1.0/3.0) : t / 3.0 * d * d + 4 / 29.0;
  193. }
  194. var L = 116.0 * fn(tmpVector.y*100.0 / Yn) - 16.0;
  195. var a = 500.0 * (fn(tmpVector.x*100.0 / Xn) - fn(tmpVector.y*100.0/Yn));
  196. var b = 200.0 * (fn(tmpVector.y*100.0 / Yn) - fn(tmpVector.z*100.0/Zn));
  197. if (outVector == null)
  198. outVector = new Vector();
  199. outVector.set(
  200. hxd.Math.clamp(L/100.0),
  201. hxd.Math.clamp((a+128.0)/255.0),
  202. hxd.Math.clamp((b+128.0)/255.0),
  203. outVector.a
  204. );
  205. return outVector;
  206. }
  207. public static function iRGBtoHCL(color: Color, outVector: Vector = null) : Vector {
  208. outVector = iRGBtoLAB(color, outVector);
  209. var a = outVector.y * 255.0 - 128.0;
  210. var b = outVector.z * 255.0 - 128.0;
  211. var chroma = hxd.Math.sqrt(a * a + b * b) / 100.0;
  212. var hue = ((hxd.Math.atan2(b, a) + hxd.Math.PI * 2.0) % (hxd.Math.PI * 2.0)) / (hxd.Math.PI * 2.0);
  213. var luminance = outVector.x;
  214. outVector.x = hue;
  215. outVector.y = chroma;
  216. outVector.z = luminance;
  217. return outVector;
  218. }
  219. public static function HCLtoiRGB(value: Vector, outColor : Color) : Color {
  220. tmpVector.x = value.z;
  221. var a = value.x * hxd.Math.PI * 2.0;
  222. tmpVector.y = hxd.Math.cos(a) * value.y * 100.0;
  223. tmpVector.z = hxd.Math.sin(a) * value.y * 100.0;
  224. tmpVector.y = hxd.Math.clamp((tmpVector.y+128.0)/255.0);
  225. tmpVector.z = hxd.Math.clamp((tmpVector.z+128.0)/255.0);
  226. tmpVector.a = value.a;
  227. return LABtoiRGB(tmpVector, outColor);
  228. }
  229. public static var colorModes : Array<ColorMode> = [
  230. {name:"RGB", valueToARGB: fRGBtoiRGB, ARGBToValue: iRGBtofRGB},
  231. {name:"HSV", valueToARGB: HSVtoiRGB, ARGBToValue: iRGBtoHSV},
  232. {name:"HSL", valueToARGB: HSLtoiRGB, ARGBToValue: iRGBtoHSL},
  233. {name:"XYZ", valueToARGB: XYZtoiRGB, ARGBToValue: iRGBtoXYZ},
  234. {name:"LAB", valueToARGB: LABtoiRGB, ARGBToValue: iRGBtoLAB},
  235. {name:"HCL", valueToARGB: HCLtoiRGB, ARGBToValue: iRGBtoHCL},
  236. ];
  237. }