/uppsrc/Painter/Image.cpp

https://github.com/ultimatepp/mirror · C++ · 365 lines · 327 code · 38 blank · 0 comment · 132 complexity · b97532c94376ca135fef83bfbf325be3 MD5 · raw file

  1. #include "Painter.h"
  2. namespace Upp {
  3. #ifdef CPU_SIMD
  4. force_inline
  5. int IntAndFraction(f32x4 x, f32x4& fraction)
  6. {
  7. x = x + f32all(8000); // Truncate truncates toward 0, need to fix negatives
  8. i32x4 m = Truncate(x);
  9. fraction = x - ToFloat(m);
  10. return (int)m - 8000;
  11. }
  12. force_inline
  13. int Int(f32x4 x)
  14. {
  15. return (int)Truncate(x + f32all(8000)) - 8000;
  16. }
  17. struct PainterImageSpanData {
  18. int ax, ay, cx, cy, maxx, maxy;
  19. byte style;
  20. byte hstyle, vstyle;
  21. bool fast;
  22. bool fixed;
  23. Image image;
  24. Xform2D xform;
  25. PainterImageSpanData(dword flags, const Xform2D& m, const Image& img, bool co, bool imagecache) {
  26. style = byte(flags & 15);
  27. hstyle = byte(flags & 3);
  28. vstyle = byte(flags & 12);
  29. fast = flags & FILL_FAST;
  30. image = img;
  31. int nx = 1;
  32. int ny = 1;
  33. if(!fast) {
  34. Pointf sc = m.GetScaleXY();
  35. if(sc.x >= 0.01 && sc.y >= 0.01) {
  36. nx = (int)max(1.0, 1.0 / sc.x);
  37. ny = (int)max(1.0, 1.0 / sc.y);
  38. }
  39. }
  40. if(nx == 1 && ny == 1)
  41. xform = Inverse(m);
  42. else {
  43. if(!fast)
  44. image = (imagecache ? MinifyCached : Minify)(image, nx, ny, co);
  45. xform = Inverse(m) * Xform2D::Scale(1.0 / nx, 1.0 / ny);
  46. }
  47. cx = image.GetWidth();
  48. cy = image.GetHeight();
  49. maxx = cx - 1;
  50. maxy = cy - 1;
  51. ax = 6000000 / cx * cx * 2;
  52. ay = 6000000 / cy * cy * 2;
  53. }
  54. PainterImageSpanData() {}
  55. };
  56. struct PainterImageSpan : SpanSource, PainterImageSpanData {
  57. PainterImageSpan(const PainterImageSpanData& f)
  58. : PainterImageSpanData(f) {}
  59. const RGBA *Pixel(int x, int y) { return &image[y][x]; }
  60. const RGBA *GetPixel(int x, int y) {
  61. if(hstyle == FILL_HPAD)
  62. x = minmax(x, 0, maxx);
  63. else
  64. if(hstyle == FILL_HREFLECT)
  65. x = (x + ax) / cx & 1 ? (ax - x - 1) % cx : (x + ax) % cx;
  66. else
  67. if(hstyle == FILL_HREPEAT)
  68. x = (x + ax) % cx;
  69. if(vstyle == FILL_VPAD)
  70. y = minmax(y, 0, maxy);
  71. else
  72. if(vstyle == FILL_VREFLECT)
  73. y = (y + ay) / cy & 1 ? (ay - y - 1) % cy : (y + ay) % cy;
  74. else
  75. if(vstyle == FILL_VREPEAT)
  76. y = (y + ay) % cy;
  77. static RGBA zero;
  78. return fixed || (x >= 0 && x < cx && y >= 0 && y < cy) ? &image[y][x] : &zero;
  79. }
  80. virtual void Get(RGBA *span, int x, int y, unsigned len)
  81. {
  82. PAINTER_TIMING("ImageSpan::Get");
  83. Pointf p0 = xform.Transform(Pointf(x, y));
  84. Pointf dd = xform.Transform(Pointf(x + 1, y)) - p0;
  85. f32x4 x0 = f32all(p0.x);
  86. f32x4 y0 = f32all(p0.y);
  87. f32x4 dx = f32all(dd.x);
  88. f32x4 dy = f32all(dd.y);
  89. f32x4 ii = 0;
  90. f32x4 v1 = f32all(1);
  91. f32x4 ix, iy;
  92. auto GetIXY = [&] {
  93. ix = x0 + ii * dx;
  94. iy = y0 + ii * dy;
  95. ii += v1;
  96. };
  97. fixed = hstyle && vstyle;
  98. if(hstyle + vstyle == 0 && fast) {
  99. while(len--) {
  100. GetIXY();
  101. Point l(Int(ix), Int(iy));
  102. if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy)
  103. *span = *Pixel(l.x, l.y);
  104. else
  105. if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
  106. *span = RGBAZero();
  107. else
  108. *span = *GetPixel(l.x, l.y);
  109. ++span;
  110. }
  111. return;
  112. }
  113. while(len--) {
  114. GetIXY();
  115. f32x4 fx, fy;
  116. Point l(IntAndFraction(ix, fx), IntAndFraction(iy, fy));
  117. if(hstyle == FILL_HREPEAT)
  118. l.x = (l.x + ax) % cx;
  119. if(vstyle == FILL_VREPEAT)
  120. l.y = (l.y + ay) % cy;
  121. if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
  122. *span = RGBAZero();
  123. else
  124. if(fast) {
  125. if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy)
  126. *span = *Pixel(l.x, l.y);
  127. else
  128. *span = *GetPixel(l.x, l.y);
  129. }
  130. else {
  131. f32x4 p00, p01, p10, p11;
  132. if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy) {
  133. p00 = LoadRGBAF(Pixel(l.x + 0, l.y + 0));
  134. p01 = LoadRGBAF(Pixel(l.x + 0, l.y + 1));
  135. p10 = LoadRGBAF(Pixel(l.x + 1, l.y + 0));
  136. p11 = LoadRGBAF(Pixel(l.x + 1, l.y + 1));
  137. }
  138. else {
  139. p00 = LoadRGBAF(GetPixel(l.x + 0, l.y + 0));
  140. p01 = LoadRGBAF(GetPixel(l.x + 0, l.y + 1));
  141. p10 = LoadRGBAF(GetPixel(l.x + 1, l.y + 0));
  142. p11 = LoadRGBAF(GetPixel(l.x + 1, l.y + 1));
  143. }
  144. p01 = p01 * fy;
  145. p11 = p11 * fy;
  146. p10 = p10 * fx;
  147. p11 = p11 * fx;
  148. fx = v1 - fx;
  149. fy = v1 - fy;
  150. p00 = p00 * fy;
  151. p10 = p10 * fy;
  152. p00 = p00 * fx;
  153. p01 = p01 * fx;
  154. StoreRGBAF(span, p00 + p01 + p10 + p11);
  155. }
  156. ++span;
  157. }
  158. }
  159. };
  160. void BufferPainter::RenderImage(double width, const Image& image, const Xform2D& transsrc, dword flags)
  161. {
  162. current = Null;
  163. if(image.GetWidth() == 0 || image.GetHeight() == 0)
  164. return;
  165. PainterImageSpanData f(flags, transsrc * pathattr.mtx, image, co, imagecache);
  166. RenderPath(width, [&](One<SpanSource>& s) {
  167. s.Create<PainterImageSpan>(f);
  168. }, RGBAZero());
  169. }
  170. void BufferPainter::FillOp(const Image& image, const Xform2D& transsrc, dword flags)
  171. {
  172. Close();
  173. RenderImage(-1, image, transsrc, flags);
  174. }
  175. void BufferPainter::StrokeOp(double width, const Image& image, const Xform2D& transsrc, dword flags)
  176. {
  177. RenderImage(width, image, transsrc, flags);
  178. }
  179. #else
  180. struct PainterImageSpanData {
  181. int ax, ay, cx, cy, maxx, maxy;
  182. byte style;
  183. byte hstyle, vstyle;
  184. bool fast;
  185. bool fixed;
  186. Image image;
  187. Xform2D xform;
  188. PainterImageSpanData(dword flags, const Xform2D& m, const Image& img, bool co, bool imagecache) {
  189. style = byte(flags & 15);
  190. hstyle = byte(flags & 3);
  191. vstyle = byte(flags & 12);
  192. fast = flags & FILL_FAST;
  193. image = img;
  194. int nx = 1;
  195. int ny = 1;
  196. if(!fast) {
  197. Pointf sc = m.GetScaleXY();
  198. if(sc.x >= 0.01 && sc.y >= 0.01) {
  199. nx = (int)max(1.0, 1.0 / sc.x);
  200. ny = (int)max(1.0, 1.0 / sc.y);
  201. }
  202. }
  203. if(nx == 1 && ny == 1)
  204. xform = Inverse(m);
  205. else {
  206. if(!fast)
  207. image = (imagecache ? MinifyCached : Minify)(image, nx, ny, co);
  208. xform = Inverse(m) * Xform2D::Scale(1.0 / nx, 1.0 / ny);
  209. }
  210. cx = image.GetWidth();
  211. cy = image.GetHeight();
  212. maxx = cx - 1;
  213. maxy = cy - 1;
  214. ax = 6000000 / cx * cx * 2;
  215. ay = 6000000 / cy * cy * 2;
  216. }
  217. PainterImageSpanData() {}
  218. };
  219. struct PainterImageSpan : SpanSource, PainterImageSpanData {
  220. LinearInterpolator interpolator;
  221. PainterImageSpan(const PainterImageSpanData& f)
  222. : PainterImageSpanData(f) {
  223. interpolator.Set(xform);
  224. }
  225. RGBA Pixel(int x, int y) { return image[y][x]; }
  226. RGBA GetPixel(int x, int y) {
  227. if(hstyle == FILL_HPAD)
  228. x = minmax(x, 0, maxx);
  229. else
  230. if(hstyle == FILL_HREFLECT)
  231. x = (x + ax) / cx & 1 ? (ax - x - 1) % cx : (x + ax) % cx;
  232. else
  233. if(hstyle == FILL_HREPEAT)
  234. x = (x + ax) % cx;
  235. if(vstyle == FILL_VPAD)
  236. y = minmax(y, 0, maxy);
  237. else
  238. if(vstyle == FILL_VREFLECT)
  239. y = (y + ay) / cy & 1 ? (ay - y - 1) % cy : (y + ay) % cy;
  240. else
  241. if(vstyle == FILL_VREPEAT)
  242. y = (y + ay) % cy;
  243. return fixed || (x >= 0 && x < cx && y >= 0 && y < cy) ? image[y][x] : RGBAZero();
  244. }
  245. virtual void Get(RGBA *span, int x, int y, unsigned len)
  246. {
  247. PAINTER_TIMING("ImageSpan::Get");
  248. interpolator.Begin(x, y, len);
  249. fixed = hstyle && vstyle;
  250. if(hstyle + vstyle == 0 && fast) {
  251. while(len--) {
  252. Point l = interpolator.Get() >> 8;
  253. if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy)
  254. *span = Pixel(l.x, l.y);
  255. else
  256. if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
  257. *span = RGBAZero();
  258. else
  259. *span = GetPixel(l.x, l.y);
  260. ++span;
  261. }
  262. return;
  263. }
  264. while(len--) {
  265. Point h = interpolator.Get();
  266. Point l = h >> 8;
  267. if(hstyle == FILL_HREPEAT)
  268. l.x = (l.x + ax) % cx;
  269. if(vstyle == FILL_VREPEAT)
  270. l.y = (l.y + ay) % cy;
  271. if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy))
  272. *span = RGBAZero();
  273. else
  274. if(fast) {
  275. if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy)
  276. *span = Pixel(l.x, l.y);
  277. else
  278. *span = GetPixel(l.x, l.y);
  279. }
  280. else {
  281. RGBAV v;
  282. v.Set(0);
  283. h.x &= 255;
  284. h.y &= 255;
  285. Point u = -h + 256;
  286. if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy) {
  287. v.Put(u.x * u.y, Pixel(l.x, l.y));
  288. v.Put(h.x * u.y, Pixel(l.x + 1, l.y));
  289. v.Put(u.x * h.y, Pixel(l.x, l.y + 1));
  290. v.Put(h.x * h.y, Pixel(l.x + 1, l.y + 1));
  291. }
  292. else {
  293. v.Put(u.x * u.y, GetPixel(l.x, l.y));
  294. v.Put(h.x * u.y, GetPixel(l.x + 1, l.y));
  295. v.Put(u.x * h.y, GetPixel(l.x, l.y + 1));
  296. v.Put(h.x * h.y, GetPixel(l.x + 1, l.y + 1));
  297. }
  298. span->r = byte(v.r >> 16);
  299. span->g = byte(v.g >> 16);
  300. span->b = byte(v.b >> 16);
  301. span->a = byte(v.a >> 16);
  302. }
  303. ++span;
  304. }
  305. }
  306. };
  307. void BufferPainter::RenderImage(double width, const Image& image, const Xform2D& transsrc, dword flags)
  308. {
  309. current = Null;
  310. if(image.GetWidth() == 0 || image.GetHeight() == 0)
  311. return;
  312. PainterImageSpanData f(flags, transsrc * pathattr.mtx, image, co, imagecache);
  313. RenderPath(width, [&](One<SpanSource>& s) {
  314. s.Create<PainterImageSpan>(f);
  315. }, RGBAZero());
  316. }
  317. void BufferPainter::FillOp(const Image& image, const Xform2D& transsrc, dword flags)
  318. {
  319. Close();
  320. RenderImage(-1, image, transsrc, flags);
  321. }
  322. void BufferPainter::StrokeOp(double width, const Image& image, const Xform2D& transsrc, dword flags)
  323. {
  324. RenderImage(width, image, transsrc, flags);
  325. }
  326. #endif
  327. }