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.
 
 
 

117 lines
3.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. * Ostromoukhov dithering functions
  16. *
  17. * This module implements Ostromoukhov's simple error diffusion algorithm,
  18. * as introduced in the paper "A Simple and Efficient Error-Diffusion
  19. * Algorithm", Proceedings of SIGGRAPH 2001, in ACM Computer Graphics,
  20. * Annual Conference Series, pp. 567--572, 2001.
  21. *
  22. * Note: the authors initially provided a large data table, but we
  23. * manually converted it to a piecewise linear function.
  24. */
  25. namespace lol
  26. {
  27. static inline vec3 GetDiffusion(float v)
  28. {
  29. static vec3 const table[] =
  30. {
  31. vec3(0.0000f, 0.2777f, 0.0000f),
  32. vec3(0.0039f, 0.2777f, 0.0000f),
  33. vec3(0.0117f, 0.3636f, 0.0000f),
  34. vec3(0.0157f, 0.3846f, 0.0000f),
  35. vec3(0.0392f, 0.2308f, 0.2308f),
  36. vec3(0.0863f, 0.1667f, 0.3333f),
  37. vec3(0.1255f, 0.3878f, 0.2041f),
  38. vec3(0.2510f, 0.0000f, 0.4762f),
  39. vec3(0.2824f, 0.0769f, 0.5385f),
  40. vec3(0.3020f, 0.1667f, 0.1667f),
  41. vec3(0.3333f, 0.1667f, 0.1667f),
  42. vec3(0.3725f, 0.2000f, 0.3000f),
  43. vec3(0.4196f, 0.2000f, 0.3000f),
  44. vec3(0.4980f, 0.1667f, 0.1667f),
  45. vec3(1.0000f, 0.1667f, 0.1667f), /* Safe value */
  46. };
  47. vec3 ret(0.1667f);
  48. if (v > 0.5f)
  49. v = 1.f - v;
  50. if (v < 0.f)
  51. v = 0.f;
  52. for (unsigned int i = 1; i < sizeof(table) / sizeof(table[0]); ++i)
  53. {
  54. if (v <= table[i][0])
  55. {
  56. ret[1] = lol::mix(table[i - 1][1], table[i][1],
  57. (table[i][0] - v) / (table[i][0] - table[i - 1][0]));
  58. ret[2] = lol::mix(table[i - 1][2], table[i][2],
  59. (table[i][0] - v) / (table[i][0] - table[i - 1][0]));
  60. break;
  61. }
  62. }
  63. ret[0] = 1.f - ret[1] - ret[2];
  64. return ret;
  65. }
  66. Image Image::DitherOstromoukhov(ScanMode scan) const
  67. {
  68. Image dst = *this;
  69. float *pixels = dst.Lock<PixelFormat::Y_F32>();
  70. int w = dst.GetSize().x;
  71. int h = dst.GetSize().y;
  72. for (int y = 0; y < h; y++)
  73. {
  74. bool reverse = (y & 1) && (scan == ScanMode::Serpentine);
  75. for (int x = 0; x < w; x++)
  76. {
  77. int x2 = reverse ? w - 1 - x : x;
  78. int s = reverse ? -1 : 1;
  79. float p = pixels[y * w + x2];
  80. float q = p < 0.5f ? 0.f : 1.f;
  81. pixels[y * w + x2] = q;
  82. vec3 e = (p - q) * GetDiffusion(p);
  83. if(x < w - 1)
  84. pixels[y * w + x2 + s] += e[0];
  85. if(y < h - 1)
  86. {
  87. if(x > 0)
  88. pixels[(y + 1) * w + x2 - s] += e[1];
  89. pixels[(y + 1) * w + x2] += e[2];
  90. }
  91. }
  92. }
  93. dst.Unlock(pixels);
  94. return dst;
  95. }
  96. } /* namespace lol */