Kstars

scanrender.cpp
1 /*
2  SPDX-FileCopyrightText: 2015-2017 Pavel Mraz
3 
4  SPDX-FileCopyrightText: 2017 Jasem Mutlaq
5 
6  SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #include "scanrender.h"
10 
11 //#include <omp.h>
12 //#define PARALLEL_OMP
13 
14 #define FRAC(f, from, to) ((((f) - (from)) / (double)((to) - (from))))
15 #define LERP(f, mi, ma) ((mi) + (f) * ((ma) - (mi)))
16 #define CLAMP(v, mi, ma) (((v) < (mi)) ? (mi) : ((v) > (ma)) ? (ma) : (v))
17 #define SIGN(x) ((x) >= 0 ? 1.0 : -1.0)
18 
19 #pragma GCC diagnostic push
20 #pragma GCC diagnostic ignored "-Wcast-align"
21 
22 //////////////////////////////
23 ScanRender::ScanRender(void)
24 //////////////////////////////
25 {
26 }
27 
28 /////////////////////////////////////////////////
29 void ScanRender::setBilinearInterpolationEnabled(bool enable)
30 /////////////////////////////////////////////////
31 {
32  bBilinear = enable;
33 }
34 
35 //////////////////////////////////
36 bool ScanRender::isBilinearInterpolationEnabled()
37 //////////////////////////////////
38 {
39  return(bBilinear);
40 }
41 
42 ///////////////////////////////////////////////
43 void ScanRender::resetScanPoly(int sx, int sy)
44 ///////////////////////////////////////////////
45 {
46  plMinY = 999999;
47  plMaxY = -999999;
48 
49  if (sy >= MAX_BK_SCANLINES)
50  {
51  qDebug("ScanRender::resetScanPoly fail!");
52  return;
53  }
54 
55  m_sx = sx;
56  m_sy = sy;
57 }
58 
59 //////////////////////////////////////////////////////////
60 void ScanRender::scanLine(int x1, int y1, int x2, int y2)
61 //////////////////////////////////////////////////////////
62 {
63  int side;
64 
65  if (y1 > y2)
66  {
67  qSwap(x1, x2);
68  qSwap(y1, y2);
69  side = 0;
70  }
71  else
72  {
73  side = 1;
74  }
75 
76  if (y2 < 0)
77  {
78  return; // offscreen
79  }
80 
81  if (y1 >= m_sy)
82  {
83  return; // offscreen
84  }
85 
86  float dy = (float)(y2 - y1);
87 
88  if (dy == 0) // hor. line
89  {
90  return;
91  }
92 
93  float dx = (float)(x2 - x1) / dy;
94  float x = x1;
95  int y;
96 
97  if (y2 >= m_sy)
98  {
99  y2 = m_sy - 1;
100  }
101 
102  if (y1 < 0)
103  { // partially off screen
104  float m = (float) -y1;
105 
106  x += dx * m;
107  y1 = 0;
108  }
109 
110  int minY = qMin(y1, y2);
111  int maxY = qMax(y1, y2);
112 
113  if (minY < plMinY)
114  plMinY = minY;
115  if (maxY > plMaxY)
116  plMaxY = maxY;
117 
118 #define SCAN_FIX_PT 1
119 
120 #if SCAN_FIX_PT
121 
122 #define FP 16
123 
124  int fx = (int)(x * (float)(1 << FP));
125  int fdx = (int)(dx * (float)(1 << FP));
126 
127  for (y = y1; y <= y2; y++)
128  {
129  scLR[y].scan[side] = fx >> FP;
130  fx += fdx;
131  }
132 
133 #else
134 
135  for (y = y1; y <= y2; y++)
136  {
137  if (side == 1)
138  { // side left
139  scLR[y].scan[0] = float2int(x);
140  }
141  else
142  { // side right
143  scLR[y].scan[1] = float2int(x);
144  }
145  x += dx;
146  }
147 
148 #endif
149 }
150 
151 
152 //////////////////////////////////////////////////////////////////////////////////////////////////
153 void ScanRender::scanLine(int x1, int y1, int x2, int y2, float u1, float v1, float u2, float v2)
154 //////////////////////////////////////////////////////////////////////////////////////////////////
155 {
156  int side;
157 
158  if (y1 > y2)
159  {
160  qSwap(x1, x2);
161  qSwap(y1, y2);
162  qSwap(u1, u2);
163  qSwap(v1, v2);
164  side = 0;
165  }
166  else
167  {
168  side = 1;
169  }
170 
171  if (y2 < 0)
172  return; // offscreen
173  if (y1 >= m_sy)
174  return; // offscreen
175 
176  float dy = (float)(y2 - y1);
177 
178  if (dy == 0) // hor. line
179  return;
180 
181  float dx = (float)(x2 - x1) / dy;
182  float x = x1;
183  int y;
184 
185  if (y2 >= m_sy)
186  y2 = m_sy - 1;
187 
188  float duv[2];
189  float uv[2] = {u1, v1};
190 
191  duv[0] = (u2 - u1) / dy;
192  duv[1] = (v2 - v1) / dy;
193 
194  if (y1 < 0)
195  { // partially off screen
196  float m = (float) -y1;
197 
198  uv[0] += duv[0] * m;
199  uv[1] += duv[1] * m;
200 
201  x += dx * m;
202  y1 = 0;
203  }
204 
205  int minY = qMin(y1, y2);
206  int maxY = qMax(y1, y2);
207 
208  if (minY < plMinY)
209  plMinY = minY;
210  if (maxY > plMaxY)
211  plMaxY = maxY;
212 
213  for (y = y1; y <= y2; y++)
214  {
215  scLR[y].scan[side] = (int)x;
216  scLR[y].uv[side][0] = uv[0];
217  scLR[y].uv[side][1] = uv[1];
218 
219  x += dx;
220 
221  uv[0] += duv[0];
222  uv[1] += duv[1];
223  }
224 }
225 
226 
227 ////////////////////////////////////////////////////////
228 void ScanRender::renderPolygon(QColor col, QImage *dst)
229 ////////////////////////////////////////////////////////
230 {
231  quint32 c = col.rgb();
232  quint32 *bits = (quint32 *)dst->bits();
233  int dw = dst->width();
234  bkScan_t *scan = scLR;
235 
236  for (int y = plMinY; y <= plMaxY; y++)
237  {
238  int px1 = scan[y].scan[0];
239  int px2 = scan[y].scan[1];
240 
241  if (px1 > px2)
242  {
243  qSwap(px1, px2);
244  }
245 
246  if (px1 < 0)
247  {
248  px1 = 0;
249  if (px2 < 0)
250  {
251  continue;
252  }
253  }
254 
255  if (px2 >= m_sx)
256  {
257  if (px1 >= m_sx)
258  {
259  continue;
260  }
261  px2 = m_sx - 1;
262  }
263 
264  quint32 *pDst = bits + (y * dw) + px1;
265  for (int x = px1; x < px2; x++)
266  {
267  *pDst = c;
268  pDst++;
269  }
270  }
271 }
272 
273 
274 /////////////////////////////////////////////////////////////
275 void ScanRender::renderPolygonAlpha(QColor col, QImage *dst)
276 /////////////////////////////////////////////////////////////
277 {
278  quint32 c = col.rgba();
279  quint32 *bits = (quint32 *)dst->bits();
280  int dw = dst->width();
281  bkScan_t *scan = scLR;
282  float a = qAlpha(c) / 256.0f;
283  int rc = qRed(c);
284  int gc = qGreen(c);
285  int bc = qBlue(c);
286 
287  for (int y = plMinY; y <= plMaxY; y++)
288  {
289  int px1 = scan[y].scan[0];
290  int px2 = scan[y].scan[1];
291 
292  if (px1 > px2)
293  {
294  qSwap(px1, px2);
295  }
296 
297  if (px1 < 0)
298  {
299  px1 = 0;
300  }
301 
302  if (px2 >= m_sx)
303  {
304  px2 = m_sx - 1;
305  }
306 
307  quint32 *pDst = bits + (y * dw) + px1;
308  for (int x = px1; x < px2; x++)
309  {
310  QRgb rgbd = *pDst;
311 
312  *pDst = qRgb(LERP(a, qRed(rgbd), rc),
313  LERP(a, qGreen(rgbd), gc),
314  LERP(a, qBlue(rgbd), bc)
315  );
316  pDst++;
317  }
318  }
319 }
320 
321 void ScanRender::setOpacity(float opacity)
322 {
323  m_opacity = opacity;
324 }
325 
326 /////////////////////////////////////////////////////////
327 void ScanRender::renderPolygon(QImage *dst, QImage *src)
328 /////////////////////////////////////////////////////////
329 {
330  if (bBilinear)
331  renderPolygonBI(dst, src);
332  else
333  renderPolygonNI(dst, src);
334 }
335 
336 void ScanRender::renderPolygon(int interpolation, QPointF *pts, QImage *pDest, QImage *pSrc, QPointF *uv)
337 {
338  QPointF Auv = uv[0];
339  QPointF Buv = uv[1];
340  QPointF Cuv = uv[2];
341  QPointF Duv = uv[3];
342 
343  if (interpolation < 2)
344  {
345  resetScanPoly(pDest->width(), pDest->height());
346  scanLine(pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y(), 1, 1, 1, 0);
347  scanLine(pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(), 1, 0, 0, 0);
348  scanLine(pts[2].x(), pts[2].y(), pts[3].x(), pts[3].y(), 0, 0, 0, 1);
349  scanLine(pts[3].x(), pts[3].y(), pts[0].x(), pts[0].y(), 0, 1, 1, 1);
350  renderPolygon(pDest, pSrc);
351  return;
352  }
353 
354  QPointF A = pts[0];
355  QPointF B = pts[1];
356  QPointF C = pts[2];
357  QPointF D = pts[3];
358 
359  //p->setPen(Qt::green);
360 
361  for (int i = 0; i < interpolation; i++)
362  {
363  QPointF P1 = A + i * (D - A) / interpolation;
364  QPointF P1uv = Auv + i * (Duv - Auv) / interpolation;
365 
366  QPointF P2 = B + i * (C - B) / interpolation;
367  QPointF P2uv = Buv + i * (Cuv - Buv) / interpolation;
368 
369  QPointF Q1 = A + (i + 1) * (D - A) / interpolation;
370  QPointF Q1uv = Auv + (i + 1) * (Duv - Auv) / interpolation;
371 
372  QPointF Q2 = B + (i + 1) * (C - B) / interpolation;
373  QPointF Q2uv = Buv + (i + 1) * (Cuv - Buv) / interpolation;
374 
375  for (int j = 0; j < interpolation; j++)
376  {
377  QPointF A1 = P1 + j * (P2 - P1) / interpolation;
378  QPointF A1uv = P1uv + j * (P2uv - P1uv) / interpolation;
379 
380  QPointF B1 = P1 + (j + 1) * (P2 - P1) / interpolation;
381  QPointF B1uv = P1uv + (j + 1) * (P2uv - P1uv) / interpolation;
382 
383  QPointF C1 = Q1 + (j + 1) * (Q2 - Q1) / interpolation;
384  QPointF C1uv = Q1uv + (j + 1) * (Q2uv - Q1uv) / interpolation;
385 
386  QPointF D1 = Q1 + j * (Q2 - Q1) / interpolation;
387  QPointF D1uv = Q1uv + j * (Q2uv - Q1uv) / interpolation;
388 
389  resetScanPoly(pDest->width(), pDest->height());
390  scanLine(A1.x(), A1.y(), B1.x(), B1.y(), A1uv.x(), A1uv.y(), B1uv.x(), B1uv.y());
391  scanLine(B1.x(), B1.y(), C1.x(), C1.y(), B1uv.x(), B1uv.y(), C1uv.x(), C1uv.y());
392  scanLine(C1.x(), C1.y(), D1.x(), D1.y(), C1uv.x(), C1uv.y(), D1uv.x(), D1uv.y());
393  scanLine(D1.x(), D1.y(), A1.x(), A1.y(), D1uv.x(), D1uv.y(), A1uv.x(), A1uv.y());
394  renderPolygon(pDest, pSrc);
395 
396  //p->drawLine(A1, B1);
397  //p->drawLine(B1, C1);
398  //p->drawLine(C1, D1);
399  //p->drawLine(D1, A1);
400  }
401  }
402 }
403 
404 ///////////////////////////////////////////////////////////
405 void ScanRender::renderPolygonNI(QImage *dst, QImage *src)
406 ///////////////////////////////////////////////////////////
407 {
408  int w = dst->width();
409  int sw = src->width();
410  int sh = src->height();
411  float tsx = src->width() - 1;
412  float tsy = src->height() - 1;
413  const quint32 *bitsSrc = (quint32 *)src->constBits();
414  quint32 *bitsDst = (quint32 *)dst->bits();
415  bkScan_t *scan = scLR;
416  bool bw = src->format() == QImage::Format_Indexed8 || src->format() == QImage::Format_Grayscale8;
417 
418  //#pragma omp parallel for
419  for (int y = plMinY; y <= plMaxY; y++)
420  {
421  if (scan[y].scan[0] > scan[y].scan[1])
422  {
423  qSwap(scan[y].scan[0], scan[y].scan[1]);
424  qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
425  qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
426  }
427 
428  int px1 = scan[y].scan[0];
429  int px2 = scan[y].scan[1];
430 
431  float dx = px2 - px1;
432  if (dx == 0)
433  continue;
434 
435  float duv[2];
436  float uv[2];
437 
438  duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
439  duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
440 
441  uv[0] = scan[y].uv[0][0];
442  uv[1] = scan[y].uv[0][1];
443 
444  if (px1 < 0)
445  {
446  float m = (float)-px1;
447 
448  px1 = 0;
449  uv[0] += duv[0] * m;
450  uv[1] += duv[1] * m;
451  }
452 
453  if (px2 >= w)
454  px2 = w - 1;
455 
456  uv[0] *= tsx;
457  uv[1] *= tsy;
458 
459  duv[0] *= tsx;
460  duv[1] *= tsy;
461 
462  quint32 *pDst = bitsDst + (y * w) + px1;
463 
464  int fuv[2];
465  int fduv[2];
466 
467  fuv[0] = uv[0] * 65536;
468  fuv[1] = uv[1] * 65536;
469 
470  fduv[0] = duv[0] * 65536;
471  fduv[1] = duv[1] * 65536;
472 
473  fuv[0] = CLAMP(fuv[0], 0, (sw - 1) * 65536.);
474  fuv[1] = CLAMP(fuv[1], 0, (sh - 1) * 65536.);
475 
476  if (bw)
477  {
478  for (int x = px1; x < px2; x++)
479  {
480  const uchar *pSrc = (uchar *)bitsSrc + (fuv[0] >> 16) + ((fuv[1] >> 16) * sw);
481  *pDst = qRgb(*pSrc, *pSrc, *pSrc);
482  pDst++;
483 
484  fuv[0] += fduv[0];
485  fuv[1] += fduv[1];
486  }
487  }
488  else
489  {
490  for (int x = px1; x < px2; x++)
491  {
492  int offset = (fuv[0] >> 16) + ((fuv[1] >> 16) * sw);
493 
494  const quint32 *pSrc = bitsSrc + offset;
495  *pDst = (*pSrc) | (0xFF << 24);
496 
497  pDst++;
498 
499  fuv[0] += fduv[0];
500  fuv[1] += fduv[1];
501  }
502  }
503  }
504 }
505 
506 
507 ///////////////////////////////////////////////////////////
508 void ScanRender::renderPolygonBI(QImage *dst, QImage *src)
509 ///////////////////////////////////////////////////////////
510 {
511  int w = dst->width();
512  int sw = src->width();
513  int sh = src->height();
514  float tsx = src->width() - 1;
515  float tsy = src->height() - 1;
516  const quint32 *bitsSrc = (quint32 *)src->constBits();
517  const uchar *bitsSrc8 = (uchar *)src->constBits();
518  quint32 *bitsDst = (quint32 *)dst->bits();
519  bkScan_t *scan = scLR;
520  bool bw = src->format() == QImage::Format_Indexed8 || src->format() == QImage::Format_Grayscale8;
521 
522 #ifdef PARALLEL_OMP
523  #pragma omp parallel for
524 #endif
525  for (int y = plMinY; y <= plMaxY; y++)
526  {
527  if (scan[y].scan[0] > scan[y].scan[1])
528  {
529  qSwap(scan[y].scan[0], scan[y].scan[1]);
530  qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
531  qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
532  }
533 
534  int px1 = scan[y].scan[0];
535  int px2 = scan[y].scan[1];
536 
537  float dx = px2 - px1;
538  if (dx == 0)
539  continue;
540 
541  float duv[2];
542  float uv[2];
543 
544  duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
545  duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
546 
547  uv[0] = scan[y].uv[0][0];
548  uv[1] = scan[y].uv[0][1];
549 
550  if (px1 < 0)
551  {
552  float m = (float)-px1;
553 
554  px1 = 0;
555  uv[0] += duv[0] * m;
556  uv[1] += duv[1] * m;
557  }
558 
559  if (px2 >= w)
560  px2 = w - 1;
561 
562  uv[0] *= tsx;
563  uv[1] *= tsy;
564 
565  duv[0] *= tsx;
566  duv[1] *= tsy;
567 
568  int size = sw * sh;
569 
570  quint32 *pDst = bitsDst + (y * w) + px1;
571  if (bw)
572  {
573  for (int x = px1; x < px2; x++)
574  {
575  float x_diff = uv[0] - static_cast<int>(uv[0]);
576  float y_diff = uv[1] - static_cast<int>(uv[1]);
577  float x_1diff = 1 - x_diff;
578  float y_1diff = 1 - y_diff;
579 
580  int index = ((int)uv[0] + ((int)uv[1] * sw));
581 
582  uchar a = bitsSrc8[index];
583  uchar b = bitsSrc8[(index + 1) % size];
584  uchar c = bitsSrc8[(index + sw) % size];
585  uchar d = bitsSrc8[(index + sw + 1) % size];
586 
587  int val = (a&0xff)*(x_1diff)*(y_1diff) + (b&0xff)*(x_diff)*(y_1diff) +
588  (c&0xff)*(y_diff)*(x_1diff) + (d&0xff)*(x_diff*y_diff);
589 
590  *pDst = 0xff000000 |
591  ((((int)val)<<16)&0xff0000) |
592  ((((int)val)<<8)&0xff00) |
593  ((int)val) ;
594  pDst++;
595 
596  uv[0] += duv[0];
597  uv[1] += duv[1];
598  }
599  }
600  else
601  {
602  for (int x = px1; x < px2; x++)
603  {
604  float x_diff = uv[0] - static_cast<int>(uv[0]);
605  float y_diff = uv[1] - static_cast<int>(uv[1]);
606  float x_1diff = 1 - x_diff;
607  float y_1diff = 1 - y_diff;
608 
609  int index = ((int)uv[0] + ((int)uv[1] * sw));
610 
611  quint32 a = bitsSrc[index];
612  quint32 b = bitsSrc[(index + 1) % size];
613  quint32 c = bitsSrc[(index + sw) % size];
614  quint32 d = bitsSrc[(index + sw + 1) % size];
615 
616  int qxy1 = (x_1diff * y_1diff) * 65536;
617  int qxy2 =(x_diff * y_1diff) * 65536;
618  int qxy = (x_diff * y_diff) * 65536;
619  int qyx1 = (y_diff * x_1diff) * 65536;
620 
621  // blue element
622  int blue = ((a&0xff)*(qxy1) + (b&0xff)*(qxy2) + (c&0xff)*(qyx1) + (d&0xff)*(qxy)) >> 16;
623 
624  // green element
625  int green = (((a>>8)&0xff)*(qxy1) + ((b>>8)&0xff)*(qxy2) + ((c>>8)&0xff)*(qyx1) + ((d>>8)&0xff)*(qxy)) >> 16;
626 
627  // red element
628  int red = (((a>>16)&0xff)*(qxy1) + ((b>>16)&0xff)*(qxy2) +((c>>16)&0xff)*(qyx1) + ((d>>16)&0xff)*(qxy)) >> 16;
629 
630  *pDst = 0xff000000 | (((red)<<16)&0xff0000) | (((green)<<8)&0xff00) | (blue);
631 
632  pDst++;
633 
634  uv[0] += duv[0];
635  uv[1] += duv[1];
636  }
637  }
638  }
639 }
640 
641 void ScanRender::renderPolygonAlpha(QImage *dst, QImage *src)
642 {
643  if (bBilinear)
644  renderPolygonAlphaBI(dst, src);
645  else
646  renderPolygonAlphaNI(dst, src);
647 }
648 
649 
650 void ScanRender::renderPolygonAlphaBI(QImage *dst, QImage *src)
651 {
652  int w = dst->width();
653  int sw = src->width();
654  int sh = src->height();
655  float tsx = src->width() - 1;
656  float tsy = src->height() - 1;
657  const quint32 *bitsSrc = (quint32 *)src->constBits();
658  quint32 *bitsDst = (quint32 *)dst->bits();
659  bkScan_t *scan = scLR;
660  bool bw = src->format() == QImage::Format_Indexed8;
661  float opacity = (m_opacity / 65536.) * 0.00390625f;
662 
663 #ifdef PARALLEL_OMP
664  #pragma omp parallel for shared(bitsDst, bitsSrc, scan, tsx, tsy, w, sw)
665 #endif
666  for (int y = plMinY; y <= plMaxY; y++)
667  {
668  if (scan[y].scan[0] > scan[y].scan[1])
669  {
670  qSwap(scan[y].scan[0], scan[y].scan[1]);
671  qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
672  qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
673  }
674 
675  int px1 = scan[y].scan[0];
676  int px2 = scan[y].scan[1];
677 
678  float dx = px2 - px1;
679  if (dx == 0)
680  continue;
681 
682  float duv[2];
683  float uv[2];
684 
685  duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
686  duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
687 
688  uv[0] = scan[y].uv[0][0];
689  uv[1] = scan[y].uv[0][1];
690 
691  if (px1 < 0)
692  {
693  float m = (float)-px1;
694 
695  px1 = 0;
696  uv[0] += duv[0] * m;
697  uv[1] += duv[1] * m;
698  }
699 
700  if (px2 >= w)
701  px2 = w - 1;
702 
703  uv[0] *= tsx;
704  uv[1] *= tsy;
705 
706  duv[0] *= tsx;
707  duv[1] *= tsy;
708 
709  int size = sw * sh;
710 
711  quint32 *pDst = bitsDst + (y * w) + px1;
712  if (bw)
713  {
714  /*
715  for (int x = px1; x < px2; x++)
716  {
717  float x_diff = uv[0] - static_cast<int>(uv[0]);
718  float y_diff = uv[1] - static_cast<int>(uv[1]);
719  float x_1diff = 1 - x_diff;
720  float y_1diff = 1 - y_diff;
721 
722  int index = ((int)uv[0] + ((int)uv[1] * sw));
723 
724  uchar a = bitsSrc8[index];
725  uchar b = bitsSrc8[(index + 1) % size];
726  uchar c = bitsSrc8[(index + sw) % size];
727  uchar d = bitsSrc8[(index + sw + 1) % size];
728 
729  int val = (a&0xff)*(x_1diff)*(y_1diff) + (b&0xff)*(x_diff)*(y_1diff) +
730  (c&0xff)*(y_diff)*(x_1diff) + (d&0xff)*(x_diff*y_diff);
731 
732 
733  *pDst = 0xff000000 |
734  ((((int)val)<<16)&0xff0000) |
735  ((((int)val)<<8)&0xff00) |
736  ((int)val) ;
737  pDst++;
738 
739  uv[0] += duv[0];
740  uv[1] += duv[1];
741  }
742  */
743  }
744  else
745  {
746  for (int x = px1; x < px2; x++)
747  {
748  float x_diff = uv[0] - static_cast<int>(uv[0]);
749  float y_diff = uv[1] - static_cast<int>(uv[1]);
750  float x_1diff = 1 - x_diff;
751  float y_1diff = 1 - y_diff;
752 
753  int index = ((int)uv[0] + ((int)uv[1] * sw));
754 
755  quint32 a = bitsSrc[index];
756  quint32 b = bitsSrc[(index + 1) % size];
757  quint32 c = bitsSrc[(index + sw) % size];
758  quint32 d = bitsSrc[(index + sw + 1) % size];
759 
760  int x1y1 = (x_1diff * y_1diff) * 65536;
761  int xy = (x_diff * y_diff) * 65536;
762  int x1y = (y_diff * x_1diff) * 65536;
763  int xy1 = (x_diff *y_1diff) * 65536;
764 
765  float alpha = ((((a>>24)&0xff)*(x1y1) + ((b>>24)&0xff)*(xy1) +
766  ((c>>24)&0xff)*(x1y) + ((d>>24)&0xff)*(xy)) * opacity);
767 
768  if (alpha > 0.00390625f) // > 1 / 256.
769  {
770  // blue element
771  int blue = ((a&0xff)*(x1y1) + (b&0xff)* (xy1) +
772  (c&0xff)*(x1y) + (d&0xff)*(xy)) >> 16;
773 
774  // green element
775  int green = (((a>>8)&0xff)*(x1y1) + ((b>>8)&0xff)*(xy1) +
776  ((c>>8)&0xff)*(x1y) + ((d>>8)&0xff)*(xy)) >> 16;
777 
778  // red element
779  int red = (((a>>16)&0xff)*(x1y1) + ((b>>16)&0xff)*(xy1) +
780  ((c>>16)&0xff)*(x1y) + ((d>>16)&0xff)*(xy)) >> 16;
781 
782  int rd = qRed(*pDst);
783  int gd = qGreen(*pDst);
784  int bd = qBlue(*pDst);
785 
786  *pDst = qRgb(LERP(alpha, rd, red), LERP(alpha, gd, green), LERP(alpha, bd, blue));
787  }
788 
789  pDst++;
790 
791  uv[0] += duv[0];
792  uv[1] += duv[1];
793  }
794  }
795  }
796 }
797 
798 
799 ////////////////////////////////////////////////////////////////
800 void ScanRender::renderPolygonAlphaNI(QImage *dst, QImage *src)
801 ////////////////////////////////////////////////////////////////
802 {
803  int w = dst->width();
804  int sw = src->width();
805  float tsx = src->width() - 1;
806  float tsy = src->height() - 1;
807  const quint32 *bitsSrc = (quint32 *)src->constBits();
808  quint32 *bitsDst = (quint32 *)dst->bits();
809  bkScan_t *scan = scLR;
810  float opacity = 0.00390625f * m_opacity;
811 
812 #ifdef PARALLEL_OMP
813  #pragma omp parallel for shared(bitsDst, bitsSrc, scan, tsx, tsy, w, sw)
814 #endif
815  for (int y = plMinY; y <= plMaxY; y++)
816  {
817  if (scan[y].scan[0] > scan[y].scan[1])
818  {
819  qSwap(scan[y].scan[0], scan[y].scan[1]);
820  qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
821  qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
822  }
823 
824  int px1 = scan[y].scan[0];
825  int px2 = scan[y].scan[1];
826 
827  float dx = px2 - px1;
828  if (dx == 0)
829  continue;
830 
831  float duv[2];
832  float uv[2];
833 
834  duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
835  duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
836 
837  uv[0] = scan[y].uv[0][0];
838  uv[1] = scan[y].uv[0][1];
839 
840  if (px1 < 0)
841  {
842  float m = (float)-px1;
843 
844  px1 = 0;
845  uv[0] += duv[0] * m;
846  uv[1] += duv[1] * m;
847  }
848 
849  if (px2 >= w)
850  px2 = w - 1;
851 
852  quint32 *pDst = bitsDst + (y * w) + px1;
853 
854  uv[0] *= tsx;
855  uv[1] *= tsy;
856 
857  duv[0] *= tsx;
858  duv[1] *= tsy;
859 
860  for (int x = px1; x < px2; x++)
861  {
862  const quint32 *pSrc = bitsSrc + ((int)(uv[0])) + ((int)(uv[1]) * sw);
863  QRgb rgbs = *pSrc;
864  QRgb rgbd = *pDst;
865  float a = qAlpha(*pSrc) * opacity;
866 
867  if (a > 0.00390625f)
868  {
869  *pDst = qRgb(LERP(a, qRed(rgbd), qRed(rgbs)),
870  LERP(a, qGreen(rgbd), qGreen(rgbs)),
871  LERP(a, qBlue(rgbd), qBlue(rgbs))
872  );
873  }
874  pDst++;
875 
876  uv[0] += duv[0];
877  uv[1] += duv[1];
878  }
879  }
880 }
881 
882 #pragma GCC diagnostic pop
int height() const const
QRgb rgb() const const
QImage::Format format() const const
uchar * bits()
qreal x() const const
qreal y() const const
const uchar * constBits() const const
QRgb rgba() const const
int width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sun Aug 14 2022 04:14:00 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.