ColorSpace.hx 8.5 KB

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