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//////////////////////////////
23ScanRender::ScanRender(void)
24//////////////////////////////
25{
26}
27
28/////////////////////////////////////////////////
29void ScanRender::setBilinearInterpolationEnabled(bool enable)
30/////////////////////////////////////////////////
31{
32 bBilinear = enable;
33}
34
35//////////////////////////////////
36bool ScanRender::isBilinearInterpolationEnabled()
37//////////////////////////////////
38{
39 return(bBilinear);
40}
41
42///////////////////////////////////////////////
43void 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//////////////////////////////////////////////////////////
60void 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//////////////////////////////////////////////////////////////////////////////////////////////////
153void 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////////////////////////////////////////////////////////
228void 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/////////////////////////////////////////////////////////////
275void 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
321void ScanRender::setOpacity(float opacity)
322{
323 m_opacity = opacity;
324}
325
326/////////////////////////////////////////////////////////
327void ScanRender::renderPolygon(QImage *dst, QImage *src)
328/////////////////////////////////////////////////////////
329{
330 if (bBilinear)
331 renderPolygonBI(dst, src);
332 else
333 renderPolygonNI(dst, src);
334}
335
336void 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;
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;
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///////////////////////////////////////////////////////////
405void 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///////////////////////////////////////////////////////////
508void 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
641void ScanRender::renderPolygonAlpha(QImage *dst, QImage *src)
642{
643 if (bBilinear)
644 renderPolygonAlphaBI(dst, src);
645 else
646 renderPolygonAlphaNI(dst, src);
647}
648
649
650void 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////////////////////////////////////////////////////////////////
800void 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
PRISONSCANNER_EXPORT ScanResult scan(const QImage &image, Format::BarcodeFormats formats={})
const uchar * constBits() const const
Format format() const const
int height() const const
int width() const const
qreal x() const const
qreal y() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 24 2024 11:49:22 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.