Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

213 řádky
7.4 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 <lol/main.h>
  14. /*
  15. * Image resizing functions
  16. */
  17. namespace lol
  18. {
  19. static Image ResizeBicubic(Image &image, ivec2 size);
  20. static Image ResizeBresenham(Image &image, ivec2 size);
  21. Image Image::Resize(ivec2 size, ResampleAlgorithm algorithm)
  22. {
  23. switch (algorithm)
  24. {
  25. case ResampleAlgorithm::Bicubic:
  26. return ResizeBicubic(*this, size);
  27. case ResampleAlgorithm::Bresenham:
  28. default:
  29. return ResizeBresenham(*this, size);
  30. }
  31. }
  32. static Image ResizeBicubic(Image &image, ivec2 size)
  33. {
  34. Image dst(size);
  35. ivec2 const oldsize = image.GetSize();
  36. vec4 const *srcp = image.Lock<PixelFormat::RGBA_F32>();
  37. vec4 *dstp = dst.Lock<PixelFormat::RGBA_F32>();
  38. float scalex = size.x > 1 ? (oldsize.x - 1.f) / (size.x - 1) : 1.f;
  39. float scaley = size.y > 1 ? (oldsize.y - 1.f) / (size.y - 1) : 1.f;
  40. for (int y = 0; y < size.y; ++y)
  41. {
  42. float yfloat = scaley * y;
  43. int yint = (int)yfloat;
  44. float y1 = yfloat - yint;
  45. vec4 const *p0 = srcp + oldsize.x * lol::min(lol::max(0, yint - 1), oldsize.y - 1);
  46. vec4 const *p1 = srcp + oldsize.x * lol::min(lol::max(0, yint ), oldsize.y - 1);
  47. vec4 const *p2 = srcp + oldsize.x * lol::min(lol::max(0, yint + 1), oldsize.y - 1);
  48. vec4 const *p3 = srcp + oldsize.x * lol::min(lol::max(0, yint + 2), oldsize.y - 1);
  49. for (int x = 0; x < size.x; ++x)
  50. {
  51. float xfloat = scalex * x;
  52. int xint = (int)xfloat;
  53. float x1 = xfloat - xint;
  54. int const i0 = lol::min(lol::max(0, xint - 1), oldsize.x - 1);
  55. int const i1 = lol::min(lol::max(0, xint ), oldsize.x - 1);
  56. int const i2 = lol::min(lol::max(0, xint + 1), oldsize.x - 1);
  57. int const i3 = lol::min(lol::max(0, xint + 2), oldsize.x - 1);
  58. vec4 a00 = p1[i1];
  59. vec4 a01 = .5f * (p2[i1] - p0[i1]);
  60. vec4 a02 = p0[i1] - 2.5f * p1[i1]
  61. + 2.f * p2[i1] - .5f * p3[i1];
  62. vec4 a03 = .5f * (p3[i1] - p0[i1]) + 1.5f * (p1[i1] - p2[i1]);
  63. vec4 a10 = .5f * (p1[i2] - p1[i0]);
  64. vec4 a11 = .25f * (p0[i0] - p2[i0] - p0[i2] + p2[i2]);
  65. vec4 a12 = .5f * (p0[i2] - p0[i0]) + 1.25f * (p1[i0] - p1[i2])
  66. + .25f * (p3[i0] - p3[i2]) + p2[i2] - p2[i0];
  67. vec4 a13 = .25f * (p0[i0] - p3[i0] - p0[i2] + p3[i2])
  68. + .75f * (p2[i0] - p1[i0] + p1[i2] - p2[i2]);
  69. vec4 a20 = p1[i0] - 2.5f * p1[i1]
  70. + 2.f * p1[i2] - .5f * p1[i3];
  71. vec4 a21 = .5f * (p2[i0] - p0[i0]) + 1.25f * (p0[i1] - p2[i1])
  72. + .25f * (p0[i3] - p2[i3]) - p0[i2] + p2[i2];
  73. vec4 a22 = p0[i0] - p3[i2] - 2.5f * (p1[i0] + p0[i1])
  74. + 2.f * (p2[i0] + p0[i2]) - .5f * (p3[i0] + p0[i3])
  75. + 6.25f * p1[i1] - 5.f * (p2[i1] + p1[i2])
  76. + 1.25f * (p3[i1] + p1[i3])
  77. + 4.f * p2[i2] - p2[i3] + .25f * p3[i3];
  78. vec4 a23 = 1.5f * (p1[i0] - p2[i0]) + .5f * (p3[i0] - p0[i0])
  79. + 1.25f * (p0[i1] - p3[i1])
  80. + 3.75f * (p2[i1] - p1[i1]) + p3[i2] - p0[i2]
  81. + 3.f * (p1[i2] - p2[i2]) + .25f * (p0[i3] - p3[i3])
  82. + .75f * (p2[i3] - p1[i3]);
  83. vec4 a30 = .5f * (p1[i3] - p1[i0]) + 1.5f * (p1[i1] - p1[i2]);
  84. vec4 a31 = .25f * (p0[i0] - p2[i0]) + .25f * (p2[i3] - p0[i3])
  85. + .75f * (p2[i1] - p0[i1] + p0[i2] - p2[i2]);
  86. vec4 a32 = -.5f * p0[i0] + 1.25f * p1[i0] - p2[i0]
  87. + .25f * p3[i0] + 1.5f * p0[i1] - 3.75f * p1[i1]
  88. + 3.f * p2[i1] - .75f * p3[i1] - 1.5f * p0[i2]
  89. + 3.75f * p1[i2] - 3.f * p2[i2] + .75f * p3[i2]
  90. + .5f * p0[i3] - 1.25f * p1[i3] + p2[i3]
  91. - .25f * p3[i3];
  92. vec4 a33 = .25f * p0[i0] - .75f * p1[i0] + .75f * p2[i0]
  93. - .25f * p3[i0] - .75f * p0[i1] + 2.25f * p1[i1]
  94. - 2.25f * p2[i1] + .75f * p3[i1] + .75f * p0[i2]
  95. - 2.25f * p1[i2] + 2.25f * p2[i2] - .75f * p3[i2]
  96. - .25f * p0[i3] + .75f * p1[i3] - .75f * p2[i3]
  97. + .25f * p3[i3];
  98. float y2 = y1 * y1; float y3 = y2 * y1;
  99. float x2 = x1 * x1; float x3 = x2 * x1;
  100. vec4 p = a00 + a01 * y1 + a02 * y2 + a03 * y3
  101. + a10 * x1 + a11 * x1 * y1 + a12 * x1 * y2 + a13 * x1 * y3
  102. + a20 * x2 + a21 * x2 * y1 + a22 * x2 * y2 + a23 * x2 * y3
  103. + a30 * x3 + a31 * x3 * y1 + a32 * x3 * y2 + a33 * x3 * y3;
  104. dstp[y * size.x + x] = lol::clamp(p, 0.f, 1.f);
  105. }
  106. }
  107. dst.Unlock(dstp);
  108. image.Unlock(srcp);
  109. return dst;
  110. }
  111. /* This is Bresenham resizing. I “rediscovered” it independently but
  112. * it was actually first described in 1995 by Tim Kientzle in “Scaling
  113. * Bitmaps with Bresenham”. */
  114. /* FIXME: the algorithm does not handle alpha components properly. Resulting
  115. * alpha should be the mean alpha value of the neightbouring pixels, but
  116. * the colour components should be weighted with the alpha value. */
  117. static Image ResizeBresenham(Image &image, ivec2 size)
  118. {
  119. Image dst(size);
  120. ivec2 const oldsize = image.GetSize();
  121. float const invswsh = 1.0f / (oldsize.x * oldsize.y);
  122. vec4 const *srcp = image.Lock<PixelFormat::RGBA_F32>();
  123. vec4 *dstp = dst.Lock<PixelFormat::RGBA_F32>();
  124. array<vec4> aline, line;
  125. aline.Resize(size.x);
  126. line.Resize(size.x);
  127. memset(line.Data(), 0, line.Bytes());
  128. int remy = 0;
  129. for (int y = 0, y0 = 0; y < size.y; y++)
  130. {
  131. memset(aline.Data(), 0, aline.Bytes());
  132. for (int toty = 0; toty < oldsize.y; )
  133. {
  134. if (remy == 0)
  135. {
  136. vec4 color(0.f);
  137. int remx = 0;
  138. for (int x = 0, x0 = 0; x < size.x; x++)
  139. {
  140. vec4 acolor(0.f);
  141. for (int totx = 0; totx < oldsize.x; )
  142. {
  143. if (remx == 0)
  144. {
  145. color = srcp[y0 * oldsize.x + x0];
  146. x0++;
  147. remx = size.x;
  148. }
  149. int nx = lol::min(remx, oldsize.x - totx);
  150. acolor += (float)nx * color;
  151. totx += nx;
  152. remx -= nx;
  153. }
  154. line[x] = acolor;
  155. }
  156. y0++;
  157. remy = size.y;
  158. }
  159. int ny = lol::min(remy, oldsize.y - toty);
  160. for (int x = 0; x < size.x; x++)
  161. aline[x] += (float)ny * line[x];
  162. toty += ny;
  163. remy -= ny;
  164. }
  165. for (int x = 0; x < size.x; x++)
  166. dstp[y * size.x + x] = aline[x] * invswsh;
  167. }
  168. dst.Unlock(dstp);
  169. image.Unlock(srcp);
  170. return dst;
  171. }
  172. } /* namespace lol */