File indexing completed on 2024-04-21 03:43:59

0001 /*
0002     SPDX-FileCopyrightText: 2015-2017 Pavel Mraz
0003 
0004     SPDX-FileCopyrightText: 2017 Jasem Mutlaq
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "scanrender.h"
0010 
0011 //#include <omp.h>
0012 //#define PARALLEL_OMP
0013 
0014 #define FRAC(f, from, to)      ((((f) - (from)) / (double)((to) - (from))))
0015 #define LERP(f, mi, ma)        ((mi) + (f) * ((ma) - (mi)))
0016 #define CLAMP(v, mi, ma)       (((v) < (mi)) ? (mi) : ((v) > (ma)) ? (ma) : (v))
0017 #define SIGN(x)                ((x) >= 0 ? 1.0 : -1.0)
0018 
0019 #pragma GCC diagnostic push
0020 #pragma GCC diagnostic ignored "-Wcast-align"
0021 
0022 //////////////////////////////
0023 ScanRender::ScanRender(void)
0024 //////////////////////////////
0025 {
0026 }
0027 
0028 /////////////////////////////////////////////////
0029 void ScanRender::setBilinearInterpolationEnabled(bool enable)
0030 /////////////////////////////////////////////////
0031 {
0032   bBilinear = enable;
0033 }
0034 
0035 //////////////////////////////////
0036 bool ScanRender::isBilinearInterpolationEnabled()
0037 //////////////////////////////////
0038 {
0039   return(bBilinear);
0040 }
0041 
0042 ///////////////////////////////////////////////
0043 void ScanRender::resetScanPoly(int sx, int sy)
0044 ///////////////////////////////////////////////
0045 {
0046   plMinY =  999999;
0047   plMaxY = -999999;
0048 
0049   if (sy >= MAX_BK_SCANLINES)
0050   {
0051     qDebug("ScanRender::resetScanPoly fail!");
0052     return;
0053   }
0054 
0055   m_sx = sx;
0056   m_sy = sy;
0057 }
0058 
0059 //////////////////////////////////////////////////////////
0060 void ScanRender::scanLine(int x1, int y1, int x2, int y2)
0061 //////////////////////////////////////////////////////////
0062 {
0063   int side;
0064 
0065   if (y1 > y2)
0066   {
0067     qSwap(x1, x2);
0068     qSwap(y1, y2);
0069     side = 0;
0070   }
0071   else
0072   {
0073     side = 1;
0074   }
0075 
0076   if (y2 < 0)
0077   {
0078     return; // offscreen
0079   }
0080 
0081   if (y1 >= m_sy)
0082   {
0083     return; // offscreen
0084   }
0085 
0086   float dy = (float)(y2 - y1);
0087 
0088   if (dy == 0) // hor. line
0089   {
0090     return;
0091   }
0092 
0093   float dx = (float)(x2 - x1) / dy;
0094   float x = x1;
0095   int   y;
0096 
0097   if (y2 >= m_sy)
0098   {
0099     y2 = m_sy - 1;
0100   }
0101 
0102   if (y1 < 0)
0103   { // partially off screen
0104     float m = (float) -y1;
0105 
0106     x += dx * m;
0107     y1 = 0;
0108   }
0109 
0110   int minY = qMin(y1, y2);
0111   int maxY = qMax(y1, y2);
0112 
0113   if (minY < plMinY)
0114     plMinY = minY;
0115   if (maxY > plMaxY)
0116     plMaxY = maxY;
0117 
0118 #define SCAN_FIX_PT 1
0119 
0120 #if SCAN_FIX_PT
0121 
0122 #define FP 16
0123 
0124   int fx = (int)(x * (float)(1 << FP));
0125   int fdx = (int)(dx * (float)(1 << FP));
0126 
0127   for (y = y1; y <= y2; y++)
0128   {
0129     scLR[y].scan[side] = fx >> FP;
0130     fx += fdx;
0131   }
0132 
0133 #else
0134 
0135   for (y = y1; y <= y2; y++)
0136   {
0137     if (side == 1)
0138     { // side left
0139       scLR[y].scan[0] = float2int(x);
0140     }
0141     else
0142     { // side right
0143       scLR[y].scan[1] = float2int(x);
0144     }
0145     x += dx;
0146   }
0147 
0148 #endif
0149 }
0150 
0151 
0152 //////////////////////////////////////////////////////////////////////////////////////////////////
0153 void ScanRender::scanLine(int x1, int y1, int x2, int y2, float u1, float v1, float u2, float v2)
0154 //////////////////////////////////////////////////////////////////////////////////////////////////
0155 {
0156   int side;
0157 
0158   if (y1 > y2)
0159   {
0160     qSwap(x1, x2);
0161     qSwap(y1, y2);
0162     qSwap(u1, u2);
0163     qSwap(v1, v2);
0164     side = 0;
0165   }
0166   else
0167   {
0168     side = 1;
0169   }
0170 
0171   if (y2 < 0)
0172     return; // offscreen
0173   if (y1 >= m_sy)
0174     return; // offscreen
0175 
0176   float dy = (float)(y2 - y1);
0177 
0178   if (dy == 0) // hor. line
0179     return;
0180 
0181   float dx = (float)(x2 - x1) / dy;
0182   float x = x1;
0183   int   y;
0184 
0185   if (y2 >= m_sy)
0186     y2 = m_sy - 1;
0187 
0188   float duv[2];
0189   float uv[2] = {u1, v1};
0190 
0191   duv[0] = (u2 - u1) / dy;
0192   duv[1] = (v2 - v1) / dy;
0193 
0194   if (y1 < 0)
0195   { // partially off screen
0196     float m = (float) -y1;
0197 
0198     uv[0] += duv[0] * m;
0199     uv[1] += duv[1] * m;
0200 
0201     x += dx * m;
0202     y1 = 0;
0203   }
0204 
0205   int minY = qMin(y1, y2);
0206   int maxY = qMax(y1, y2);
0207 
0208   if (minY < plMinY)
0209     plMinY = minY;
0210   if (maxY > plMaxY)
0211     plMaxY = maxY;
0212 
0213   for (y = y1; y <= y2; y++)
0214   {
0215     scLR[y].scan[side] = (int)x;
0216     scLR[y].uv[side][0] = uv[0];
0217     scLR[y].uv[side][1] = uv[1];
0218 
0219     x += dx;
0220 
0221     uv[0] += duv[0];
0222     uv[1] += duv[1];
0223   }
0224 }
0225 
0226 
0227 ////////////////////////////////////////////////////////
0228 void ScanRender::renderPolygon(QColor col, QImage *dst)
0229 ////////////////////////////////////////////////////////
0230 { 
0231   quint32   c = col.rgb();
0232   quint32  *bits = (quint32 *)dst->bits();
0233   int       dw = dst->width();
0234   bkScan_t *scan = scLR;
0235 
0236   for (int y = plMinY; y <= plMaxY; y++)
0237   {
0238     int px1 = scan[y].scan[0];
0239     int px2 = scan[y].scan[1];
0240 
0241     if (px1 > px2)
0242     {
0243       qSwap(px1, px2);
0244     }
0245 
0246     if (px1 < 0)
0247     {
0248       px1 = 0;
0249       if (px2 < 0)
0250       {
0251         continue;
0252       }
0253     }
0254 
0255     if (px2 >= m_sx)
0256     {
0257       if (px1 >= m_sx)
0258       {
0259         continue;
0260       }
0261       px2 = m_sx - 1;
0262     }
0263 
0264     quint32 *pDst = bits + (y * dw) + px1;    
0265     for (int x = px1; x < px2; x++)
0266     {
0267       *pDst = c;
0268       pDst++;
0269     }    
0270   }
0271 }
0272 
0273 
0274 /////////////////////////////////////////////////////////////
0275 void ScanRender::renderPolygonAlpha(QColor col, QImage *dst)
0276 /////////////////////////////////////////////////////////////
0277 {
0278   quint32   c = col.rgba();
0279   quint32  *bits = (quint32 *)dst->bits();
0280   int       dw = dst->width();
0281   bkScan_t *scan = scLR;
0282   float     a = qAlpha(c) / 256.0f;
0283   int       rc = qRed(c);
0284   int       gc = qGreen(c);
0285   int       bc = qBlue(c);
0286 
0287   for (int y = plMinY; y <= plMaxY; y++)
0288   {
0289     int px1 = scan[y].scan[0];
0290     int px2 = scan[y].scan[1];    
0291 
0292     if (px1 > px2)
0293     {
0294       qSwap(px1, px2);
0295     }
0296 
0297     if (px1 < 0)
0298     {
0299       px1 = 0;
0300     }
0301 
0302     if (px2 >= m_sx)
0303     {
0304       px2 = m_sx - 1;
0305     }
0306 
0307     quint32 *pDst = bits + (y * dw) + px1;
0308     for (int x = px1; x < px2; x++)
0309     {
0310       QRgb rgbd = *pDst;     
0311 
0312       *pDst = qRgb(LERP(a, qRed(rgbd), rc),
0313                    LERP(a, qGreen(rgbd), gc),
0314                    LERP(a, qBlue(rgbd), bc)
0315                   );     
0316       pDst++;
0317     }
0318   }
0319 }
0320 
0321 void ScanRender::setOpacity(float opacity)
0322 {
0323   m_opacity = opacity;
0324 }
0325 
0326 /////////////////////////////////////////////////////////
0327 void ScanRender::renderPolygon(QImage *dst, QImage *src)
0328 /////////////////////////////////////////////////////////
0329 {
0330   if (bBilinear)
0331     renderPolygonBI(dst, src);
0332   else
0333     renderPolygonNI(dst, src);
0334 }
0335 
0336 void ScanRender::renderPolygon(int interpolation, QPointF *pts, QImage *pDest, QImage *pSrc, QPointF *uv)
0337 {
0338   QPointF Auv = uv[0];
0339   QPointF Buv = uv[1];
0340   QPointF Cuv = uv[2];
0341   QPointF Duv = uv[3];  
0342 
0343   if (interpolation < 2)
0344   {
0345     resetScanPoly(pDest->width(), pDest->height());
0346     scanLine(pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y(), 1, 1, 1, 0);
0347     scanLine(pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(), 1, 0, 0, 0);
0348     scanLine(pts[2].x(), pts[2].y(), pts[3].x(), pts[3].y(), 0, 0, 0, 1);
0349     scanLine(pts[3].x(), pts[3].y(), pts[0].x(), pts[0].y(), 0, 1, 1, 1);
0350     renderPolygon(pDest, pSrc);
0351     return;
0352   }
0353 
0354   QPointF A = pts[0];
0355   QPointF B = pts[1];
0356   QPointF C = pts[2];
0357   QPointF D = pts[3];
0358 
0359   //p->setPen(Qt::green);
0360 
0361   for (int i = 0; i < interpolation; i++)
0362   {
0363     QPointF P1 = A + i * (D - A) / interpolation;
0364     QPointF P1uv = Auv + i * (Duv - Auv) / interpolation;
0365 
0366     QPointF P2 = B + i * (C - B) / interpolation;
0367     QPointF P2uv = Buv + i * (Cuv - Buv) / interpolation;
0368 
0369     QPointF Q1 = A + (i + 1) * (D - A) / interpolation;
0370     QPointF Q1uv = Auv + (i + 1) * (Duv - Auv) / interpolation;
0371 
0372     QPointF Q2 = B + (i + 1) * (C - B) / interpolation;
0373     QPointF Q2uv = Buv + (i + 1) * (Cuv - Buv) / interpolation;
0374 
0375     for (int j = 0; j < interpolation; j++)
0376     {
0377       QPointF A1 = P1 + j * (P2 - P1) / interpolation;
0378       QPointF A1uv = P1uv + j * (P2uv - P1uv) / interpolation;
0379 
0380       QPointF B1 = P1 + (j + 1) * (P2 - P1) / interpolation;
0381       QPointF B1uv = P1uv + (j + 1) * (P2uv - P1uv) / interpolation;
0382 
0383       QPointF C1 = Q1 + (j + 1) * (Q2 - Q1) / interpolation;
0384       QPointF C1uv = Q1uv + (j + 1) * (Q2uv - Q1uv) / interpolation;
0385 
0386       QPointF D1 = Q1 + j * (Q2 - Q1) / interpolation;
0387       QPointF D1uv = Q1uv + j * (Q2uv - Q1uv) / interpolation;
0388 
0389       resetScanPoly(pDest->width(), pDest->height());
0390       scanLine(A1.x(), A1.y(), B1.x(), B1.y(), A1uv.x(), A1uv.y(), B1uv.x(), B1uv.y());
0391       scanLine(B1.x(), B1.y(), C1.x(), C1.y(), B1uv.x(), B1uv.y(), C1uv.x(), C1uv.y());
0392       scanLine(C1.x(), C1.y(), D1.x(), D1.y(), C1uv.x(), C1uv.y(), D1uv.x(), D1uv.y());
0393       scanLine(D1.x(), D1.y(), A1.x(), A1.y(), D1uv.x(), D1uv.y(), A1uv.x(), A1uv.y());
0394       renderPolygon(pDest, pSrc);
0395 
0396       //p->drawLine(A1, B1);
0397       //p->drawLine(B1, C1);
0398       //p->drawLine(C1, D1);
0399       //p->drawLine(D1, A1);
0400     }
0401   }
0402 }
0403 
0404 ///////////////////////////////////////////////////////////
0405 void ScanRender::renderPolygonNI(QImage *dst, QImage *src)
0406 ///////////////////////////////////////////////////////////
0407 {
0408   int w = dst->width();
0409   int sw = src->width();
0410   int sh = src->height();
0411   float tsx = src->width() - 1;
0412   float tsy = src->height() - 1;
0413   const quint32 *bitsSrc = (quint32 *)src->constBits();
0414   quint32 *bitsDst = (quint32 *)dst->bits();
0415   bkScan_t *scan = scLR;
0416   bool bw = src->format() == QImage::Format_Indexed8 || src->format() == QImage::Format_Grayscale8;      
0417 
0418   //#pragma omp parallel for
0419   for (int y = plMinY; y <= plMaxY; y++)
0420   {   
0421     if (scan[y].scan[0] > scan[y].scan[1])
0422     {
0423       qSwap(scan[y].scan[0], scan[y].scan[1]);
0424       qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
0425       qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
0426     }    
0427 
0428     int px1 = scan[y].scan[0];
0429     int px2 = scan[y].scan[1];
0430 
0431     float dx = px2 - px1;
0432     if (dx == 0)
0433       continue;
0434 
0435     float duv[2];
0436     float uv[2];
0437 
0438     duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
0439     duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
0440 
0441     uv[0] = scan[y].uv[0][0];
0442     uv[1] = scan[y].uv[0][1];
0443 
0444     if (px1 < 0)
0445     {
0446       float m = (float)-px1;
0447 
0448       px1 = 0;
0449       uv[0] += duv[0] * m;
0450       uv[1] += duv[1] * m;
0451     }
0452 
0453     if (px2 >= w)
0454       px2 = w - 1;
0455 
0456     uv[0] *= tsx;
0457     uv[1] *= tsy;
0458 
0459     duv[0] *= tsx;
0460     duv[1] *= tsy;
0461 
0462     quint32 *pDst = bitsDst + (y * w) + px1;
0463 
0464     int fuv[2];
0465     int fduv[2];
0466 
0467     fuv[0] = uv[0] * 65536;
0468     fuv[1] = uv[1] * 65536;
0469 
0470     fduv[0] = duv[0] * 65536;    
0471     fduv[1] = duv[1] * 65536;
0472 
0473     fuv[0] = CLAMP(fuv[0], 0, (sw - 1) * 65536.);
0474     fuv[1] = CLAMP(fuv[1], 0, (sh - 1) * 65536.);
0475 
0476     if (bw)
0477     {
0478       for (int x = px1; x < px2; x++)
0479       {
0480         const uchar *pSrc = (uchar *)bitsSrc + (fuv[0] >> 16) + ((fuv[1] >> 16) * sw);
0481         *pDst = qRgb(*pSrc, *pSrc, *pSrc);
0482         pDst++;
0483 
0484         fuv[0] += fduv[0];
0485         fuv[1] += fduv[1];
0486       }      
0487     }
0488     else
0489     {                  
0490       for (int x = px1; x < px2; x++)
0491       {        
0492         int offset = (fuv[0] >> 16) + ((fuv[1] >> 16) * sw);        
0493 
0494         const quint32 *pSrc = bitsSrc + offset;
0495         *pDst = (*pSrc) | (0xFF << 24);
0496 
0497         pDst++;
0498 
0499         fuv[0] += fduv[0];
0500         fuv[1] += fduv[1];
0501       }
0502     }
0503   }
0504 }
0505 
0506 
0507 ///////////////////////////////////////////////////////////
0508 void ScanRender::renderPolygonBI(QImage *dst, QImage *src)
0509 ///////////////////////////////////////////////////////////
0510 {
0511   int w = dst->width();
0512   int sw = src->width();
0513   int sh = src->height();
0514   float tsx = src->width() - 1;
0515   float tsy = src->height() - 1;
0516   const quint32 *bitsSrc = (quint32 *)src->constBits();
0517   const uchar *bitsSrc8 = (uchar *)src->constBits();
0518   quint32 *bitsDst = (quint32 *)dst->bits();
0519   bkScan_t *scan = scLR;
0520   bool bw = src->format() == QImage::Format_Indexed8 || src->format() == QImage::Format_Grayscale8;
0521 
0522 #ifdef PARALLEL_OMP
0523   #pragma omp parallel for
0524 #endif
0525   for (int y = plMinY; y <= plMaxY; y++)
0526   {
0527     if (scan[y].scan[0] > scan[y].scan[1])
0528     {
0529       qSwap(scan[y].scan[0], scan[y].scan[1]);
0530       qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
0531       qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
0532     }
0533 
0534     int px1 = scan[y].scan[0];
0535     int px2 = scan[y].scan[1];
0536 
0537     float dx = px2 - px1;
0538     if (dx == 0)
0539       continue;
0540 
0541     float duv[2];
0542     float uv[2];
0543 
0544     duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
0545     duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
0546 
0547     uv[0] = scan[y].uv[0][0];
0548     uv[1] = scan[y].uv[0][1];
0549 
0550     if (px1 < 0)
0551     {
0552       float m = (float)-px1;
0553 
0554       px1 = 0;
0555       uv[0] += duv[0] * m;
0556       uv[1] += duv[1] * m;
0557     }
0558 
0559     if (px2 >= w)
0560       px2 = w - 1;
0561 
0562     uv[0] *= tsx;
0563     uv[1] *= tsy;
0564 
0565     duv[0] *= tsx;
0566     duv[1] *= tsy;
0567 
0568     int size = sw * sh;
0569 
0570     quint32 *pDst = bitsDst + (y * w) + px1;
0571     if (bw)
0572     {
0573       for (int x = px1; x < px2; x++)
0574       {
0575         float x_diff = uv[0] - static_cast<int>(uv[0]);
0576         float y_diff = uv[1] - static_cast<int>(uv[1]);
0577         float x_1diff = 1 - x_diff;
0578         float y_1diff = 1 - y_diff;
0579 
0580         int index = ((int)uv[0] + ((int)uv[1] * sw));
0581 
0582         uchar a = bitsSrc8[index];
0583         uchar b = bitsSrc8[(index + 1) % size];
0584         uchar c = bitsSrc8[(index + sw) % size];
0585         uchar d = bitsSrc8[(index + sw + 1) % size];
0586 
0587         int val = (a&0xff)*(x_1diff)*(y_1diff) + (b&0xff)*(x_diff)*(y_1diff) +
0588                   (c&0xff)*(y_diff)*(x_1diff)   + (d&0xff)*(x_diff*y_diff);
0589 
0590         *pDst = 0xff000000 |
0591                 ((((int)val)<<16)&0xff0000) |
0592                 ((((int)val)<<8)&0xff00) |
0593                 ((int)val) ;
0594         pDst++;
0595 
0596         uv[0] += duv[0];
0597         uv[1] += duv[1];
0598       }
0599     }
0600     else
0601     {
0602       for (int x = px1; x < px2; x++)
0603       {
0604         float x_diff = uv[0] - static_cast<int>(uv[0]);
0605         float y_diff = uv[1] - static_cast<int>(uv[1]);
0606         float x_1diff = 1 - x_diff;
0607         float y_1diff = 1 - y_diff;
0608 
0609         int index = ((int)uv[0] + ((int)uv[1] * sw));
0610 
0611         quint32 a = bitsSrc[index];
0612         quint32 b = bitsSrc[(index + 1) % size];
0613         quint32 c = bitsSrc[(index + sw) % size];
0614         quint32 d = bitsSrc[(index + sw + 1) % size];
0615 
0616         int qxy1 = (x_1diff * y_1diff) * 65536;
0617         int qxy2 =(x_diff * y_1diff) * 65536;
0618         int qxy = (x_diff * y_diff) * 65536;
0619         int qyx1 = (y_diff * x_1diff) * 65536;
0620 
0621         // blue element
0622         int blue = ((a&0xff)*(qxy1) + (b&0xff)*(qxy2) + (c&0xff)*(qyx1)  + (d&0xff)*(qxy)) >> 16;
0623 
0624         // green element
0625         int green = (((a>>8)&0xff)*(qxy1) + ((b>>8)&0xff)*(qxy2) + ((c>>8)&0xff)*(qyx1)  + ((d>>8)&0xff)*(qxy)) >> 16;
0626 
0627         // red element
0628         int red = (((a>>16)&0xff)*(qxy1) + ((b>>16)&0xff)*(qxy2) +((c>>16)&0xff)*(qyx1)  + ((d>>16)&0xff)*(qxy)) >> 16;
0629 
0630         *pDst = 0xff000000 | (((red)<<16)&0xff0000) | (((green)<<8)&0xff00) | (blue);
0631 
0632         pDst++;
0633 
0634         uv[0] += duv[0];
0635         uv[1] += duv[1];
0636       }
0637     }
0638   }
0639 }
0640 
0641 void ScanRender::renderPolygonAlpha(QImage *dst, QImage *src)
0642 {
0643   if (bBilinear)
0644     renderPolygonAlphaBI(dst, src);
0645   else
0646     renderPolygonAlphaNI(dst, src);
0647 }
0648 
0649 
0650 void ScanRender::renderPolygonAlphaBI(QImage *dst, QImage *src)
0651 {
0652   int w = dst->width();
0653   int sw = src->width();
0654   int sh = src->height();
0655   float tsx = src->width() - 1;
0656   float tsy = src->height() - 1;
0657   const quint32 *bitsSrc = (quint32 *)src->constBits();  
0658   quint32 *bitsDst = (quint32 *)dst->bits();
0659   bkScan_t *scan = scLR;
0660   bool bw = src->format() == QImage::Format_Indexed8;
0661   float opacity = (m_opacity / 65536.) * 0.00390625f;
0662 
0663 #ifdef PARALLEL_OMP
0664   #pragma omp parallel for shared(bitsDst, bitsSrc, scan, tsx, tsy, w, sw)
0665 #endif
0666   for (int y = plMinY; y <= plMaxY; y++)
0667   {
0668     if (scan[y].scan[0] > scan[y].scan[1])
0669     {
0670       qSwap(scan[y].scan[0], scan[y].scan[1]);
0671       qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
0672       qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
0673     }
0674 
0675     int px1 = scan[y].scan[0];
0676     int px2 = scan[y].scan[1];
0677 
0678     float dx = px2 - px1;
0679     if (dx == 0)
0680       continue;
0681 
0682     float duv[2];
0683     float uv[2];
0684 
0685     duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
0686     duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
0687 
0688     uv[0] = scan[y].uv[0][0];
0689     uv[1] = scan[y].uv[0][1];
0690 
0691     if (px1 < 0)
0692     {
0693       float m = (float)-px1;
0694 
0695       px1 = 0;
0696       uv[0] += duv[0] * m;
0697       uv[1] += duv[1] * m;
0698     }
0699 
0700     if (px2 >= w)
0701       px2 = w - 1;
0702 
0703     uv[0] *= tsx;
0704     uv[1] *= tsy;
0705 
0706     duv[0] *= tsx;
0707     duv[1] *= tsy;
0708 
0709     int size = sw * sh;
0710 
0711     quint32 *pDst = bitsDst + (y * w) + px1;
0712     if (bw)
0713     {
0714       /*
0715       for (int x = px1; x < px2; x++)
0716       {
0717         float x_diff = uv[0] - static_cast<int>(uv[0]);
0718         float y_diff = uv[1] - static_cast<int>(uv[1]);
0719         float x_1diff = 1 - x_diff;
0720         float y_1diff = 1 - y_diff;
0721 
0722         int index = ((int)uv[0] + ((int)uv[1] * sw));
0723 
0724         uchar a = bitsSrc8[index];
0725         uchar b = bitsSrc8[(index + 1) % size];
0726         uchar c = bitsSrc8[(index + sw) % size];
0727         uchar d = bitsSrc8[(index + sw + 1) % size];
0728 
0729         int val = (a&0xff)*(x_1diff)*(y_1diff) + (b&0xff)*(x_diff)*(y_1diff) +
0730                   (c&0xff)*(y_diff)*(x_1diff)   + (d&0xff)*(x_diff*y_diff);
0731 
0732 
0733         *pDst = 0xff000000 |
0734                 ((((int)val)<<16)&0xff0000) |
0735                 ((((int)val)<<8)&0xff00) |
0736                 ((int)val) ;
0737         pDst++;
0738 
0739         uv[0] += duv[0];
0740         uv[1] += duv[1];
0741       }
0742       */
0743     }
0744     else
0745     {      
0746       for (int x = px1; x < px2; x++)
0747       {
0748         float x_diff = uv[0] - static_cast<int>(uv[0]);
0749         float y_diff = uv[1] - static_cast<int>(uv[1]);
0750         float x_1diff = 1 - x_diff;
0751         float y_1diff = 1 - y_diff;
0752 
0753         int index = ((int)uv[0] + ((int)uv[1] * sw));
0754 
0755         quint32 a = bitsSrc[index];
0756         quint32 b = bitsSrc[(index + 1) % size];
0757         quint32 c = bitsSrc[(index + sw) % size];
0758         quint32 d = bitsSrc[(index + sw + 1) % size];
0759 
0760         int x1y1 = (x_1diff * y_1diff) * 65536;
0761         int xy = (x_diff * y_diff) * 65536;
0762         int x1y = (y_diff * x_1diff) * 65536;
0763         int xy1 = (x_diff *y_1diff) * 65536;
0764 
0765         float alpha = ((((a>>24)&0xff)*(x1y1) + ((b>>24)&0xff)*(xy1) +
0766                         ((c>>24)&0xff)*(x1y) + ((d>>24)&0xff)*(xy)) * opacity);
0767 
0768         if (alpha > 0.00390625f) // > 1 / 256.
0769         {
0770           // blue element
0771           int blue = ((a&0xff)*(x1y1) + (b&0xff)* (xy1) +
0772                      (c&0xff)*(x1y)  + (d&0xff)*(xy)) >> 16;
0773 
0774           // green element
0775           int green = (((a>>8)&0xff)*(x1y1) + ((b>>8)&0xff)*(xy1) +
0776                       ((c>>8)&0xff)*(x1y)  + ((d>>8)&0xff)*(xy)) >> 16;
0777 
0778           // red element
0779           int red = (((a>>16)&0xff)*(x1y1) + ((b>>16)&0xff)*(xy1) +
0780                     ((c>>16)&0xff)*(x1y)  + ((d>>16)&0xff)*(xy)) >> 16;
0781 
0782           int rd = qRed(*pDst);
0783           int gd = qGreen(*pDst);
0784           int bd = qBlue(*pDst);
0785 
0786           *pDst = qRgb(LERP(alpha, rd,  red), LERP(alpha, gd, green),  LERP(alpha, bd, blue));
0787         }
0788 
0789         pDst++;
0790 
0791         uv[0] += duv[0];
0792         uv[1] += duv[1];
0793       }
0794     }
0795   }
0796 }
0797 
0798 
0799 ////////////////////////////////////////////////////////////////
0800 void ScanRender::renderPolygonAlphaNI(QImage *dst, QImage *src)
0801 ////////////////////////////////////////////////////////////////
0802 {
0803   int w = dst->width();
0804   int sw = src->width();
0805   float tsx = src->width() - 1;
0806   float tsy = src->height() - 1;
0807   const quint32 *bitsSrc = (quint32 *)src->constBits();
0808   quint32 *bitsDst = (quint32 *)dst->bits();
0809   bkScan_t *scan = scLR;
0810   float opacity = 0.00390625f * m_opacity;    
0811 
0812 #ifdef PARALLEL_OMP
0813   #pragma omp parallel for shared(bitsDst, bitsSrc, scan, tsx, tsy, w, sw)
0814 #endif
0815   for (int y = plMinY; y <= plMaxY; y++)
0816   {
0817     if (scan[y].scan[0] > scan[y].scan[1])
0818     {
0819       qSwap(scan[y].scan[0], scan[y].scan[1]);
0820       qSwap(scan[y].uv[0][0], scan[y].uv[1][0]);
0821       qSwap(scan[y].uv[0][1], scan[y].uv[1][1]);
0822     }
0823 
0824     int px1 = scan[y].scan[0];
0825     int px2 = scan[y].scan[1];
0826 
0827     float dx = px2 - px1;
0828     if (dx == 0)
0829       continue;
0830 
0831     float duv[2];
0832     float uv[2];
0833 
0834     duv[0] = (float)(scan[y].uv[1][0] - scan[y].uv[0][0]) / dx;
0835     duv[1] = (float)(scan[y].uv[1][1] - scan[y].uv[0][1]) / dx;
0836 
0837     uv[0] = scan[y].uv[0][0];
0838     uv[1] = scan[y].uv[0][1];
0839 
0840     if (px1 < 0)
0841     {
0842       float m = (float)-px1;
0843 
0844       px1 = 0;
0845       uv[0] += duv[0] * m;
0846       uv[1] += duv[1] * m;
0847     }
0848 
0849     if (px2 >= w)
0850       px2 = w - 1;
0851 
0852     quint32 *pDst = bitsDst + (y * w) + px1;
0853 
0854     uv[0] *= tsx;
0855     uv[1] *= tsy;
0856 
0857     duv[0] *= tsx;
0858     duv[1] *= tsy;
0859 
0860     for (int x = px1; x < px2; x++)
0861     {
0862       const quint32 *pSrc = bitsSrc + ((int)(uv[0])) + ((int)(uv[1]) * sw);
0863       QRgb rgbs = *pSrc;
0864       QRgb rgbd = *pDst;
0865       float a = qAlpha(*pSrc) * opacity;
0866 
0867       if (a > 0.00390625f)
0868       {
0869         *pDst = qRgb(LERP(a, qRed(rgbd), qRed(rgbs)),
0870                      LERP(a, qGreen(rgbd), qGreen(rgbs)),
0871                      LERP(a, qBlue(rgbd), qBlue(rgbs))
0872                      );        
0873       }
0874       pDst++;
0875 
0876       uv[0] += duv[0];
0877       uv[1] += duv[1];
0878     }
0879   }  
0880 }
0881 
0882 #pragma GCC diagnostic pop