/core/color.d

http://github.com/wilkie/djehuty · D · 449 lines · 357 code · 67 blank · 25 comment · 90 complexity · dff41e30c6446827c9162070724e6eb2 MD5 · raw file

  1. /*
  2. * color.d
  3. *
  4. * This file has an implementation of a platform neutral Color datatype.
  5. *
  6. * Author: Dave Wilkinson
  7. *
  8. */
  9. module core.color;
  10. import platform.definitions;
  11. import core.definitions;
  12. import core.parameters;
  13. import core.util;
  14. // Color
  15. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  16. alias ubyte ColorComponent;
  17. alias uint ColorValue;
  18. }
  19. else static if (Colorbpp == Parameter_Colorbpp.Color16bpp) {
  20. alias ushort ColorComponent;
  21. alias ulong ColorValue;
  22. }
  23. else {
  24. alias ubyte ColorComponent;
  25. alias uint ColorValue;
  26. pragma(msg, "WARNING: Colorbpp parameter is not set!");
  27. }
  28. static if (ColorType == Parameter_ColorType.ColorRGBA) {
  29. align(1) struct _comps {
  30. ColorComponent r;
  31. ColorComponent g;
  32. ColorComponent b;
  33. ColorComponent a;
  34. }
  35. }
  36. else static if (ColorType == Parameter_ColorType.ColorBGRA) {
  37. align(1) struct _comps{
  38. ColorComponent b;
  39. ColorComponent g;
  40. ColorComponent r;
  41. ColorComponent a;
  42. }
  43. }
  44. else static if (ColorType == Parameter_ColorType.ColorABGR) {
  45. align(1) struct _comps {
  46. ColorComponent a;
  47. ColorComponent b;
  48. ColorComponent g;
  49. ColorComponent r;
  50. }
  51. }
  52. else static if (ColorType == Parameter_ColorType.ColorARGB) {
  53. align(1) struct _comps {
  54. ColorComponent a;
  55. ColorComponent r;
  56. ColorComponent g;
  57. ColorComponent b;
  58. }
  59. }
  60. else {
  61. align(1) struct _comps {
  62. ColorComponent r;
  63. ColorComponent g;
  64. ColorComponent b;
  65. ColorComponent a;
  66. }
  67. pragma(msg, "WARNING: ColorType parameter is not set!");
  68. }
  69. // a small function to convert an 8bpp value into
  70. // the native bits per pixel (which is either 8bpp or 16bpp)
  71. template _8toNativebpp(double comp) {
  72. const ColorComponent _8toNativebpp = cast(ColorComponent)(comp * cast(double)((1 << (ColorComponent.sizeof*8)) - 1));
  73. }
  74. // Section: Types
  75. // Description: This abstracts a color type. Internally, the structure is different for each platform depending on the native component ordering and the bits per pixel for the platform.
  76. union Color {
  77. public:
  78. // -- Predefined values
  79. // Description: Black!
  80. static const Color Black = { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
  81. static const Color Green = { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
  82. static const Color Red = { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
  83. static const Color Blue = { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
  84. static const Color Magenta = { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
  85. static const Color Yellow = { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
  86. static const Color Cyan = { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
  87. static const Color DarkGreen = { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
  88. static const Color DarkRed = { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
  89. static const Color DarkBlue = { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
  90. static const Color DarkMagenta = { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.0), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
  91. static const Color DarkYellow = { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.0), a: _8toNativebpp!(1.0) } } };
  92. static const Color DarkCyan = { _internal: { components: {r: _8toNativebpp!(0.0), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
  93. static const Color DarkGray = { _internal: { components: {r: _8toNativebpp!(0.5), g: _8toNativebpp!(0.5), b: _8toNativebpp!(0.5), a: _8toNativebpp!(1.0) } } };
  94. static const Color Gray = { _internal: { components: {r: _8toNativebpp!(0.75), g: _8toNativebpp!(0.75), b: _8toNativebpp!(0.75), a: _8toNativebpp!(1.0) } } };
  95. static const Color White = { _internal: { components: {r: _8toNativebpp!(1.0), g: _8toNativebpp!(1.0), b: _8toNativebpp!(1.0), a: _8toNativebpp!(1.0) } } };
  96. // --
  97. // Description: This function will set the color given the red, green, blue, and alpha components.
  98. static Color fromRGBA(double r, double g, double b, double a) {
  99. Color ret;
  100. ret.red = r;
  101. ret.green = g;
  102. ret.blue = b;
  103. ret.alpha = a;
  104. return ret;
  105. }
  106. // Description: This function will set the color given the red, green, and blue components.
  107. static Color fromRGB(double r, double g, double b) {
  108. Color ret;
  109. ret.red = r;
  110. ret.green = g;
  111. ret.blue = b;
  112. ret.alpha = 1.0;
  113. return ret;
  114. }
  115. // Description: This function will set the color given the hue, saturation, luminance, and alpha components.
  116. static Color fromHSLA(double h, double s, double l, double a) {
  117. Color ret;
  118. ret.hue = h;
  119. ret.sat = s;
  120. ret.lum = l;
  121. ret.alpha = a;
  122. return ret;
  123. }
  124. // Description: This function will set the color given the hue, saturation, and luminance components.
  125. static Color fromHSL(ubyte h, ubyte s, ubyte l) {
  126. Color ret;
  127. ret.hue = h;
  128. ret.sat = s;
  129. ret.lum = l;
  130. ret.alpha = 1.0;
  131. return ret;
  132. }
  133. double blue() {
  134. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  135. return cast(double)_internal.components.b / cast(double)0xFF;
  136. }
  137. else {
  138. return cast(double)_internal.components.b / cast(double)0xFFFF;
  139. }
  140. }
  141. void blue(double val) {
  142. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  143. _internal.components.b = cast(ubyte)(0xffp0 * val);
  144. }
  145. else {
  146. _internal.components.b = cast(ubyte)(0xffffp0 * val);
  147. }
  148. }
  149. double green() {
  150. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  151. return cast(double)_internal.components.g / cast(double)0xFF;
  152. }
  153. else {
  154. return cast(double)_internal.components.g / cast(double)0xFFFF;
  155. }
  156. }
  157. void green(ubyte val) {
  158. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  159. _internal.components.g = val;
  160. }
  161. else {
  162. _internal.components.g = (cast(double)val / cast(double)0xFF) * 0xFFFF;
  163. }
  164. }
  165. void green(double val) {
  166. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  167. _internal.components.g = cast(ubyte)(0xffp0 * val);
  168. }
  169. else {
  170. _internal.components.g = cast(ubyte)(0xffffp0 * val);
  171. }
  172. }
  173. double red() {
  174. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  175. return cast(double)_internal.components.r / cast(double)0xFF;
  176. }
  177. else {
  178. return cast(double)_internal.components.r / cast(double)0xFFFF;
  179. }
  180. }
  181. void red(ubyte val) {
  182. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  183. _internal.components.r = val;
  184. }
  185. else {
  186. _internal.components.r = (cast(double)val / cast(double)0xFF) * 0xFFFF;
  187. }
  188. }
  189. void red(double val) {
  190. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  191. _internal.components.r = cast(ubyte)(0xffp0 * val);
  192. }
  193. else {
  194. _internal.components.r = cast(ubyte)(0xffffp0 * val);
  195. }
  196. }
  197. double alpha() {
  198. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  199. return cast(double)_internal.components.a / cast(double)0xFF;
  200. }
  201. else {
  202. return cast(double)_internal.components.a / cast(double)0xFFFF;
  203. }
  204. }
  205. void alpha(double val) {
  206. static if (Colorbpp == Parameter_Colorbpp.Color8bpp) {
  207. _internal.components.a = cast(ubyte)(0xffp0 * val);
  208. }
  209. else {
  210. _internal.components.a = cast(ubyte)(0xffffp0 * val);
  211. }
  212. }
  213. void hue(double val) {
  214. if (!_hslValid) {
  215. _calculateHSL();
  216. }
  217. _hue = val;
  218. _calculateFromHSL();
  219. }
  220. double hue() {
  221. if (_hslValid) {
  222. return _hue;
  223. }
  224. _calculateHSL();
  225. return _hue;
  226. }
  227. void sat(double val) {
  228. if (!_hslValid) {
  229. _calculateHSL();
  230. }
  231. _sat = val;
  232. _calculateFromHSL();
  233. }
  234. double sat() {
  235. if (_hslValid) {
  236. return _sat;
  237. }
  238. _calculateHSL();
  239. return _sat;
  240. }
  241. void lum(double val) {
  242. if (!_hslValid) {
  243. _calculateHSL();
  244. }
  245. _lum = val;
  246. _calculateFromHSL();
  247. }
  248. double lum() {
  249. if (_hslValid) {
  250. return _lum;
  251. }
  252. _calculateHSL();
  253. return _lum;
  254. }
  255. ColorValue value() {
  256. return _internal.clr;
  257. }
  258. private:
  259. union internal {
  260. _comps components;
  261. ColorValue clr;
  262. }
  263. internal _internal;
  264. // cache HSL values
  265. bool _hslValid;
  266. double _hue;
  267. double _sat;
  268. double _lum;
  269. void _calculateFromHSL() {
  270. if (_sat == 0) {
  271. this.red = _lum;
  272. this.blue = _lum;
  273. this.green = _lum;
  274. return;
  275. }
  276. double p;
  277. double q;
  278. if (_lum < 0.5) {
  279. q = _lum * (1.0 + _sat);
  280. }
  281. else {
  282. q = _lum + _sat - (_lum * _sat);
  283. }
  284. p = (2.0 * _lum) - q;
  285. double[3] ctmp;
  286. ctmp[0] = _hue + (1.0/3.0);
  287. ctmp[1] = _hue;
  288. ctmp[2] = _hue - (1.0/3.0);
  289. for(size_t i = 0; i < 3; i++) {
  290. if (ctmp[i] < 0) {
  291. ctmp[i] += 1.0;
  292. }
  293. else if (ctmp[i] > 1) {
  294. ctmp[i] -= 1.0;
  295. }
  296. if (ctmp[i] < (1.0 / 6.0)) {
  297. ctmp[i] = p + ((q - p) * 6.0 * ctmp[i]);
  298. }
  299. else if (ctmp[i] < 0.5) {
  300. ctmp[i] = q;
  301. }
  302. else if (ctmp[i] < (2.0 / 3.0)) {
  303. ctmp[i] = p + (q - p) * ((2.0 / 3.0) - ctmp[i]) * 6.0;
  304. }
  305. else {
  306. ctmp[i] = p;
  307. }
  308. }
  309. this.red = ctmp[0];
  310. this.green = ctmp[1];
  311. this.blue = ctmp[2];
  312. }
  313. void _calculateHSL() {
  314. // find min and max values
  315. double min, max;
  316. double r,g,b;
  317. r = this.red;
  318. g = this.green;
  319. b = this.blue;
  320. uint maxColor;
  321. if (r<=g && r<=b) {
  322. min = r;
  323. if (g<b) {
  324. max = b;
  325. maxColor = 2;
  326. }
  327. else {
  328. max = g;
  329. maxColor = 1;
  330. }
  331. }
  332. else if (g<=b && g<=r) {
  333. min = g;
  334. if (r<b) {
  335. max = b;
  336. maxColor = 2;
  337. }
  338. else {
  339. max = r;
  340. maxColor = 0;
  341. }
  342. }
  343. else {
  344. min = b;
  345. if (r<g) {
  346. max = g;
  347. maxColor = 1;
  348. }
  349. else {
  350. max = r;
  351. maxColor = 0;
  352. }
  353. }
  354. // find luminance
  355. _lum = (max + min) * 0.5;
  356. if (max == min) {
  357. _sat = 0;
  358. _hue = 0;
  359. _hslValid = true;
  360. return;
  361. }
  362. // find the saturation
  363. if (_lum < 0.5) {
  364. _sat = (max - min) / (max + min);
  365. }
  366. else {
  367. _sat = (max - min) / (2.0 - max - min);
  368. }
  369. // find hue
  370. if (maxColor == 0) {
  371. _hue = (g - b) / (max - min);
  372. }
  373. else if (maxColor == 1){
  374. _hue = 2.0 + (b - r) / (max - min);
  375. }
  376. else {
  377. _hue = 4.0 + (r - g) / (max - min);
  378. }
  379. _hue /= 6.0;
  380. _hslValid = true;
  381. }
  382. }