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 //////////////////////////////
ScanRender(void)23 ScanRender::ScanRender(void)
24 //////////////////////////////
25 {
26 }
27 
28 /////////////////////////////////////////////////
setBilinearInterpolationEnabled(bool enable)29 void ScanRender::setBilinearInterpolationEnabled(bool enable)
30 /////////////////////////////////////////////////
31 {
32   bBilinear = enable;
33 }
34 
35 //////////////////////////////////
isBilinearInterpolationEnabled()36 bool ScanRender::isBilinearInterpolationEnabled()
37 //////////////////////////////////
38 {
39   return(bBilinear);
40 }
41 
42 ///////////////////////////////////////////////
resetScanPoly(int sx,int sy)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 //////////////////////////////////////////////////////////
scanLine(int x1,int y1,int x2,int y2)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 //////////////////////////////////////////////////////////////////////////////////////////////////
scanLine(int x1,int y1,int x2,int y2,float u1,float v1,float u2,float v2)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 ////////////////////////////////////////////////////////
renderPolygon(QColor col,QImage * dst)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 /////////////////////////////////////////////////////////////
renderPolygonAlpha(QColor col,QImage * dst)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 
setOpacity(float opacity)321 void ScanRender::setOpacity(float opacity)
322 {
323   m_opacity = opacity;
324 }
325 
326 /////////////////////////////////////////////////////////
renderPolygon(QImage * dst,QImage * src)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 
renderPolygon(int interpolation,QPointF * pts,QImage * pDest,QImage * pSrc,QPointF * uv)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 ///////////////////////////////////////////////////////////
renderPolygonNI(QImage * dst,QImage * src)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 ///////////////////////////////////////////////////////////
renderPolygonBI(QImage * dst,QImage * src)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 
renderPolygonAlpha(QImage * dst,QImage * src)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 
renderPolygonAlphaBI(QImage * dst,QImage * src)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 ////////////////////////////////////////////////////////////////
renderPolygonAlphaNI(QImage * dst,QImage * src)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
883