You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

282 line
7.0 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include "core.h"
  14. /*
  15. * Stock images and kernels
  16. */
  17. namespace lol
  18. {
  19. bool Image::Stock(char const *name)
  20. {
  21. /* Generate a completely random image. */
  22. if (!strncmp(name, "random:", 7))
  23. {
  24. ivec2 size(0);
  25. size.x = atoi(name + 7);
  26. name = strchr(name + 7, 'x');
  27. if (name)
  28. size.y = atoi(name + 1);
  29. if (!size.y)
  30. size.y = size.x;
  31. if (size.x <= 0 || size.y <= 0)
  32. return false;
  33. return RenderRandom(size);
  34. }
  35. return false;
  36. }
  37. Array2D<float> Image::BayerKernel(ivec2 size)
  38. {
  39. Array2D<float> ret(size);
  40. int n = 1;
  41. while (n < size.x || n < size.y)
  42. n *= 2;
  43. for (int j = 0; j < size.y; j++)
  44. for (int i = 0; i < size.x; i++)
  45. {
  46. int x = 0;
  47. for (int k = 1, l = n * n / 4; k < n; k *= 2, l /= 4)
  48. {
  49. if ((i & k) && (j & k))
  50. x += l;
  51. else if (i & k)
  52. x += 3 * l;
  53. else if (j & k)
  54. x += 2 * l;
  55. }
  56. ret[i][j] = (float)(x + 1) / (n * n + 1);
  57. }
  58. return ret;
  59. }
  60. Array2D<float> Image::HalftoneKernel(ivec2 size)
  61. {
  62. Array2D<float> ret(size);
  63. for (int y = 0; y < size.y; y++)
  64. for (int x = 0; x < size.x; x++)
  65. {
  66. float dx = 2.f * x / size.x - 0.5f;
  67. float dy = 2.f * (y + 0.07f) / size.y - 0.5f;
  68. bool flip = false;
  69. if (dx > 0.5f)
  70. {
  71. flip = !flip;
  72. dx -= 1.0f;
  73. }
  74. if (dy > 0.5f)
  75. {
  76. flip = !flip;
  77. dy -= 1.0f;
  78. }
  79. /* Using dx²+dy² here creates another interesting halftone. */
  80. float r = - lol::cos(F_PI * (dx - dy)) - lol::cos(F_PI * (dx + dy));
  81. ret[x][y] = flip ? 10.f - r : r;
  82. }
  83. return NormalizeKernel(ret);
  84. }
  85. struct Dot
  86. {
  87. int x, y;
  88. float val;
  89. };
  90. static int cmpdot(const void *p1, const void *p2)
  91. {
  92. return ((Dot const *)p1)->val > ((Dot const *)p2)->val;
  93. }
  94. Array2D<float> Image::NormalizeKernel(Array2D<float> const &kernel)
  95. {
  96. ivec2 size = kernel.GetSize();
  97. Array<Dot> tmp;
  98. tmp.Resize(size.x * size.y);
  99. for (int y = 0; y < size.y; y++)
  100. for (int x = 0; x < size.x; x++)
  101. {
  102. tmp[y * size.x + x].x = x;
  103. tmp[y * size.x + x].y = y;
  104. tmp[y * size.x + x].val = kernel[x][y];
  105. }
  106. std::qsort(tmp.Data(), size.x * size.y, sizeof(Dot), cmpdot);
  107. Array2D<float> dst(size);
  108. float epsilon = 1.f / (size.x * size.y + 1);
  109. for (int n = 0; n < size.x * size.y; n++)
  110. {
  111. int x = tmp[n].x;
  112. int y = tmp[n].y;
  113. dst[x][y] = (float)(n + 1) * epsilon;
  114. }
  115. return dst;
  116. }
  117. Array2D<float> Image::EdiffKernel(EdiffAlgorithm algorithm)
  118. {
  119. Array2D<float> ret;
  120. switch(algorithm)
  121. {
  122. case EdiffAlgorithm::FloydSteinberg:
  123. ret.SetSize(ivec2(3, 2));
  124. {
  125. static float const myker[] =
  126. {
  127. 0., 1., 7./16,
  128. 3./16, 5./16, 1./16,
  129. };
  130. memcpy(&ret[0][0], myker, sizeof(myker));
  131. }
  132. return ret;
  133. case EdiffAlgorithm::JaJuNi:
  134. ret.SetSize(ivec2(5, 3));
  135. {
  136. static float const myker[] =
  137. {
  138. 0., 0., 1., 7./48, 5./48,
  139. 3./48, 5./48, 7./48, 5./48, 3./48,
  140. 1./48, 3./48, 5./48, 3./48, 1./48,
  141. };
  142. memcpy(&ret[0][0], myker, sizeof(myker));
  143. }
  144. return ret;
  145. case EdiffAlgorithm::Atkinson:
  146. ret.SetSize(ivec2(4, 3));
  147. {
  148. static float const myker[] =
  149. {
  150. 0., 1., 1./8, 1./8,
  151. 1./8, 1./8, 1./8, 0.,
  152. 0., 1./8, 0., 0.,
  153. };
  154. memcpy(&ret[0][0], myker, sizeof(myker));
  155. }
  156. return ret;
  157. case EdiffAlgorithm::Fan:
  158. ret.SetSize(ivec2(4, 2));
  159. {
  160. static float const myker[] =
  161. {
  162. 0., 0., 1., 7./16,
  163. 1./16, 3./16, 5./16, 0.,
  164. };
  165. memcpy(&ret[0][0], myker, sizeof(myker));
  166. }
  167. return ret;
  168. case EdiffAlgorithm::ShiauFan:
  169. ret.SetSize(ivec2(4, 2));
  170. {
  171. static float const myker[] =
  172. {
  173. 0., 0., 1., 1./2,
  174. 1./8, 1./8, 1./4, 0.,
  175. };
  176. memcpy(&ret[0][0], myker, sizeof(myker));
  177. }
  178. return ret;
  179. case EdiffAlgorithm::ShiauFan2:
  180. ret.SetSize(ivec2(5, 2));
  181. {
  182. static float const myker[] =
  183. {
  184. 0., 0., 0., 1., 1./2,
  185. 1./16, 1./16, 1./8, 1./4, 0.,
  186. };
  187. memcpy(&ret[0][0], myker, sizeof(myker));
  188. }
  189. return ret;
  190. case EdiffAlgorithm::Stucki:
  191. ret.SetSize(ivec2(5, 3));
  192. {
  193. static float const myker[] =
  194. {
  195. 0., 0., 1., 8./42, 4./42,
  196. 2./42, 4./42, 8./42, 4./42, 2./42,
  197. 1./42, 2./42, 4./42, 2./42, 1./42,
  198. };
  199. memcpy(&ret[0][0], myker, sizeof(myker));
  200. }
  201. return ret;
  202. case EdiffAlgorithm::Burkes:
  203. ret.SetSize(ivec2(5, 2));
  204. {
  205. static float const myker[] =
  206. {
  207. 0., 0., 1., 4./16, 2./16,
  208. 1./16, 2./16, 4./16, 2./16, 1./16,
  209. };
  210. memcpy(&ret[0][0], myker, sizeof(myker));
  211. }
  212. return ret;
  213. case EdiffAlgorithm::Sierra:
  214. ret.SetSize(ivec2(5, 3));
  215. {
  216. static float const myker[] =
  217. {
  218. 0., 0., 1., 5./32, 3./32,
  219. 2./32, 4./32, 5./32, 4./32, 2./32,
  220. 0., 2./32, 3./32, 2./32, 0.,
  221. };
  222. memcpy(&ret[0][0], myker, sizeof(myker));
  223. }
  224. return ret;
  225. case EdiffAlgorithm::Sierra2:
  226. ret.SetSize(ivec2(5, 2));
  227. {
  228. static float const myker[] =
  229. {
  230. 0., 0., 1., 4./16, 3./16,
  231. 1./16, 2./16, 3./16, 2./16, 1./16,
  232. };
  233. memcpy(&ret[0][0], myker, sizeof(myker));
  234. }
  235. return ret;
  236. case EdiffAlgorithm::Lite:
  237. ret.SetSize(ivec2(3, 2));
  238. {
  239. static float const myker[] =
  240. {
  241. 0., 1., 1./2,
  242. 1./4, 1./4, 0.,
  243. };
  244. memcpy(&ret[0][0], myker, sizeof(myker));
  245. }
  246. return ret;
  247. }
  248. return ret;
  249. }
  250. } /* namespace lol */