1 /*
2 * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "draw/draw_utils.h"
17
18 #include "draw/draw_triangle.h"
19 #include "engines/gfx/gfx_engine_manager.h"
20 #include "font/ui_font.h"
21 #include "gfx_utils/color.h"
22 #include "gfx_utils/graphic_log.h"
23 #include "gfx_utils/graphic_math.h"
24 #include "graphic_performance.h"
25 #include "securec.h"
26 #include "common/typed_text.h"
27 #ifdef ARM_NEON_OPT
28 #include "graphic_neon_pipeline.h"
29 #include "graphic_neon_utils.h"
30 #endif
31
32 #if ENABLE_ARM_MATH
33 #include "arm_math.h"
34 #endif
35
36 namespace OHOS {
37 // Preprocess operation for draw
38 #define DRAW_UTILS_PREPROCESS(gfxBufferInfo, opa) \
39 if ((opa) == OPA_TRANSPARENT) { \
40 return; \
41 } \
42 uint8_t* screenBuffer = static_cast<uint8_t*>(gfxBufferInfo.virAddr); \
43 if (screenBuffer == nullptr) { \
44 return; \
45 } \
46 ColorMode bufferMode = gfxBufferInfo.mode; \
47 uint8_t bufferPxSize = GetByteSizeByColorMode(bufferMode); \
48 uint16_t screenBufferWidth = gfxBufferInfo.width;
49
50 /* cover mode, src alpha is 255 */
51 #define COLOR_FILL_COVER(d, dm, r2, g2, b2, sm) \
52 if ((dm) == ARGB8888 || (dm) == XRGB8888) { \
53 reinterpret_cast<Color32*>(d)->alpha = OPA_OPAQUE; \
54 if (sm == RGB565) { \
55 reinterpret_cast<Color32*>(d)->red = (r2) << 3; \
56 reinterpret_cast<Color32*>(d)->green = (g2) << 2; \
57 reinterpret_cast<Color32*>(d)->blue = (b2) << 3; \
58 } else { \
59 reinterpret_cast<Color32*>(d)->red = (r2); \
60 reinterpret_cast<Color32*>(d)->green = (g2); \
61 reinterpret_cast<Color32*>(d)->blue = (b2); \
62 } \
63 } else if ((dm) == RGB888) { \
64 if (sm == RGB565) { \
65 reinterpret_cast<Color24*>(d)->red = (r2) << 3; \
66 reinterpret_cast<Color24*>(d)->green = (g2) << 2; \
67 reinterpret_cast<Color24*>(d)->blue = (b2) << 3; \
68 } else { \
69 reinterpret_cast<Color24*>(d)->red = (r2); \
70 reinterpret_cast<Color24*>(d)->green = (g2); \
71 reinterpret_cast<Color24*>(d)->blue = (b2); \
72 } \
73 } else if ((dm) == RGB565) { \
74 if ((sm) == ARGB8888 || (sm) == RGB888 || (sm) == XRGB8888) { \
75 reinterpret_cast<Color16*>(d)->red = (r2) >> 3; \
76 reinterpret_cast<Color16*>(d)->green = (g2) >> 2; \
77 reinterpret_cast<Color16*>(d)->blue = (b2) >> 3; \
78 } else { \
79 reinterpret_cast<Color16*>(d)->red = (r2); \
80 reinterpret_cast<Color16*>(d)->green = (g2); \
81 reinterpret_cast<Color16*>(d)->blue = (b2); \
82 } \
83 } else { \
84 ASSERT(0); \
85 }
86
87 #define COLOR_BLEND_RGBA(r1, g1, b1, a1, r2, g2, b2, a2) \
88 const float Alpha1 = static_cast<float>(a1) / OPA_OPAQUE; \
89 const float Alpha2 = static_cast<float>(a2) / OPA_OPAQUE; \
90 const float Alpha3 = 1 - (1 - Alpha1) * (1 - Alpha2); \
91 (r1) = static_cast<uint8_t>((Alpha2 * (r2) + (1 - Alpha2) * Alpha1 * (r1)) / Alpha3); \
92 (g1) = static_cast<uint8_t>((Alpha2 * (g2) + (1 - Alpha2) * Alpha1 * (g1)) / Alpha3); \
93 (b1) = static_cast<uint8_t>((Alpha2 * (b2) + (1 - Alpha2) * Alpha1 * (b1)) / Alpha3); \
94 (a1) = static_cast<uint8_t>(Alpha3 * OPA_OPAQUE)
95
96 #define COLOR_BLEND_XRGB(r1, g1, b1, a1, r2, g2, b2, a2) \
97 (r1) = (((r2) * (a2)) / OPA_OPAQUE) + (((r1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
98 (g1) = (((g2) * (a2)) / OPA_OPAQUE) + (((g1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
99 (b1) = (((b2) * (a2)) / OPA_OPAQUE) + (((b1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
100 (a1) = static_cast<uint8_t>(OPA_OPAQUE)
101
102 #define COLOR_BLEND_RGB(r1, g1, b1, r2, g2, b2, a2) \
103 (r1) = (((r2) * (a2)) / OPA_OPAQUE) + (((r1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
104 (g1) = (((g2) * (a2)) / OPA_OPAQUE) + (((g1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE); \
105 (b1) = (((b2) * (a2)) / OPA_OPAQUE) + (((b1) * (OPA_OPAQUE - (a2))) / OPA_OPAQUE)
106
107 // 565
108 #define COLOR_FILL_BLEND(d, dm, s, sm, a) \
109 if ((dm) == ARGB8888) { \
110 Color32* p = reinterpret_cast<Color32*>(d); \
111 if ((sm) == ARGB8888 || (sm) == XRGB8888) { \
112 Color32* sTmp = reinterpret_cast<Color32*>(s); \
113 uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE; \
114 COLOR_BLEND_RGBA(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, alpha); \
115 } else if ((sm) == RGB888) { \
116 Color24* sTmp = reinterpret_cast<Color24*>(s); \
117 COLOR_BLEND_RGBA(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, a); \
118 } else if ((sm) == RGB565) { \
119 Color16* sTmp = reinterpret_cast<Color16*>(s); \
120 COLOR_BLEND_RGBA(p->red, p->green, p->blue, p->alpha, (sTmp->red) << 3, (sTmp->green) << 2, \
121 (sTmp->blue) << 3, a); \
122 } \
123 } else if ((dm) == XRGB8888) { \
124 Color32* p = reinterpret_cast<Color32*>(d); \
125 if ((sm) == ARGB8888 || (sm) == XRGB8888) { \
126 Color32* sTmp = reinterpret_cast<Color32*>(s); \
127 uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE; \
128 COLOR_BLEND_XRGB(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, alpha); \
129 } else if ((sm) == RGB888) { \
130 Color24* sTmp = reinterpret_cast<Color24*>(s); \
131 COLOR_BLEND_XRGB(p->red, p->green, p->blue, p->alpha, sTmp->red, sTmp->green, sTmp->blue, a); \
132 } else if ((sm) == RGB565) { \
133 Color16* sTmp = reinterpret_cast<Color16*>(s); \
134 COLOR_BLEND_XRGB(p->red, p->green, p->blue, p->alpha, (sTmp->red) << 3, (sTmp->green) << 2, \
135 (sTmp->blue) << 3, a); \
136 } \
137 } else if ((dm) == RGB888) { \
138 Color24* p = reinterpret_cast<Color24*>(d); \
139 if ((sm) == ARGB8888 || (sm) == XRGB8888) { \
140 Color32* sTmp = reinterpret_cast<Color32*>(s); \
141 uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE; \
142 COLOR_BLEND_RGB(p->red, p->green, p->blue, sTmp->red, sTmp->green, sTmp->blue, alpha); \
143 } else if ((sm) == RGB888) { \
144 Color24* sTmp = reinterpret_cast<Color24*>(s); \
145 COLOR_BLEND_RGB(p->red, p->green, p->blue, sTmp->red, sTmp->green, sTmp->blue, a); \
146 } else if ((sm) == RGB565) { \
147 Color16* sTmp = reinterpret_cast<Color16*>(s); \
148 COLOR_BLEND_RGB(p->red, p->green, p->blue, (sTmp->red) << 3, (sTmp->green) << 2, (sTmp->blue) << 3, a); \
149 } \
150 } else if ((dm) == RGB565) { \
151 Color16* p = reinterpret_cast<Color16*>(d); \
152 if ((sm) == ARGB8888 || (sm) == XRGB8888) { \
153 Color32* sTmp = reinterpret_cast<Color32*>(s); \
154 uint8_t alpha = (sTmp->alpha * (a)) / OPA_OPAQUE; \
155 COLOR_BLEND_RGB(p->red, p->green, p->blue, (sTmp->red) >> 3, (sTmp->green) >> 2, (sTmp->blue) >> 3, \
156 alpha); \
157 } else if ((sm) == RGB888) { \
158 Color24* sTmp = reinterpret_cast<Color24*>(s); \
159 COLOR_BLEND_RGB(p->red, p->green, p->blue, (sTmp->red) >> 3, (sTmp->green) >> 2, (sTmp->blue) >> 3, a); \
160 } else if ((sm) == RGB565) { \
161 Color16* sTmp = reinterpret_cast<Color16*>(s); \
162 COLOR_BLEND_RGB(p->red, p->green, p->blue, sTmp->red, sTmp->green, sTmp->blue, a); \
163 } \
164 } else { \
165 ASSERT(0); \
166 }
167
168 namespace {
169 static constexpr uint8_t OPACITY_STEP_A1 = 255;
170 static constexpr uint8_t OPACITY_STEP_A2 = 85;
171 static constexpr uint8_t OPACITY_STEP_A4 = 17;
172 } // namespace
173
TriangleEdge(int16_t x1,int16_t y1,int16_t x2,int16_t y2)174 TriangleEdge::TriangleEdge(int16_t x1, int16_t y1, int16_t x2, int16_t y2)
175 {
176 #if ENABLE_FIXED_POINT
177 curX = FO_TRANS_INTEGER_TO_FIXED(x1);
178 curY = FO_TRANS_INTEGER_TO_FIXED(y1);
179 du = FO_TRANS_INTEGER_TO_FIXED(x2 - x1);
180 dv = FO_TRANS_INTEGER_TO_FIXED(y2 - y1);
181 #else
182 curX = static_cast<float>(x1);
183 curY = static_cast<float>(y1);
184 du = static_cast<float>(x2 - x1);
185 dv = static_cast<float>(y2 - y1);
186 #endif
187 }
188
~TriangleEdge()189 TriangleEdge::~TriangleEdge() {}
190
GetInstance()191 DrawUtils* DrawUtils::GetInstance()
192 {
193 static DrawUtils instance;
194 return &instance;
195 }
196
DrawColorAreaBySides(BufferInfo & gfxDstBuffer,const Rect & mask,const ColorType & color,OpacityType opa,const EdgeSides & sides) const197 void DrawUtils::DrawColorAreaBySides(BufferInfo& gfxDstBuffer,
198 const Rect& mask,
199 const ColorType& color,
200 OpacityType opa,
201 const EdgeSides& sides) const
202 {
203 Rect area(sides.left, sides.top, sides.right, sides.bottom);
204 DrawUtils::GetInstance()->DrawColorArea(gfxDstBuffer, area, mask, color, opa);
205 }
206
DrawColorArea(BufferInfo & gfxDstBuffer,const Rect & area,const Rect & mask,const ColorType & color,OpacityType opa) const207 void DrawUtils::DrawColorArea(BufferInfo& gfxDstBuffer,
208 const Rect& area,
209 const Rect& mask,
210 const ColorType& color,
211 OpacityType opa) const
212 {
213 if (opa == OPA_TRANSPARENT) {
214 return;
215 }
216
217 Rect maskedArea;
218 if (!maskedArea.Intersect(area, mask)) {
219 return;
220 }
221
222 BaseGfxEngine::GetInstance()->Fill(gfxDstBuffer, maskedArea, color, opa);
223 }
224
GetPxSizeByColorMode(uint8_t colorMode)225 uint8_t DrawUtils::GetPxSizeByColorMode(uint8_t colorMode)
226 {
227 switch (colorMode) {
228 case TSC6:
229 case TSC6A:
230 case ARGB8888:
231 case XRGB8888:
232 return 32; // 32: 32 bit
233 case RGB888:
234 return 24; // 24: 24 bit
235 case RGB565:
236 case ARGB1555:
237 case ARGB4444:
238 return 16; // 16: 16 bit
239 case L1:
240 case A1:
241 return 1; // 1: 1 bit
242 case L2:
243 case A2:
244 return 2; // 2: 2 bit
245 case L4:
246 case A4:
247 return 4; // 4: 4 bit
248 case L8:
249 case A8:
250 return 8; // 8: 8 bit
251 default:
252 return 0;
253 }
254 }
255
GetByteSizeByColorMode(uint8_t colorMode)256 uint8_t DrawUtils::GetByteSizeByColorMode(uint8_t colorMode)
257 {
258 switch (colorMode) {
259 case ARGB8888:
260 case XRGB8888:
261 return 4; // 4: 4 Byte
262 case RGB888:
263 return 3; // 3: 3 Byte
264 case RGB565:
265 case ARGB1555:
266 case ARGB4444:
267 return 2; // 2: 2 Byte
268 default:
269 return 0;
270 }
271 }
272
DrawPixel(BufferInfo & gfxDstBuffer,int16_t x,int16_t y,const Rect & mask,const ColorType & color,OpacityType opa) const273 void DrawUtils::DrawPixel(BufferInfo& gfxDstBuffer,
274 int16_t x,
275 int16_t y,
276 const Rect& mask,
277 const ColorType& color,
278 OpacityType opa) const
279 {
280 if ((x < mask.GetLeft()) || (x > mask.GetRight()) || (y < mask.GetTop()) || (y > mask.GetBottom())) {
281 return;
282 }
283
284 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
285
286 Color32 fillColor;
287 fillColor.full = Color::ColorTo32(color);
288
289 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
290 COLOR_FILL_BLEND(screenBuffer, bufferMode, &fillColor, ARGB8888, opa);
291 }
292
DrawColorLetter(BufferInfo & gfxDstBuffer,const LabelLetterInfo & letterInfo,uint8_t * fontMap,GlyphNode node,uint8_t maxLetterSize) const293 void DrawUtils::DrawColorLetter(BufferInfo& gfxDstBuffer,
294 const LabelLetterInfo& letterInfo,
295 uint8_t* fontMap,
296 GlyphNode node,
297 uint8_t maxLetterSize) const
298 {
299 if (fontMap == nullptr) {
300 return;
301 }
302 UIFont* fontEngine = UIFont::GetInstance();
303 uint16_t letterW = node.cols;
304 uint16_t letterH = node.rows;
305 int16_t posX;
306 int16_t posY;
307 if (letterInfo.baseLine) {
308 posY = letterInfo.pos.y + maxLetterSize - node.top + letterInfo.offsetY;
309 } else {
310 FontHeader head;
311 if (fontEngine->GetFontHeader(head, letterInfo.fontId, letterInfo.fontSize) != 0) {
312 return;
313 }
314 posY = letterInfo.pos.y + head.ascender - letterInfo.offsetY;
315 }
316 if (letterInfo.direct == TEXT_DIRECT_RTL) {
317 /* RTL */
318 posX = letterInfo.pos.x- node.advance + letterInfo.offsetX;
319 } else {
320 /* LTR */
321 posX = letterInfo.pos.x;
322 }
323
324 uint16_t rowStart = (posY >= letterInfo.mask.GetTop()) ? 0 : (letterInfo.mask.GetTop() - posY);
325 uint16_t rowEnd =
326 (posY + letterH <= letterInfo.mask.GetBottom()) ? letterH : (letterInfo.mask.GetBottom() - posY + 1);
327 uint16_t colStart = (posX >= letterInfo.mask.GetLeft()) ? 0 : (letterInfo.mask.GetLeft() - posX);
328 uint16_t colEnd =
329 (posX + letterW <= letterInfo.mask.GetRight()) ? letterW : (letterInfo.mask.GetRight() - posX + 1);
330
331 Rect srcRect(posX, posY, posX + letterW - 1, posY + letterH - 1);
332 Rect subRect(posX + colStart, posY + rowStart, colEnd - 1 + posX, rowEnd - 1 + posY);
333
334 uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(gfxDstBuffer.mode);
335 DrawImage(gfxDstBuffer, srcRect, letterInfo.mask, fontMap, letterInfo.opa, pxSize, ARGB8888);
336 }
337
DrawNormalLetter(BufferInfo & gfxDstBuffer,const LabelLetterInfo & letterInfo,uint8_t * fontMap,GlyphNode node,uint8_t maxLetterSize) const338 void DrawUtils::DrawNormalLetter(BufferInfo& gfxDstBuffer,
339 const LabelLetterInfo& letterInfo,
340 uint8_t* fontMap,
341 GlyphNode node,
342 uint8_t maxLetterSize) const
343 {
344 if (fontMap == nullptr) {
345 return;
346 }
347
348 UIFont* fontEngine = UIFont::GetInstance();
349 uint16_t letterW = node.cols;
350 uint16_t letterH = node.rows;
351 int16_t posX;
352 int16_t posY;
353
354 if (letterInfo.baseLine) {
355 posY = letterInfo.pos.y + maxLetterSize - node.top + letterInfo.offsetY;
356 } else {
357 FontHeader head;
358 if (fontEngine->GetFontHeader(head, letterInfo.fontId, letterInfo.fontSize) != 0) {
359 return;
360 }
361 posY = letterInfo.pos.y + head.ascender - node.top - letterInfo.offsetY;
362 }
363 if (letterInfo.direct == TEXT_DIRECT_RTL) {
364 /* RTL */
365 posX = letterInfo.pos.x - node.advance + node.left + letterInfo.offsetX;
366 } else {
367 /* LTR */
368 posX = letterInfo.pos.x + node.left + letterInfo.offsetX;
369 }
370
371 if (letterInfo.havebackgroundColor) {
372 Rect backgroundRect(posX, letterInfo.mask.GetTop(), posX + letterW + letterInfo.letterSpace_ - 1,
373 letterInfo.mask.GetBottom() - letterInfo.lineSpace_);
374 Style style;
375 style.bgColor_ = letterInfo.backgroundColor;
376 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, backgroundRect,
377 backgroundRect, style, style.bgColor_.alpha);
378 }
379
380 if ((posX + letterW < letterInfo.mask.GetLeft()) || (posX > letterInfo.mask.GetRight()) ||
381 (posY + letterH < letterInfo.mask.GetTop()) || (posY > letterInfo.mask.GetBottom())) {
382 return;
383 }
384
385 uint16_t rowStart = (posY >= letterInfo.mask.GetTop()) ? 0 : (letterInfo.mask.GetTop() - posY);
386 uint16_t rowEnd =
387 (posY + letterH <= letterInfo.mask.GetBottom()) ? letterH : (letterInfo.mask.GetBottom() - posY + 1);
388 uint16_t colStart = (posX >= letterInfo.mask.GetLeft()) ? 0 : (letterInfo.mask.GetLeft() - posX);
389 uint16_t colEnd =
390 (posX + letterW <= letterInfo.mask.GetRight()) ? letterW : (letterInfo.mask.GetRight() - posX + 1);
391
392 Rect srcRect(posX, posY, posX + letterW - 1, posY + letterH - 1);
393 Rect subRect(posX + colStart, posY + rowStart, colEnd - 1 + posX, rowEnd - 1 + posY);
394
395 uint8_t fontWeight = fontEngine->GetFontWeight(letterInfo.fontId);
396 BaseGfxEngine::GetInstance()->DrawLetter(gfxDstBuffer, fontMap, srcRect, subRect,
397 fontWeight, letterInfo.color, letterInfo.opa);
398 }
399
DrawLetter(BufferInfo & gfxDstBuffer,const uint8_t * fontMap,const Rect & fontRect,const Rect & subRect,const uint8_t fontWeight,const ColorType & color,const OpacityType opa) const400 void DrawUtils::DrawLetter(BufferInfo& gfxDstBuffer,
401 const uint8_t* fontMap,
402 const Rect& fontRect,
403 const Rect& subRect,
404 const uint8_t fontWeight,
405 const ColorType& color,
406 const OpacityType opa) const
407 {
408 Color32 fillColor;
409 fillColor.full = Color::ColorTo32(color);
410 uint8_t opacityMask;
411 uint8_t opacityStep = 1;
412 switch (fontWeight) {
413 case FONT_WEIGHT_1:
414 opacityStep = OPACITY_STEP_A1;
415 opacityMask = 0x01;
416 break;
417 case FONT_WEIGHT_2:
418 opacityStep = OPACITY_STEP_A2;
419 opacityMask = 0x03;
420 break;
421 case FONT_WEIGHT_4:
422 opacityStep = OPACITY_STEP_A4;
423 opacityMask = 0x0F;
424 break;
425 case FONT_WEIGHT_8:
426 opacityMask = 0xFF;
427 break;
428 case FONT_WEIGHT_32:
429 opacityMask = 0xFF;
430 break;
431 default:
432 return;
433 }
434
435 uint8_t letterWidthInByte = (fontRect.GetWidth() * fontWeight) >> SHIFT_3;
436 if ((fontRect.GetWidth() * fontWeight) & 0x7) { // 0x7 : less than 1 byte is counted as 1 byte
437 letterWidthInByte++;
438 }
439 int16_t rowStart = subRect.GetY() - fontRect.GetY();
440 int16_t rowEnd = rowStart + subRect.GetHeight();
441 int16_t colStart = subRect.GetX() - fontRect.GetX();
442 int16_t colEnd = colStart + subRect.GetWidth();
443
444 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
445 screenBuffer += ((subRect.GetY() * screenBufferWidth) + subRect.GetX()) * bufferPxSize;
446 fontMap += (rowStart * letterWidthInByte) + ((colStart * fontWeight) >> SHIFT_3);
447
448 uint8_t offsetInFont = (colStart * fontWeight) % FONT_WEIGHT_8;
449 int16_t temp = subRect.GetWidth() * fontWeight - FONT_WEIGHT_8 + offsetInFont;
450 if (temp < 0) {
451 temp = 0;
452 }
453 int16_t validWidthInByte = temp / FONT_WEIGHT_8 + 1;
454 if (temp % FONT_WEIGHT_8 != 0) {
455 validWidthInByte++;
456 }
457 for (int16_t i = rowStart; i < rowEnd; i++) {
458 int16_t col = colStart;
459 uint8_t tempOffset = offsetInFont;
460 uint8_t tempFontByte = (*fontMap++) >> offsetInFont;
461 while (col < colEnd) {
462 while ((tempOffset < FONT_WEIGHT_8) && (col < colEnd)) {
463 uint8_t validOpacity = tempFontByte & opacityMask;
464 if (validOpacity != 0) {
465 validOpacity *= opacityStep;
466 if (opa != OPA_OPAQUE) {
467 validOpacity =
468 static_cast<OpacityType>((static_cast<uint16_t>(validOpacity) * opa) >> FONT_WEIGHT_8);
469 }
470 COLOR_FILL_BLEND(screenBuffer, bufferMode, &fillColor, ARGB8888, validOpacity);
471 }
472 screenBuffer += bufferPxSize;
473 tempFontByte = tempFontByte >> fontWeight;
474 tempOffset += fontWeight;
475 col++;
476 }
477 tempOffset = 0;
478 tempFontByte = *(fontMap++);
479 }
480 fontMap += letterWidthInByte - validWidthInByte - 1;
481 screenBuffer += (screenBufferWidth - (colEnd - colStart)) * bufferPxSize;
482 }
483 }
484
DrawImage(BufferInfo & gfxDstBuffer,const Rect & area,const Rect & mask,const uint8_t * image,OpacityType opa,uint8_t pxBitSize,ColorMode colorMode) const485 void DrawUtils::DrawImage(BufferInfo& gfxDstBuffer,
486 const Rect& area,
487 const Rect& mask,
488 const uint8_t* image,
489 OpacityType opa,
490 uint8_t pxBitSize,
491 ColorMode colorMode) const
492 {
493 if (image == nullptr) {
494 return;
495 }
496 Rect maskedArea;
497 if (!maskedArea.Intersect(area, mask)) {
498 return;
499 }
500 int16_t mapWidth = area.GetWidth();
501 int16_t imageX = maskedArea.GetLeft() - area.GetLeft();
502 int16_t imageY = maskedArea.GetTop() - area.GetTop();
503 uint32_t imageWidthInByte = (static_cast<uint32_t>(mapWidth) * pxBitSize) >> SHIFT_3;
504 if ((mapWidth * pxBitSize) & 0x7) { // 0x7 : less than 1 byte is counted as 1 byte
505 imageWidthInByte++;
506 }
507
508 BufferInfo src;
509 src.rect = {imageX, imageY, static_cast<int16_t>(imageX + maskedArea.GetWidth() - 1),
510 static_cast<int16_t>(imageY + maskedArea.GetHeight() - 1)};
511
512 src.virAddr = static_cast<void*>(const_cast<uint8_t*>(image));
513 src.stride = imageWidthInByte;
514 src.mode = colorMode;
515 src.color = 0;
516
517 Point dstPos = {maskedArea.GetLeft(), maskedArea.GetTop()};
518 BlendOption blendOption;
519 blendOption.opacity = opa;
520 blendOption.mode = BLEND_SRC_OVER;
521 BaseGfxEngine::GetInstance()->Blit(gfxDstBuffer, dstPos, src, maskedArea, blendOption);
522 }
523
FillAreaWithSoftWare(BufferInfo & gfxDstBuffer,const Rect & fillArea,const ColorType & color,const OpacityType & opa) const524 void DrawUtils::FillAreaWithSoftWare(BufferInfo& gfxDstBuffer,
525 const Rect& fillArea,
526 const ColorType& color,
527 const OpacityType& opa) const
528 {
529 if (gfxDstBuffer.virAddr == nullptr) {
530 return;
531 }
532 ColorMode mode = gfxDstBuffer.mode;
533 uint8_t destByteSize = GetByteSizeByColorMode(mode);
534 int16_t destWidth = gfxDstBuffer.width;
535 int32_t halBufferDeltaByteLen = static_cast<int32_t>(destWidth) * destByteSize;
536 int16_t width = fillArea.GetWidth();
537 int16_t height = fillArea.GetHeight();
538 uint8_t* dest = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
539 int32_t offset = static_cast<int32_t>(fillArea.GetTop()) * destWidth + fillArea.GetLeft();
540 dest += offset * destByteSize;
541
542 int32_t dstMaxSize = (gfxDstBuffer.width * gfxDstBuffer.height - offset) * destByteSize;
543 Color32 fillColor;
544 fillColor.full = Color::ColorTo32(color);
545 uint8_t* dstTmp = nullptr;
546
547 if ((fillColor.alpha == OPA_TRANSPARENT) || (opa == OPA_TRANSPARENT)) {
548 return;
549 }
550 /* cover mode */
551 if ((opa == OPA_OPAQUE) && (fillColor.alpha == OPA_OPAQUE)) {
552 for (int16_t col = 0; col < width; ++col) {
553 dstTmp = dest + (col * destByteSize);
554 COLOR_FILL_COVER(dstTmp, mode, fillColor.red, fillColor.green, fillColor.blue, ARGB8888);
555 }
556 uint8_t* memStart = dest;
557 int32_t memSize = static_cast<int32_t>(width) * destByteSize;
558 dest += halBufferDeltaByteLen;
559 dstMaxSize -= halBufferDeltaByteLen;
560 for (int16_t row = 1; row < height; ++row) {
561 #ifdef ARM_NEON_OPT
562 {
563 DEBUG_PERFORMANCE_TRACE("memcpy_neon");
564 NeonMemcpy(dest, dstMaxSize, memStart, memSize);
565 }
566 #else
567 {
568 DEBUG_PERFORMANCE_TRACE("memcpy");
569 if (memcpy_s(dest, dstMaxSize, memStart, memSize) != EOK) {
570 GRAPHIC_LOGE("DrawUtils::FillAreaWithSoftWare memcpy failed!\n");
571 return;
572 }
573 }
574 #endif
575 dest += halBufferDeltaByteLen;
576 dstMaxSize -= halBufferDeltaByteLen;
577 }
578 } else {
579 #ifdef ARM_NEON_OPT
580 {
581 DEBUG_PERFORMANCE_TRACE("FillAreaWithSoftWare_neon");
582 NeonBlendPipeLine pipeLine;
583 pipeLine.Construct(mode, ARGB8888, &fillColor, opa);
584 int16_t step = NEON_STEP_8 * GetByteSizeByColorMode(mode);
585 for (int16_t row = 0; row < height; ++row) {
586 uint8_t* buf = dest;
587 int16_t tmpWidth = width;
588 while (tmpWidth >= NEON_STEP_8) {
589 pipeLine.Invoke(buf);
590 buf += step;
591 tmpWidth -= NEON_STEP_8;
592 }
593 for (int16_t i = 0; i < tmpWidth; ++i) {
594 COLOR_FILL_BLEND(buf, mode, &fillColor, ARGB8888, opa);
595 buf += destByteSize;
596 }
597 dest += halBufferDeltaByteLen;
598 }
599 }
600 #else
601 {
602 DEBUG_PERFORMANCE_TRACE("FillAreaWithSoftWare");
603 for (int16_t row = 0; row < height; row++) {
604 for (int16_t col = 0; col < width; col++) {
605 dstTmp = dest + (col * destByteSize);
606 COLOR_FILL_BLEND(dstTmp, mode, &fillColor, ARGB8888, opa);
607 }
608 dest += destWidth * destByteSize;
609 }
610 }
611 #endif
612 }
613 }
614
615 #ifdef ARM_NEON_OPT
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t cover)616 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
617 uint8_t alpha, uint8_t cover)
618 {
619 NeonBlendPipeLine mNeonBlendPipeLine;
620 mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha, cover);
621 }
622
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha)623 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
624 {
625 NeonBlendPipeLine mNeonBlendPipeLine;
626 mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha);
627 }
628
BlendLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t srcCover)629 void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t srcCover)
630 {
631 NeonBlendPipeLine mNeonBlendPipeLine;
632 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
633 }
634
BlendLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t * srcCovers)635 void DrawUtils::BlendLerpPix(uint8_t* dstColors, uint8_t* srcColors, uint8_t* srcCovers)
636 {
637 NeonBlendPipeLine mNeonBlendPipeLine;
638 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
639 }
640
BlendLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t * covers)641 void DrawUtils::BlendLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
642 uint8_t alpha, uint8_t* covers)
643 {
644 NeonBlendPipeLine mNeonBlendPipeLine;
645 mNeonBlendPipeLine.NeonLerpARGB8888(color, red, green, blue, alpha, covers);
646 }
647
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t cover)648 void DrawUtils::BlendPreLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue,
649 uint8_t alpha, uint8_t cover)
650 {
651 NeonBlendPipeLine mNeonBlendPipeLine;
652 mNeonBlendPipeLine.NeonPrelerpARGB8888(color, red, green, blue, alpha, cover);
653 }
654
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha)655 void DrawUtils::BlendPreLerpPix(uint8_t* color, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
656 {
657 NeonBlendPipeLine mNeonBlendPipeLine;
658 mNeonBlendPipeLine.NeonPrelerpARGB8888(color, red, green, blue, alpha);
659 }
BlendPreLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t srcCover)660 void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t srcCover)
661 {
662 NeonBlendPipeLine mNeonBlendPipeLine;
663 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCover);
664 }
665
BlendPreLerpPix(uint8_t * dstColors,uint8_t * srcColors,uint8_t * srcCovers)666 void DrawUtils::BlendPreLerpPix(uint8_t *dstColors, uint8_t *srcColors, uint8_t *srcCovers)
667 {
668 NeonBlendPipeLine mNeonBlendPipeLine;
669 mNeonBlendPipeLine.NeonLerpARGB8888(dstColors, srcColors, srcCovers);
670 }
671
BlendPreLerpPix(uint8_t * color,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha,uint8_t * covers)672 void DrawUtils::BlendPreLerpPix(uint8_t *color, uint8_t red, uint8_t green, uint8_t blue,
673 uint8_t alpha, uint8_t *covers)
674 {
675 NeonBlendPipeLine mNeonBlendPipeLine;
676 mNeonBlendPipeLine.NeonPreLerpARGB8888(color, red, green, blue, alpha, covers);
677 }
678 #endif
679
BlendWithSoftWare(const uint8_t * src1,const Rect & srcRect,uint32_t srcStride,uint32_t srcLineNumber,ColorMode srcMode,uint32_t color,OpacityType opa,uint8_t * dst,uint32_t destStride,ColorMode destMode,uint32_t x,uint32_t y) const680 void DrawUtils::BlendWithSoftWare(const uint8_t* src1,
681 const Rect& srcRect,
682 uint32_t srcStride,
683 uint32_t srcLineNumber,
684 ColorMode srcMode,
685 uint32_t color,
686 OpacityType opa,
687 uint8_t* dst,
688 uint32_t destStride,
689 ColorMode destMode,
690 uint32_t x,
691 uint32_t y) const
692 {
693 if ((dst == nullptr) || (src1 == nullptr)) {
694 return;
695 }
696 uint8_t destByteSize = GetByteSizeByColorMode(destMode);
697 uint8_t srcByteSize = GetByteSizeByColorMode(srcMode);
698
699 uint8_t* dest = dst + destStride * y;
700 dest += destByteSize * x;
701
702 uint8_t pxByteSize = GetPxSizeByColorMode(srcMode) >> 3; // 3 : right shift 3 bits
703 uint8_t* src = const_cast<uint8_t*>(src1) + srcStride * srcRect.GetY() + pxByteSize * srcRect.GetX();
704 uint32_t width = srcRect.GetWidth();
705 uint32_t height = srcRect.GetHeight();
706 #ifdef ARM_NEON_OPT
707 {
708 DEBUG_PERFORMANCE_TRACE("BlendWithSoftWare_neon");
709 NeonBlendPipeLine pipeLine;
710 pipeLine.Construct(destMode, srcMode);
711 int16_t dstStep = NEON_STEP_8 * GetByteSizeByColorMode(destMode);
712 int16_t srcStep = NEON_STEP_8 * GetByteSizeByColorMode(srcMode);
713 for (uint32_t row = 0; row < height; ++row) {
714 uint8_t* dstBuf = dest;
715 uint8_t* srcBuf = const_cast<uint8_t*>(src);
716 int16_t tmpWidth = width;
717 while (tmpWidth >= NEON_STEP_8) {
718 pipeLine.Invoke(dstBuf, srcBuf, opa);
719 dstBuf += dstStep;
720 srcBuf += srcStep;
721 tmpWidth -= NEON_STEP_8;
722 }
723 for (int16_t i = 0; i < tmpWidth; ++i) {
724 COLOR_FILL_BLEND(dstBuf, destMode, srcBuf, srcMode, opa);
725 dstBuf += destByteSize;
726 srcBuf += srcByteSize;
727 }
728 dest += destStride;
729 src += srcStride;
730 }
731 }
732 #else
733 {
734 DEBUG_PERFORMANCE_TRACE("BlendWithSoftWare");
735 for (uint32_t row = 0; row < height; ++row) {
736 uint8_t* destTmp = dest;
737 uint8_t* srcTmp = const_cast<uint8_t*>(src);
738 for (uint32_t col = 0; col < width; ++col) {
739 COLOR_FILL_BLEND(destTmp, destMode, srcTmp, srcMode, opa);
740 destTmp += destByteSize;
741 srcTmp += srcByteSize;
742 }
743 dest += destStride;
744 src += srcStride;
745 }
746 }
747 #endif
748 }
749
GetXAxisErrForJunctionLine(bool ignoreJunctionPoint,bool isRightPart,int16_t & xMinErr,int16_t & xMaxErr)750 void DrawUtils::GetXAxisErrForJunctionLine(bool ignoreJunctionPoint,
751 bool isRightPart,
752 int16_t& xMinErr,
753 int16_t& xMaxErr)
754 {
755 xMinErr = 0;
756 xMaxErr = 0;
757 if (ignoreJunctionPoint) {
758 if (isRightPart) {
759 xMinErr = 1;
760 } else {
761 xMaxErr = -1;
762 }
763 }
764 }
765
GetTransformInitState(const TransformMap & transMap,const Point & position,const Rect & trans,TransformInitState & init)766 void DrawUtils::GetTransformInitState(const TransformMap& transMap,
767 const Point& position,
768 const Rect& trans,
769 TransformInitState& init)
770 {
771 int16_t x = trans.GetLeft();
772 int16_t y = trans.GetTop();
773 #if ENABLE_FIXED_POINT
774 init.duHorizon = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[0]);
775 init.dvHorizon = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[1]);
776 init.duVertical = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[3]); // 3:RSxy
777 init.dvVertical = FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[4]); // 4:RSyy
778 init.verticalU = (x - position.x) * init.duHorizon + (y - position.y) * init.duVertical +
779 FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[6]); // 6:TRSx
780 init.verticalV = (x - position.x) * init.dvHorizon + (y - position.y) * init.dvVertical +
781 FO_TRANS_FLOAT_TO_FIXED(transMap.invMatrix_.GetData()[7]); // 7:TRSy
782 #else
783 init.duHorizon = transMap.invMatrix_.GetData()[0];
784 init.dvHorizon = transMap.invMatrix_.GetData()[1];
785 init.duVertical = transMap.invMatrix_.GetData()[3]; // 3:RSxy
786 init.dvVertical = transMap.invMatrix_.GetData()[4]; // 4:RSyy
787 init.verticalU = (x - position.x) * init.duHorizon + (y - position.y) * init.duVertical +
788 transMap.invMatrix_.GetData()[6]; // 6:TRSx
789 init.verticalV = (x - position.x) * init.dvHorizon + (y - position.y) * init.dvVertical +
790 transMap.invMatrix_.GetData()[7]; // 7:TRSy
791 #endif
792 }
793
StepToNextLine(TriangleEdge & edge1,TriangleEdge & edge2)794 inline void DrawUtils::StepToNextLine(TriangleEdge& edge1, TriangleEdge& edge2)
795 {
796 #if ENABLE_FIXED_POINT
797 edge1.curY += FIXED_NUM_1;
798 edge2.curY += FIXED_NUM_1;
799 edge1.curX += FO_DIV(edge1.du, edge1.dv);
800 edge2.curX += FO_DIV(edge2.du, edge2.dv);
801 #else
802 edge1.curY++;
803 edge2.curY++;
804 edge1.curX += edge1.du / edge1.dv;
805 edge2.curX += edge2.du / edge2.dv;
806 #endif
807 }
808
DrawTriangleAlphaBilinear(const TriangleScanInfo & in,const ColorMode bufferMode)809 void DrawUtils::DrawTriangleAlphaBilinear(const TriangleScanInfo& in, const ColorMode bufferMode)
810 {
811 int16_t maskLeft = in.mask.GetLeft();
812 int16_t maskRight = in.mask.GetRight();
813 for (int16_t y = in.yMin; y <= in.yMax; y++) {
814 #if ENABLE_FIXED_POINT
815 int16_t tempV = FO_TO_INTEGER(in.edge1.curX);
816 int16_t xMin = MATH_MAX(tempV, maskLeft);
817 tempV = FO_TO_INTEGER(in.edge2.curX);
818 int16_t xMax = MATH_MIN(tempV, maskRight);
819 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
820 #else
821 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX), maskLeft);
822 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX), maskRight);
823 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
824 #endif
825 in.init.verticalU += in.init.duHorizon * diffX;
826 in.init.verticalV += in.init.dvHorizon * diffX;
827 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
828
829 #if ENABLE_FIXED_POINT
830 // parameters below are Q15 fixed-point number
831 int64_t u = in.init.verticalU;
832 int64_t v = in.init.verticalV;
833 // parameters above are Q15 fixed-point number
834 #else
835 float u = in.init.verticalU;
836 float v = in.init.verticalV;
837 #endif
838 for (int16_t x = xMin; x <= xMax; x++) {
839 #if ENABLE_FIXED_POINT
840 int16_t intU = FO_TO_INTEGER(u);
841 int16_t intV = FO_TO_INTEGER(v);
842 if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
843 int16_t intUPlus1 = intU + 1;
844 int16_t intVPlus1 = intV + 1;
845 #else
846 const int16_t intU = static_cast<int16_t>(u);
847 const int16_t intV = static_cast<int16_t>(v);
848 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
849 const int16_t intUPlus1 = intU + 1;
850 const int16_t intVPlus1 = intV + 1;
851 #endif
852 OpacityType p1 = GetPxAlphaForAlphaImg(in.info, {intU, intV});
853 OpacityType p2 = GetPxAlphaForAlphaImg(in.info, {intUPlus1, intV});
854 OpacityType p3 = GetPxAlphaForAlphaImg(in.info, {intU, intVPlus1});
855 OpacityType p4 = GetPxAlphaForAlphaImg(in.info, {intUPlus1, intVPlus1});
856 #if ENABLE_FIXED_POINT
857 // parameters below are Q15 fixed-point number
858 int64_t decU = FO_DECIMAL(u);
859 int64_t decV = FO_DECIMAL(v);
860 int64_t decUMinus1 = FIXED_NUM_1 - decU;
861 int64_t decVMinus1 = FIXED_NUM_1 - decV;
862 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
863 int64_t w2 = FO_MUL(decU, decVMinus1);
864 int64_t w3 = FO_MUL(decUMinus1, decV);
865 int64_t w4 = FO_MUL(decU, decV);
866 // parameters above are Q15 fixed-point number
867 #else
868 const float decU = u - intU;
869 const float decV = v - intV;
870 const float decUMinus1 = 1.0f - decU;
871 const float decVMinus1 = 1.0f - decV;
872
873 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
874 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
875 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
876 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
877 #endif
878 #if ENABLE_ARM_MATH
879 const int64_t outA = __SMUAD(p1, w1) + __SMUAD(p2, w2) + __SMUAD(p3, w3) + __SMUAD(p4, w4);
880 #else
881 const int64_t outA = p1 * w1 + p2 * w2 + p3 * w3 + p4 * w4;
882 #endif
883 Color32 result;
884 result.full = Color::ColorTo32(in.color);
885 #if ENABLE_FIXED_POINT
886 result.alpha = FO_TO_INTEGER(outA);
887 #else
888 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
889 #endif
890 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
891 }
892 u += in.init.duHorizon;
893 v += in.init.dvHorizon;
894 screenBuffer += in.bufferPxSize;
895 }
896 StepToNextLine(in.edge1, in.edge2);
897 in.init.verticalU += in.init.duVertical;
898 in.init.verticalV += in.init.dvVertical;
899 #if ENABLE_FIXED_POINT
900 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
901 #else
902 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
903 #endif
904 in.init.verticalU += in.init.duHorizon * deltaX;
905 in.init.verticalV += in.init.dvHorizon * deltaX;
906 }
907 }
908
909 void DrawUtils::DrawTriangleTrueColorBilinear565(const TriangleScanInfo& in, const ColorMode bufferMode)
910 {
911 int16_t maskLeft = in.mask.GetLeft();
912 int16_t maskRight = in.mask.GetRight();
913 int16_t xMinErr = 0;
914 int16_t xMaxErr = 0;
915 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
916 for (int16_t y = in.yMin; y <= in.yMax; y++) {
917 #if ENABLE_FIXED_POINT
918 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
919 int16_t xMin = MATH_MAX(tempV, maskLeft);
920 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
921 int16_t xMax = MATH_MIN(tempV, maskRight);
922 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
923 #else
924 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
925 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
926 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
927 #endif
928 in.init.verticalU += in.init.duHorizon * diffX;
929 in.init.verticalV += in.init.dvHorizon * diffX;
930 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
931 #if ENABLE_FIXED_POINT
932 // parameters below are Q15 fixed-point number
933 int64_t u = in.init.verticalU;
934 int64_t v = in.init.verticalV;
935 // parameters above are Q15 fixed-point number
936 #else
937 float u = in.init.verticalU;
938 float v = in.init.verticalV;
939 #endif
940 for (int16_t x = xMin; x <= xMax; x++) {
941 #if ENABLE_FIXED_POINT
942 int16_t intU = FO_TO_INTEGER(u);
943 int16_t intV = FO_TO_INTEGER(v);
944 if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
945 #else
946 const int16_t intU = static_cast<int16_t>(u);
947 const int16_t intV = static_cast<int16_t>(v);
948 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
949 #endif
950 #if ENABLE_ARM_MATH
951 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
952 uint32_t val2 = __SMUAD(intU, in.pixelSize);
953 uint32_t px1 = val1 + val2;
954 #else
955 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
956 #endif
957 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
958 const Color16 p1 = *(reinterpret_cast<Color16*>(&imgHead[px1]));
959 const Color16 p2 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.pixelSize]));
960 const Color16 p3 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.srcLineWidth]));
961 const Color16 p4 = *(reinterpret_cast<Color16*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
962 #if ENABLE_FIXED_POINT
963 // parameters below are Q15 fixed-point number
964 int64_t decU = FO_DECIMAL(u);
965 int64_t decV = FO_DECIMAL(v);
966 int64_t decUMinus1 = FIXED_NUM_1 - decU;
967 int64_t decVMinus1 = FIXED_NUM_1 - decV;
968 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
969 int64_t w2 = FO_MUL(decU, decVMinus1);
970 int64_t w3 = FO_MUL(decUMinus1, decV);
971 int64_t w4 = FO_MUL(decU, decV);
972 // parameters above are Q15 fixed-point number
973 #else
974 const float decU = u - intU;
975 const float decV = v - intV;
976 const float decUMinus1 = 1 - decU;
977 const float decVMinus1 = 1 - decV;
978 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
979 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
980 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
981 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
982 #endif
983 #if ENABLE_ARM_MATH
984 const int64_t outR =
985 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
986 const int64_t outG =
987 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
988 const int64_t outB =
989 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
990 #else
991 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
992 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
993 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
994 #endif
995
996 Color16 result;
997 #if ENABLE_FIXED_POINT
998 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
999 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1000 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1001 #else
1002 result.red = static_cast<uint8_t>(outR >> 5); // 5:shift 5 bit right
1003 result.green = static_cast<uint8_t>(outG >> 6); // 6:shift 6 bit right
1004 result.blue = static_cast<uint8_t>(outB >> 5); // 5:shift 5 bit right
1005 #endif
1006 if (in.opaScale == OPA_OPAQUE) {
1007 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, RGB565);
1008 } else {
1009 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, RGB565, in.opaScale);
1010 }
1011 }
1012 u += in.init.duHorizon;
1013 v += in.init.dvHorizon;
1014 screenBuffer += in.bufferPxSize;
1015 }
1016 StepToNextLine(in.edge1, in.edge2);
1017 in.init.verticalU += in.init.duVertical;
1018 in.init.verticalV += in.init.dvVertical;
1019 #if ENABLE_FIXED_POINT
1020 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1021 #else
1022 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1023 #endif
1024 in.init.verticalU += in.init.duHorizon * deltaX;
1025 in.init.verticalV += in.init.dvHorizon * deltaX;
1026 }
1027 }
1028
1029 void DrawUtils::DrawTriangleTrueColorBilinear888(const TriangleScanInfo& in, const ColorMode bufferMode)
1030 {
1031 int16_t maskLeft = in.mask.GetLeft();
1032 int16_t maskRight = in.mask.GetRight();
1033 int16_t xMinErr = 0;
1034 int16_t xMaxErr = 0;
1035 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1036 for (int16_t y = in.yMin; y <= in.yMax; y++) {
1037 #if ENABLE_FIXED_POINT
1038 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1039 int16_t xMin = MATH_MAX(tempV, maskLeft);
1040 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1041 int16_t xMax = MATH_MIN(tempV, maskRight);
1042 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1043 #else
1044 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1045 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1046 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1047 #endif
1048 in.init.verticalU += in.init.duHorizon * diffX;
1049 in.init.verticalV += in.init.dvHorizon * diffX;
1050 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1051 #if ENABLE_FIXED_POINT
1052 // parameters below are Q15 fixed-point number
1053 int64_t u = in.init.verticalU;
1054 int64_t v = in.init.verticalV;
1055 // parameters above are Q15 fixed-point number
1056 #else
1057 float u = in.init.verticalU;
1058 float v = in.init.verticalV;
1059 #endif
1060 for (int16_t x = xMin; x <= xMax; x++) {
1061 #if ENABLE_FIXED_POINT
1062 int16_t intU = FO_TO_INTEGER(u);
1063 int16_t intV = FO_TO_INTEGER(v);
1064 #else
1065 const int16_t intU = static_cast<int16_t>(u);
1066 const int16_t intV = static_cast<int16_t>(v);
1067 #endif
1068 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1069 #if ENABLE_ARM_MATH
1070 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1071 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1072 uint32_t px1 = val1 + val2;
1073 #else
1074 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1075 #endif
1076 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1077 const Color24 p1 = *(reinterpret_cast<Color24*>(&imgHead[px1]));
1078 const Color24 p2 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.pixelSize]));
1079 const Color24 p3 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.srcLineWidth]));
1080 const Color24 p4 = *(reinterpret_cast<Color24*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1081 #if ENABLE_FIXED_POINT
1082 // parameters below are Q15 fixed-point number
1083 int64_t decU = FO_DECIMAL(u);
1084 int64_t decV = FO_DECIMAL(v);
1085 int64_t decUMinus1 = FIXED_NUM_1 - decU;
1086 int64_t decVMinus1 = FIXED_NUM_1 - decV;
1087 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1088 int64_t w2 = FO_MUL(decU, decVMinus1);
1089 int64_t w3 = FO_MUL(decUMinus1, decV);
1090 int64_t w4 = FO_MUL(decU, decV);
1091 // parameters above are Q15 fixed-point number
1092 #else
1093 const float decU = u - intU;
1094 const float decV = v - intV;
1095 const float decUMinus1 = 1 - decU;
1096 const float decVMinus1 = 1 - decV;
1097 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1098 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
1099 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
1100 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
1101 #endif
1102
1103 #if ENABLE_ARM_MATH
1104 const int64_t outR =
1105 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1106 const int64_t outG =
1107 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1108 const int64_t outB =
1109 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1110 #else
1111 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1112 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1113 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1114 #endif
1115
1116 Color24 result;
1117 #if ENABLE_FIXED_POINT
1118 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1119 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1120 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1121 #else
1122 result.red = static_cast<uint8_t>(outR >> 8); // 8:shift 8 bit right
1123 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1124 result.blue = static_cast<uint8_t>(outB >> 8); // 8:shift 8 bit right
1125 #endif
1126 if (in.opaScale == OPA_OPAQUE) {
1127 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, RGB888);
1128 } else {
1129 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, RGB888, in.opaScale);
1130 }
1131 }
1132 u += in.init.duHorizon;
1133 v += in.init.dvHorizon;
1134 screenBuffer += in.bufferPxSize;
1135 }
1136 StepToNextLine(in.edge1, in.edge2);
1137 in.init.verticalU += in.init.duVertical;
1138 in.init.verticalV += in.init.dvVertical;
1139 #if ENABLE_FIXED_POINT
1140 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1141 #else
1142 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1143 #endif
1144 in.init.verticalU += in.init.duHorizon * deltaX;
1145 in.init.verticalV += in.init.dvHorizon * deltaX;
1146 }
1147 }
1148
1149 #if !ENABLE_FIXED_POINT
1150 static void DrawTriangleTrueColorBilinear8888Inner(const TriangleScanInfo& in,
1151 uint8_t* screenBuffer,
1152 int16_t len,
1153 const ColorMode bufferMode,
1154 float u,
1155 float v)
1156 {
1157 for (int16_t x = 0; x < len; ++x) {
1158 const int16_t intU = static_cast<int16_t>(u);
1159 const int16_t intV = static_cast<int16_t>(v);
1160 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1161 #if ENABLE_ARM_MATH
1162 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1163 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1164 uint32_t px1 = val1 + val2;
1165 #else
1166 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1167 #endif
1168 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1169 const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1170 const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1171 const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1172 const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1173
1174 const float decU = u - intU;
1175 const float decV = v - intV;
1176 const float decUMinus1 = 1 - decU;
1177 const float decVMinus1 = 1 - decV;
1178
1179 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1180 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
1181 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
1182 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f); // 256:shift 8 bit left
1183
1184 #if ENABLE_ARM_MATH
1185 const int32_t outR = __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1186 const int32_t outG =
1187 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1188 const int32_t outB =
1189 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1190 const int32_t outA =
1191 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1192 #else
1193 const int32_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1194 const int32_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1195 const int32_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1196 const int32_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1197 #endif
1198
1199 Color32 result;
1200 result.red = static_cast<uint8_t>(outR >> 8); // 8:shift 8 bit right
1201 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1202 result.blue = static_cast<uint8_t>(outB >> 8); // 8:shift 8 bit right
1203 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
1204 if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1205 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1206 } else {
1207 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1208 }
1209 }
1210 u += in.init.duHorizon;
1211 v += in.init.dvHorizon;
1212 screenBuffer += in.bufferPxSize;
1213 }
1214 }
1215 #endif
1216
1217 #if defined(ENABLE_FIXED_POINT) && ENABLE_FIXED_POINT
1218 static void DrawFixedTriangleTrueColorBilinear8888Inner(const TriangleScanInfo& in,
1219 uint8_t* screenBuffer,
1220 int16_t len,
1221 const ColorMode bufferMode,
1222 int64_t u,
1223 int64_t v)
1224 {
1225 for (int16_t x = 0; x < len; ++x) {
1226 int16_t intU = FO_TO_INTEGER(u);
1227 int16_t intV = FO_TO_INTEGER(v);
1228 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1229 #if ENABLE_ARM_MATH
1230 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1231 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1232 uint32_t px1 = val1 + val2;
1233 #else
1234 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1235 #endif
1236 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1237 const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1238 const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1239 const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1240 const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1241
1242 // parameters below are Q15 fixed-point number
1243 int64_t decU = FO_DECIMAL(u);
1244 int64_t decV = FO_DECIMAL(v);
1245 int64_t decUMinus1 = FIXED_NUM_1 - decU;
1246 int64_t decVMinus1 = FIXED_NUM_1 - decV;
1247 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1248 int64_t w2 = FO_MUL(decU, decVMinus1);
1249 int64_t w3 = FO_MUL(decUMinus1, decV);
1250 int64_t w4 = FO_MUL(decU, decV);
1251 // parameters above are Q15 fixed-point number
1252
1253 #if ENABLE_ARM_MATH
1254 const int64_t outR = __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1255 const int64_t outG =
1256 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1257 const int64_t outB =
1258 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1259 const int64_t outA =
1260 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1261 #else
1262 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1263 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1264 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1265 const int64_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1266 #endif
1267
1268 Color32 result;
1269 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1270 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1271 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1272 result.alpha = static_cast<uint8_t>(outA >> FIXED_Q_NUM);
1273 if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1274 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1275 } else {
1276 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1277 }
1278 }
1279 u += in.init.duHorizon;
1280 v += in.init.dvHorizon;
1281 screenBuffer += in.bufferPxSize;
1282 }
1283 }
1284 #endif
1285
1286 #ifdef ARM_NEON_OPT
1287 static void DrawTriangleTrueColorBilinear8888InnerNeon(const TriangleScanInfo& in,
1288 uint8_t* screenBuffer,
1289 int16_t len,
1290 float u,
1291 float v,
1292 NeonBlendPipeLine& pipeLine,
1293 const ColorMode bufferMode)
1294 {
1295 ColorType arrayp1[NEON_STEP_8] = {};
1296 ColorType arrayp2[NEON_STEP_8] = {};
1297 ColorType arrayp3[NEON_STEP_8] = {};
1298 ColorType arrayp4[NEON_STEP_8] = {};
1299 float arrayU[NEON_STEP_8] = {0};
1300 float arrayV[NEON_STEP_8] = {0};
1301 int32_t arrayPx1[NEON_STEP_8] = {0};
1302 int16_t step = in.bufferPxSize * NEON_STEP_8;
1303 #if ENABLE_FIXED_POINT
1304 float duHorizon = static_cast<float>(in.init.duHorizon) / FIXED_NUM_1;
1305 float dvHorizon = static_cast<float>(in.init.dvHorizon) / FIXED_NUM_1;
1306 #endif
1307 while (len >= NEON_STEP_8) {
1308 for (uint32_t i = 0; i < NEON_STEP_8; ++i) {
1309 arrayU[i] = u;
1310 arrayV[i] = v;
1311 #if ENABLE_FIXED_POINT
1312 u += duHorizon;
1313 v += dvHorizon;
1314 #else
1315 u += in.init.duHorizon;
1316 v += in.init.dvHorizon;
1317 #endif
1318 }
1319 // Monotonically increasing or decreasing, so only judge the beginning and end.
1320 if ((arrayU[0] >= 0) && (arrayU[0] < in.info.header.width - 1) && (arrayV[0] >= 0) &&
1321 (arrayV[0] < in.info.header.height - 1) && (arrayU[NEON_STEP_8 - 1] >= 0) &&
1322 (arrayU[NEON_STEP_8 - 1] < in.info.header.width - 1) && (arrayV[NEON_STEP_8 - 1] >= 0) &&
1323 (arrayV[NEON_STEP_8 - 1] < in.info.header.height - 1)) {
1324 // Process the lower half of arrayU and arrayV
1325 float32x4_t vU = vld1q_f32(arrayU);
1326 float32x4_t vV = vld1q_f32(arrayV);
1327 int32x4_t vIntU = vcvtq_s32_f32(vU);
1328 int32x4_t vIntV = vcvtq_s32_f32(vV);
1329 int32x4_t vPx1 =
1330 vaddq_s32(vmulq_s32(vIntV, vdupq_n_s32(in.srcLineWidth)), vmulq_s32(vIntU, vdupq_n_s32(in.pixelSize)));
1331 vst1q_s32(arrayPx1, vPx1);
1332 float32x4_t vDecU = vsubq_f32(vU, vcvtq_f32_s32(vIntU));
1333 float32x4_t vDecV = vsubq_f32(vV, vcvtq_f32_s32(vIntV));
1334 float32x4_t vDecUMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecU);
1335 float32x4_t vDecVMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecV);
1336 // 256:shift 8 bit left
1337 uint32x4_t vLowW1 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecVMinus1), vdupq_n_f32(256.0)));
1338 uint32x4_t vLowW2 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecVMinus1), vdupq_n_f32(256.0)));
1339 uint32x4_t vLowW3 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecV), vdupq_n_f32(256.0)));
1340 uint32x4_t vLowW4 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecV), vdupq_n_f32(256.0)));
1341 // Process the higher half of arrayU and arrayV
1342 vU = vld1q_f32(arrayU + NEON_STEP_4);
1343 vV = vld1q_f32(arrayV + NEON_STEP_4);
1344 vIntU = vcvtq_s32_f32(vU);
1345 vIntV = vcvtq_s32_f32(vV);
1346 vPx1 =
1347 vaddq_s32(vmulq_s32(vIntV, vdupq_n_s32(in.srcLineWidth)), vmulq_s32(vIntU, vdupq_n_s32(in.pixelSize)));
1348 vst1q_s32(arrayPx1 + NEON_STEP_4, vPx1);
1349 vDecU = vsubq_f32(vU, vcvtq_f32_s32(vIntU));
1350 vDecV = vsubq_f32(vV, vcvtq_f32_s32(vIntV));
1351 vDecUMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecU);
1352 vDecVMinus1 = vsubq_f32(vdupq_n_f32(1.0), vDecV);
1353 // 256:shift 8 bit left
1354 uint32x4_t vHighW1 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecVMinus1), vdupq_n_f32(256.0)));
1355 uint32x4_t vHighW2 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecVMinus1), vdupq_n_f32(256.0)));
1356 uint32x4_t vHighW3 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecUMinus1, vDecV), vdupq_n_f32(256.0)));
1357 uint32x4_t vHighW4 = vcvtq_u32_f32(vmulq_f32(vmulq_f32(vDecU, vDecV), vdupq_n_f32(256.0)));
1358
1359 // joins two uint32x4_t vectors into a uint16x8_t vector
1360 uint16x8_t vW1 = vcombine_u16(vmovn_u32(vLowW1), vmovn_u32(vHighW1));
1361 uint16x8_t vW2 = vcombine_u16(vmovn_u32(vLowW2), vmovn_u32(vHighW2));
1362 uint16x8_t vW3 = vcombine_u16(vmovn_u32(vLowW3), vmovn_u32(vHighW3));
1363 uint16x8_t vW4 = vcombine_u16(vmovn_u32(vLowW4), vmovn_u32(vHighW4));
1364
1365 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1366 for (uint32_t i = 0; i < NEON_STEP_8; ++i) {
1367 int32_t px1 = arrayPx1[i];
1368 arrayp1[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1369 arrayp2[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1370 arrayp3[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1371 arrayp4[i] = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1372 }
1373
1374 uint8x8x4_t v4p1 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp1));
1375 uint8x8x4_t v4p2 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp2));
1376 uint8x8x4_t v4p3 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp3));
1377 uint8x8x4_t v4p4 = vld4_u8(reinterpret_cast<uint8_t*>(arrayp4));
1378 uint8x8_t vOutB =
1379 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_B]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_B]), vW2) +
1380 vmulq_u16(vmovl_u8(v4p3.val[NEON_B]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_B]), vW4),
1381 8); // 8:shift 8 bit right
1382 uint8x8_t vOutG =
1383 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_G]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_G]), vW2) +
1384 vmulq_u16(vmovl_u8(v4p3.val[NEON_G]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_G]), vW4),
1385 8); // 8:shift 8 bit right
1386 uint8x8_t vOutR =
1387 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_R]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_R]), vW2) +
1388 vmulq_u16(vmovl_u8(v4p3.val[NEON_R]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_R]), vW4),
1389 8); // 8:shift 8 bit right
1390 uint8x8_t vOutA =
1391 vshrn_n_u16(vmulq_u16(vmovl_u8(v4p1.val[NEON_A]), vW1) + vmulq_u16(vmovl_u8(v4p2.val[NEON_A]), vW2) +
1392 vmulq_u16(vmovl_u8(v4p3.val[NEON_A]), vW3) + vmulq_u16(vmovl_u8(v4p4.val[NEON_A]), vW4),
1393 8); // 8:shift 8 bit right
1394 vOutA = NeonMulDiv255(vdup_n_u8(in.opaScale), vOutA);
1395 pipeLine.Invoke(screenBuffer, vOutR, vOutG, vOutB, vOutA);
1396 } else {
1397 #if ENABLE_FIXED_POINT
1398 int64_t fixedU = FO_TRANS_FLOAT_TO_FIXED(arrayU[0]);
1399 int64_t fixedV = FO_TRANS_FLOAT_TO_FIXED(arrayV[0]);
1400 DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, NEON_STEP_8, bufferMode, fixedU, fixedV);
1401 #else
1402 DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, NEON_STEP_8, bufferMode, arrayU[0], arrayV[0]);
1403 #endif
1404 }
1405 screenBuffer += step;
1406 len -= NEON_STEP_8;
1407 }
1408 if (len > 0) {
1409 #if ENABLE_FIXED_POINT
1410 int64_t fixedU = FO_TRANS_FLOAT_TO_FIXED(u);
1411 int64_t fixedV = FO_TRANS_FLOAT_TO_FIXED(v);
1412 DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, len, bufferMode, fixedU, fixedV);
1413 #else
1414 DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, len, bufferMode, u, v);
1415 #endif
1416 }
1417 }
1418 #endif
1419
1420 void DrawUtils::Draw3DTriangleTrueColorBilinear8888(const TriangleScanInfo& in, const ColorMode bufferMode)
1421 {
1422 int16_t maskLeft = in.mask.GetLeft();
1423 int16_t maskRight = in.mask.GetRight();
1424 int16_t xMinErr = 0;
1425 int16_t xMaxErr = 0;
1426 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1427 #if ENABLE_FIXED_POINT
1428 int64_t invMatrix00 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[0]);
1429 int64_t invMatrix01 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[1]);
1430 int64_t invMatrix02 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[2]);
1431 int64_t invMatrix20 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[3]);
1432 int64_t invMatrix21 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[4]);
1433 int64_t invMatrix22 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[5]);
1434 int64_t invMatrix30 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[6]);
1435 int64_t invMatrix31 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[7]);
1436 int64_t invMatrix32 = FO_TRANS_FLOAT_TO_FIXED(in.matrix.GetData()[8]);
1437 #else // ENABLE_FIXED_POINT
1438 float invMatrix00 = in.matrix.GetData()[0];
1439 float invMatrix01 = in.matrix.GetData()[1];
1440 float invMatrix02 = in.matrix.GetData()[2];
1441 float invMatrix20 = in.matrix.GetData()[3];
1442 float invMatrix21 = in.matrix.GetData()[4];
1443 float invMatrix22 = in.matrix.GetData()[5];
1444 float invMatrix30 = in.matrix.GetData()[6];
1445 float invMatrix31 = in.matrix.GetData()[7];
1446 float invMatrix32 = in.matrix.GetData()[8];
1447 #endif // ENABLE_FIXED_POINT
1448 for (int16_t y = in.yMin; y <= in.yMax; ++y) {
1449 #if ENABLE_FIXED_POINT
1450 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1451 int16_t xMin = MATH_MAX(tempV, maskLeft);
1452 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1453 int16_t xMax = MATH_MIN(tempV, maskRight);
1454 #else // ENABLE_FIXED_POINT
1455 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1456 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1457 #endif // ENABLE_FIXED_POINT
1458 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1459 // move to current position
1460 for (int16_t x = xMin; x <= xMax; x++) {
1461 #if ENABLE_FIXED_POINT
1462 int64_t w = invMatrix02 * x + invMatrix22 * y + invMatrix32;
1463 int64_t u = FO_DIV((invMatrix00 * x + invMatrix20 * y + invMatrix30), w);
1464 int64_t v = FO_DIV((invMatrix01 * x + invMatrix21 * y + invMatrix31), w);
1465 int16_t intU = FO_TO_INTEGER(u);
1466 int16_t intV = FO_TO_INTEGER(v);
1467 #else // ENABLE_FIXED_POINT
1468 float w = invMatrix02 * x + invMatrix22 * y + invMatrix32;
1469 float u = (invMatrix00 * x + invMatrix20 * y + invMatrix30) / w;
1470 float v = (invMatrix01 * x + invMatrix21 * y + invMatrix31) / w;
1471 int16_t intU = static_cast<int16_t>(u);
1472 int16_t intV = static_cast<int16_t>(v);
1473 #endif // ENABLE_FIXED_POINT
1474 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1475 #if ENABLE_ARM_MATH
1476 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1477 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1478 uint32_t px1 = val1 + val2;
1479 #else // ENABLE_ARM_MATH
1480 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1481 #endif // ENABLE_ARM_MATH
1482 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1483 const ColorType p1 = *(reinterpret_cast<ColorType*>(&imgHead[px1]));
1484 const ColorType p2 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.pixelSize]));
1485 const ColorType p3 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth]));
1486 const ColorType p4 = *(reinterpret_cast<ColorType*>(&imgHead[px1 + in.srcLineWidth + in.pixelSize]));
1487 #if ENABLE_FIXED_POINT
1488 int64_t decU = FO_DECIMAL(u);
1489 int64_t decV = FO_DECIMAL(v);
1490 int64_t decUMinus1 = FIXED_NUM_1 - decU;
1491 int64_t decVMinus1 = FIXED_NUM_1 - decV;
1492 int64_t w1 = FO_MUL(decUMinus1, decVMinus1);
1493 int64_t w2 = FO_MUL(decU, decVMinus1);
1494 int64_t w3 = FO_MUL(decUMinus1, decV);
1495 int64_t w4 = FO_MUL(decU, decV);
1496 #if ENABLE_ARM_MATH
1497 const int64_t outR =
1498 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1499 const int64_t outG =
1500 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1501 const int64_t outB =
1502 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1503 const int64_t outA =
1504 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1505 #else
1506 const int64_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1507 const int64_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1508 const int64_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1509 const int64_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1510 #endif
1511 Color32 result;
1512 result.red = static_cast<uint8_t>(outR >> FIXED_Q_NUM);
1513 result.green = static_cast<uint8_t>(outG >> FIXED_Q_NUM);
1514 result.blue = static_cast<uint8_t>(outB >> FIXED_Q_NUM);
1515 result.alpha = static_cast<uint8_t>(outA >> FIXED_Q_NUM);
1516 #else // ENABLE_FIXED_POINT
1517 const float decU = u - intU;
1518 const float decV = v - intV;
1519 const float decUMinus1 = 1 - decU;
1520 const float decVMinus1 = 1 - decV;
1521 const int32_t w1 = static_cast<int32_t>(decUMinus1 * decVMinus1 * 256.0f); // 256:shift 8 bit left
1522 const int32_t w2 = static_cast<int32_t>(decU * decVMinus1 * 256.0f); // 256:shift 8 bit left
1523 const int32_t w3 = static_cast<int32_t>(decUMinus1 * decV * 256.0f); // 256:shift 8 bit left
1524 const int32_t w4 = static_cast<int32_t>(decU * decV * 256.0f);
1525 #if ENABLE_ARM_MATH
1526 const int32_t outR =
1527 __SMUAD(p1.red, w1) + __SMUAD(p2.red, w2) + __SMUAD(p3.red, w3) + __SMUAD(p4.red, w4);
1528 const int32_t outG =
1529 __SMUAD(p1.green, w1) + __SMUAD(p2.green, w2) + __SMUAD(p3.green, w3) + __SMUAD(p4.green, w4);
1530 const int32_t outB =
1531 __SMUAD(p1.blue, w1) + __SMUAD(p2.blue, w2) + __SMUAD(p3.blue, w3) + __SMUAD(p4.blue, w4);
1532 const int32_t outA =
1533 __SMUAD(p1.alpha, w1) + __SMUAD(p2.alpha, w2) + __SMUAD(p3.alpha, w3) + __SMUAD(p4.alpha, w4);
1534 #else // ENABLE_ARM_MATH
1535 const int32_t outR = p1.red * w1 + p2.red * w2 + p3.red * w3 + p4.red * w4;
1536 const int32_t outG = p1.green * w1 + p2.green * w2 + p3.green * w3 + p4.green * w4;
1537 const int32_t outB = p1.blue * w1 + p2.blue * w2 + p3.blue * w3 + p4.blue * w4;
1538 const int32_t outA = p1.alpha * w1 + p2.alpha * w2 + p3.alpha * w3 + p4.alpha * w4;
1539 #endif // ENABLE_ARM_MATH
1540 Color32 result;
1541 result.red = static_cast<uint8_t>(outR >> 8); // 8:shift 8 bit right
1542 result.green = static_cast<uint8_t>(outG >> 8); // 8:shift 8 bit right
1543 result.blue = static_cast<uint8_t>(outB >> 8); // 8:shift 8 bit right
1544 result.alpha = static_cast<uint8_t>(outA >> 8); // 8:shift 8 bit right
1545 #endif // ENABLE_FIXED_POINT
1546 if ((in.opaScale == OPA_OPAQUE) && (result.alpha == OPA_OPAQUE)) {
1547 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
1548 } else {
1549 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, in.opaScale);
1550 }
1551 }
1552 screenBuffer += in.bufferPxSize;
1553 }
1554 StepToNextLine(in.edge1, in.edge2);
1555 }
1556 }
1557
1558 void DrawUtils::DrawTriangleTrueColorBilinear8888(const TriangleScanInfo& in, const ColorMode bufferMode)
1559 {
1560 int16_t maskLeft = in.mask.GetLeft();
1561 int16_t maskRight = in.mask.GetRight();
1562 int16_t xMinErr = 0;
1563 int16_t xMaxErr = 0;
1564 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1565 #ifdef ARM_NEON_OPT
1566 NeonBlendPipeLine pipeLine;
1567 pipeLine.Construct(bufferMode, ARGB8888);
1568 #endif
1569 for (int16_t y = in.yMin; y <= in.yMax; ++y) {
1570 #if ENABLE_FIXED_POINT
1571 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1572 int16_t xMin = MATH_MAX(tempV, maskLeft);
1573 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1574 int16_t xMax = MATH_MIN(tempV, maskRight);
1575 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1576 #else
1577 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1578 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1579 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1580 #endif
1581 in.init.verticalU += in.init.duHorizon * diffX;
1582 in.init.verticalV += in.init.dvHorizon * diffX;
1583 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1584 #ifdef ARM_NEON_OPT
1585 {
1586 #if ENABLE_FIXED_POINT
1587 float u = static_cast<float>(in.init.verticalU) / FIXED_NUM_1;
1588 float v = static_cast<float>(in.init.verticalV) / FIXED_NUM_1;
1589 #else
1590 float u = in.init.verticalU;
1591 float v = in.init.verticalV;
1592 #endif
1593 DEBUG_PERFORMANCE_TRACE("DrawTriangleTrueColorBilinear8888_neon");
1594 DrawTriangleTrueColorBilinear8888InnerNeon(in, screenBuffer, xMax - xMin + 1, u, v, pipeLine, bufferMode);
1595 }
1596 #else
1597 {
1598 DEBUG_PERFORMANCE_TRACE("DrawTriangleTrueColorBilinear8888");
1599 #if ENABLE_FIXED_POINT
1600 DrawFixedTriangleTrueColorBilinear8888Inner(in, screenBuffer, xMax - xMin + 1, bufferMode,
1601 in.init.verticalU, in.init.verticalV);
1602 #else
1603 DrawTriangleTrueColorBilinear8888Inner(in, screenBuffer, xMax - xMin + 1, bufferMode, in.init.verticalU,
1604 in.init.verticalV);
1605 #endif
1606 }
1607 #endif
1608 StepToNextLine(in.edge1, in.edge2);
1609 in.init.verticalU += in.init.duVertical;
1610 in.init.verticalV += in.init.dvVertical;
1611 #if ENABLE_FIXED_POINT
1612 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1613 #else
1614 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1615 #endif
1616 in.init.verticalU += in.init.duHorizon * deltaX;
1617 in.init.verticalV += in.init.dvHorizon * deltaX;
1618 }
1619 }
1620
1621 void DrawUtils::DrawTriangleTrueColorNearest(const TriangleScanInfo& in, const ColorMode bufferMode)
1622 {
1623 int16_t maskLeft = in.mask.GetLeft();
1624 int16_t maskRight = in.mask.GetRight();
1625 int16_t xMinErr = 0;
1626 int16_t xMaxErr = 0;
1627 GetXAxisErrForJunctionLine(in.ignoreJunctionPoint, in.isRightPart, xMinErr, xMaxErr);
1628 for (int16_t y = in.yMin; y <= in.yMax; y++) {
1629 #if ENABLE_FIXED_POINT
1630 int16_t tempV = FO_TO_INTEGER(in.edge1.curX) + xMinErr;
1631 int16_t xMin = MATH_MAX(tempV, maskLeft);
1632 tempV = FO_TO_INTEGER(in.edge2.curX) + xMaxErr;
1633 int16_t xMax = MATH_MIN(tempV, maskRight);
1634 int16_t diffX = xMin - FO_TO_INTEGER(in.edge1.curX);
1635 #else
1636 int16_t xMin = MATH_MAX(static_cast<int16_t>(in.edge1.curX + xMinErr), maskLeft);
1637 int16_t xMax = MATH_MIN(static_cast<int16_t>(in.edge2.curX + xMaxErr), maskRight);
1638 int16_t diffX = (xMin - static_cast<int32_t>(in.edge1.curX));
1639 #endif
1640 in.init.verticalU += in.init.duHorizon * diffX;
1641 in.init.verticalV += in.init.dvHorizon * diffX;
1642 uint8_t* screenBuffer = in.screenBuffer + (y * in.screenBufferWidth + xMin) * in.bufferPxSize;
1643 #if ENABLE_FIXED_POINT
1644 // parameters below are Q15 fixed-point number
1645 int64_t u = in.init.verticalU;
1646 int64_t v = in.init.verticalV;
1647 // parameters above are Q15 fixed-point number
1648 #else
1649 float u = in.init.verticalU;
1650 float v = in.init.verticalV;
1651 #endif
1652 for (int16_t x = xMin; x <= xMax; x++) {
1653 #if ENABLE_FIXED_POINT
1654 int16_t intU = FO_TO_INTEGER(u);
1655 int16_t intV = FO_TO_INTEGER(v);
1656 if ((u >= 0) && (intU < (in.info.header.width - 1)) && (v >= 0) && (intV < (in.info.header.height - 1))) {
1657 #else
1658 const int16_t intU = static_cast<int16_t>(u);
1659 const int16_t intV = static_cast<int16_t>(v);
1660 if ((u >= 0) && (intU < in.info.header.width - 1) && (v >= 0) && (intV < in.info.header.height - 1)) {
1661 #endif
1662 #if ENABLE_ARM_MATH
1663 uint32_t val1 = __SMUAD(intV, in.srcLineWidth);
1664 uint32_t val2 = __SMUAD(intU, in.pixelSize);
1665 uint32_t px1 = val1 + val2;
1666 #else
1667 uint32_t px1 = intV * in.srcLineWidth + intU * in.pixelSize;
1668 #endif
1669 uint8_t* imgHead = const_cast<uint8_t*>(in.info.data);
1670 OpacityType opa = in.opaScale;
1671
1672 switch (in.info.header.colorMode) {
1673 case RGB888: {
1674 Color24 p24 = *(reinterpret_cast<Color24*>(&imgHead[px1]));
1675 if (opa == OPA_OPAQUE) {
1676 COLOR_FILL_COVER(screenBuffer, bufferMode, p24.red, p24.green, p24.blue, RGB888);
1677 } else {
1678 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p24, RGB888, opa);
1679 }
1680 break;
1681 }
1682 case RGB565: {
1683 Color16 p16 = *(reinterpret_cast<Color16*>(&imgHead[px1]));
1684 if (opa == OPA_OPAQUE) {
1685 COLOR_FILL_COVER(screenBuffer, bufferMode, p16.red, p16.green, p16.blue, RGB565);
1686 } else {
1687 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p16, RGB565, opa);
1688 }
1689 break;
1690 }
1691 case ARGB8888: {
1692 Color32 p32 = *(reinterpret_cast<Color32*>(&imgHead[px1]));
1693 if ((in.opaScale == OPA_OPAQUE) && (p32.alpha == OPA_OPAQUE)) {
1694 COLOR_FILL_COVER(screenBuffer, bufferMode, p32.red, p32.green, p32.blue, ARGB8888);
1695 } else {
1696 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p32, ARGB8888, in.opaScale);
1697 }
1698 break;
1699 }
1700 case XRGB8888: {
1701 Color32 p32 = *(reinterpret_cast<Color32*>(&imgHead[px1]));
1702 if ((in.opaScale == OPA_OPAQUE) && (p32.alpha == OPA_OPAQUE)) {
1703 COLOR_FILL_COVER(screenBuffer, bufferMode, p32.red, p32.green, p32.blue, XRGB8888);
1704 } else {
1705 COLOR_FILL_BLEND(screenBuffer, bufferMode, &p32, XRGB8888, in.opaScale);
1706 }
1707 break;
1708 }
1709 default:
1710 return;
1711 }
1712 }
1713 u += in.init.duHorizon;
1714 v += in.init.dvHorizon;
1715 screenBuffer += in.bufferPxSize;
1716 }
1717 StepToNextLine(in.edge1, in.edge2);
1718 in.init.verticalU += in.init.duVertical;
1719 in.init.verticalV += in.init.dvVertical;
1720 #if ENABLE_FIXED_POINT
1721 int16_t deltaX = FO_TO_INTEGER(in.edge1.curX) - xMin;
1722 #else
1723 int16_t deltaX = static_cast<int16_t>(in.edge1.curX) - xMin;
1724 #endif
1725 in.init.verticalU += in.init.duHorizon * deltaX;
1726 in.init.verticalV += in.init.dvHorizon * deltaX;
1727 }
1728 }
1729
1730 void DrawUtils::DrawTriangleTransformPart(BufferInfo& gfxDstBuffer, const TrianglePartInfo& part)
1731 {
1732 #if ENABLE_FIXED_POINT
1733 // parameters below are Q15 fixed-point number
1734 int64_t yMin = FO_TRANS_INTEGER_TO_FIXED(part.yMin);
1735 part.edge1.curX += (static_cast<int64_t>(part.edge1.du) * (yMin - part.edge1.curY) / part.edge1.dv);
1736 part.edge1.curY = yMin;
1737 part.edge2.curX += (static_cast<int64_t>(part.edge2.du) * (yMin - part.edge2.curY) / part.edge2.dv);
1738 part.edge2.curY = yMin;
1739 Rect line;
1740 line.SetLeft(FO_TO_INTEGER(part.edge1.curX));
1741 line.SetRight(FO_TO_INTEGER(part.edge1.curX));
1742 line.SetTop(FO_TO_INTEGER(part.edge1.curY));
1743 line.SetBottom(FO_TO_INTEGER(part.edge1.curY));
1744 // parameters above are Q15 fixed-point number
1745 #else
1746 part.edge1.curX += part.edge1.du * (part.yMin - part.edge1.curY) / part.edge1.dv;
1747 part.edge1.curY = part.yMin;
1748 part.edge2.curX += part.edge2.du * (part.yMin - part.edge2.curY) / part.edge2.dv;
1749 part.edge2.curY = part.yMin;
1750 Rect line;
1751 line.SetLeft(static_cast<int16_t>(part.edge1.curX));
1752 line.SetRight(static_cast<int16_t>(part.edge1.curX));
1753 line.SetTop(static_cast<int16_t>(part.edge1.curY));
1754 line.SetBottom(static_cast<int16_t>(part.edge1.curY));
1755 #endif
1756 TransformInitState init;
1757 GetTransformInitState(part.transMap, part.position, line, init);
1758
1759 uint8_t* screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
1760 if (screenBuffer == nullptr) {
1761 return;
1762 }
1763 ColorMode bufferMode = gfxDstBuffer.mode;
1764 uint8_t bufferPxSize = GetByteSizeByColorMode(bufferMode);
1765
1766 uint8_t pixelSize;
1767 DrawTriangleTransformFuc fuc;
1768 bool isTrueColor = (part.info.header.colorMode == ARGB8888) || (part.info.header.colorMode == RGB888) ||
1769 (part.info.header.colorMode == RGB565) || (part.info.header.colorMode == XRGB8888);
1770 if (isTrueColor) {
1771 pixelSize = part.info.pxSize >> SHIFT_3;
1772 if (part.info.algorithm == TransformAlgorithm::NEAREST_NEIGHBOR) {
1773 fuc = DrawTriangleTrueColorNearest;
1774 } else if (part.info.header.colorMode == ARGB8888 || part.info.header.colorMode == XRGB8888) {
1775 if (part.transMap.Is3DTransform()) {
1776 fuc = Draw3DTriangleTrueColorBilinear8888;
1777 } else {
1778 fuc = DrawTriangleTrueColorBilinear8888;
1779 }
1780 } else if (part.info.header.colorMode == RGB888) {
1781 fuc = DrawTriangleTrueColorBilinear888;
1782 } else {
1783 fuc = DrawTriangleTrueColorBilinear565;
1784 }
1785 } else {
1786 pixelSize = part.info.pxSize;
1787 fuc = DrawTriangleAlphaBilinear;
1788 }
1789 const int32_t srcLineWidth = part.info.header.width * pixelSize;
1790 TriangleScanInfo input{part.yMin,
1791 part.yMax,
1792 part.edge1,
1793 part.edge2,
1794 screenBuffer,
1795 bufferPxSize,
1796 part.color,
1797 part.opaScale,
1798 init,
1799 gfxDstBuffer.width,
1800 pixelSize,
1801 srcLineWidth,
1802 part.info,
1803 part.mask,
1804 part.isRightPart,
1805 part.ignoreJunctionPoint,
1806 part.transMap.invMatrix_};
1807 fuc(input, gfxDstBuffer.mode);
1808 }
1809
1810 void DrawUtils::DrawTriangleTransform(BufferInfo& gfxDstBuffer,
1811 const Rect& mask,
1812 const Point& position,
1813 const ColorType& color,
1814 OpacityType opaScale,
1815 const TransformMap& transMap,
1816 const TriangleTransformDataInfo& triangleInfo)
1817 {
1818 bool p3IsInRight = ((triangleInfo.p1.y - triangleInfo.p2.y) * triangleInfo.p3.x +
1819 (triangleInfo.p2.x - triangleInfo.p1.x) * triangleInfo.p3.y +
1820 triangleInfo.p1.x * triangleInfo.p2.y - triangleInfo.p2.x * triangleInfo.p1.y) < 0;
1821 TriangleEdge edge1;
1822 TriangleEdge edge2;
1823 TrianglePartInfo part{
1824 mask,
1825 transMap,
1826 position,
1827 edge1,
1828 edge2,
1829 0,
1830 0,
1831 triangleInfo.info,
1832 color,
1833 opaScale,
1834 triangleInfo.isRightPart,
1835 triangleInfo.ignoreJunctionPoint,
1836 };
1837
1838 uint8_t yErr = 1;
1839 if (triangleInfo.p2.y == triangleInfo.p1.y) {
1840 yErr = 0;
1841 goto BottomHalf;
1842 }
1843 if (p3IsInRight) {
1844 edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p2.x, triangleInfo.p2.y);
1845 edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1846 } else {
1847 edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p2.x, triangleInfo.p2.y);
1848 edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1849 }
1850
1851 part.yMin = MATH_MAX(mask.GetTop(), triangleInfo.p1.y);
1852 part.yMax = MATH_MIN(mask.GetBottom(), triangleInfo.p2.y);
1853 part.edge1 = edge1;
1854 part.edge2 = edge2;
1855 DrawTriangleTransformPart(gfxDstBuffer, part);
1856 BottomHalf:
1857 if (triangleInfo.p2.y == triangleInfo.p3.y) {
1858 return;
1859 }
1860
1861 if (triangleInfo.p2.y == triangleInfo.p1.y) {
1862 if (triangleInfo.p1.x < triangleInfo.p2.x) {
1863 edge1 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1864 edge2 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1865 } else {
1866 edge2 = TriangleEdge(triangleInfo.p1.x, triangleInfo.p1.y, triangleInfo.p3.x, triangleInfo.p3.y);
1867 edge1 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1868 }
1869 } else {
1870 if (p3IsInRight) {
1871 edge1 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1872 } else {
1873 edge2 = TriangleEdge(triangleInfo.p2.x, triangleInfo.p2.y, triangleInfo.p3.x, triangleInfo.p3.y);
1874 }
1875 }
1876
1877 part.yMin = MATH_MAX(mask.GetTop(), triangleInfo.p2.y + yErr);
1878 part.yMax = MATH_MIN(mask.GetBottom(), triangleInfo.p3.y);
1879 part.edge1 = edge1;
1880 part.edge2 = edge2;
1881 DrawTriangleTransformPart(gfxDstBuffer, part);
1882 }
1883
1884 void DrawUtils::AddBorderToImageData(TransformDataInfo& newDataInfo, ImageInfo& imageinfo)
1885 {
1886 int16_t border = 1; // 1 : border width
1887 int16_t offset = border * 2; // 2 : offset
1888 uint16_t width = newDataInfo.header.width;
1889 uint16_t height = newDataInfo.header.height;
1890 int16_t diff = 0;
1891 if (newDataInfo.pxSize > FONT_WEIGHT_8) {
1892 width += offset;
1893 height += offset;
1894 diff = border * newDataInfo.pxSize / FONT_WEIGHT_8;
1895 } else {
1896 width += offset * FONT_WEIGHT_8 / newDataInfo.pxSize;
1897 height += offset;
1898 diff = border;
1899 }
1900 uint16_t widthInByte = width * newDataInfo.pxSize / FONT_WEIGHT_8;
1901 if ((width * newDataInfo.pxSize) % FONT_WEIGHT_8 != 0) {
1902 widthInByte++;
1903 }
1904 imageinfo.header.width = newDataInfo.header.width;
1905 imageinfo.header.height = newDataInfo.header.height;
1906 imageinfo.dataSize = widthInByte * height;
1907 uint8_t* newData = static_cast<uint8_t*>(ImageCacheMalloc(imageinfo));
1908 if (newData == nullptr) {
1909 return;
1910 }
1911 imageinfo.data = newData;
1912 if (memset_s(newData, widthInByte * height, 0, widthInByte * height) != EOK) {
1913 ImageCacheFree(imageinfo);
1914 newData = nullptr;
1915 return;
1916 }
1917 uint8_t* tmp = newData;
1918 uint8_t* data = const_cast<uint8_t*>(newDataInfo.data);
1919 tmp += widthInByte * border + diff;
1920 for (int i = 0; i < newDataInfo.header.height; ++i) {
1921 // 2 : double
1922 if (memcpy_s(tmp, widthInByte - diff * 2, data, widthInByte - diff * 2) != EOK) {
1923 ImageCacheFree(imageinfo);
1924 newData = nullptr;
1925 return;
1926 }
1927 tmp += widthInByte;
1928 data += widthInByte - diff * 2; // 2 : double
1929 }
1930 newDataInfo.header.width = width;
1931 newDataInfo.header.height = height;
1932 newDataInfo.data = newData;
1933 }
1934
1935 void DrawUtils::UpdateTransMap(int16_t width, int16_t height, TransformMap& transMap)
1936 {
1937 Rect rect = transMap.GetTransMapRect();
1938 Matrix4<float> matrix = transMap.GetTransformMatrix();
1939 matrix = matrix * (Matrix4<float>::Translate(Vector3<float>(-rect.GetX(), -rect.GetY(), 0)));
1940 int16_t offsetX = (width - rect.GetWidth()) / 2; // 2 : half;
1941 int16_t offsetY = (height - rect.GetHeight()) / 2; // 2 : half;
1942 rect.SetPosition(rect.GetX() - offsetX, rect.GetY() - offsetY);
1943 rect.Resize(width, height);
1944 Polygon polygon = Polygon(rect);
1945 uint8_t vertexNum = transMap.GetPolygon().GetVertexNum();
1946 Vector4<float> imgPoint4;
1947 for (uint8_t i = 0; i < vertexNum; i++) {
1948 Vector4<float> point(polygon[i].x_, polygon[i].y_, 0, 1);
1949 imgPoint4 = matrix * point;
1950 if (imgPoint4.x_ < COORD_MIN) {
1951 polygon[i].x_ = COORD_MIN;
1952 } else if (imgPoint4.x_ > COORD_MAX) {
1953 polygon[i].x_ = COORD_MAX;
1954 } else {
1955 polygon[i].x_ = MATH_ROUND(imgPoint4.x_);
1956 }
1957
1958 if (imgPoint4.y_ < COORD_MIN) {
1959 polygon[i].y_ = COORD_MIN;
1960 } else if (imgPoint4.y_ > COORD_MAX) {
1961 polygon[i].y_ = COORD_MAX;
1962 } else {
1963 polygon[i].y_ = MATH_ROUND(imgPoint4.y_);
1964 }
1965 }
1966 transMap.SetPolygon(polygon);
1967 Matrix3<float> matrix3(matrix[0][0], matrix[0][1], matrix[0][3], matrix[1][0], matrix[1][1], matrix[1][3],
1968 matrix[3][0], matrix[3][1], matrix[3][3]);
1969 transMap.invMatrix_ = (matrix3 * (Matrix3<float>::Translate(Vector2<float>(rect.GetX(), rect.GetY())))).Inverse();
1970 }
1971
1972 void DrawUtils::DrawTransform(BufferInfo& gfxDstBuffer,
1973 const Rect& mask,
1974 const Point& position,
1975 const ColorType& color,
1976 OpacityType opaScale,
1977 const TransformMap& transMap,
1978 const TransformDataInfo& dataInfo) const
1979 {
1980 if (opaScale == OPA_TRANSPARENT) {
1981 return;
1982 }
1983 if ((gfxDstBuffer.virAddr == nullptr) || (dataInfo.data == nullptr)) {
1984 return;
1985 }
1986 ImageInfo imageinfo;
1987 TransformDataInfo newDataInfo = dataInfo;
1988 TransformMap newTransMap = transMap;
1989 // If the width and height of the rectangle of transMap are not equal to the width and height of the ImageHeader,
1990 // a border of transparency values to the data cannot be added.
1991 if ((transMap.GetTransMapRect().GetWidth() == dataInfo.header.width) &&
1992 (transMap.GetTransMapRect().GetHeight() == dataInfo.header.height)) {
1993 // Add a border of transparency values to the data
1994 AddBorderToImageData(newDataInfo, imageinfo);
1995 // Update the transMap according to new rect width and height
1996 UpdateTransMap(newDataInfo.header.width, newDataInfo.header.height, newTransMap);
1997 }
1998
1999 Rect trans = newTransMap.GetBoxRect();
2000 trans.SetX(trans.GetX() + position.x);
2001 trans.SetY(trans.GetY() + position.y);
2002 imageinfo.data = newDataInfo.data;
2003 if (!trans.Intersect(trans, mask)) {
2004 if (newDataInfo.data != dataInfo.data) {
2005 ImageCacheFree(imageinfo);
2006 }
2007 return;
2008 }
2009
2010 TriangleTransformDataInfo triangleInfo{
2011 newDataInfo,
2012 };
2013 Polygon polygon = newTransMap.GetPolygon();
2014 Point p1;
2015 p1.x = polygon[0].x_ + position.x; // 0:first point
2016 p1.y = polygon[0].y_ + position.y; // 0:first point
2017 Point p2;
2018 p2.x = polygon[1].x_ + position.x; // 1:second point
2019 p2.y = polygon[1].y_ + position.y; // 1:second point
2020 Point p3;
2021 p3.x = polygon[2].x_ + position.x; // 2:third point
2022 p3.y = polygon[2].y_ + position.y; // 2:third point
2023 triangleInfo.isRightPart = ((p1.y - p3.y) * p2.x + (p3.x - p1.x) * p2.y + p1.x * p3.y - p3.x * p1.y) < 0;
2024 triangleInfo.isRightPart = (p1.y < p3.y) ? triangleInfo.isRightPart : !triangleInfo.isRightPart;
2025 DrawTriangle::SortVertexs(p1, p2, p3);
2026 triangleInfo.ignoreJunctionPoint = false;
2027 triangleInfo.p1 = p1;
2028 triangleInfo.p2 = p2;
2029 triangleInfo.p3 = p3;
2030 if ((triangleInfo.p1.y <= mask.GetBottom()) && (triangleInfo.p3.y >= mask.GetTop())) {
2031 DrawTriangleTransform(gfxDstBuffer, mask, position, color, opaScale, newTransMap, triangleInfo);
2032 }
2033
2034 triangleInfo.ignoreJunctionPoint = true;
2035 triangleInfo.isRightPart = !triangleInfo.isRightPart;
2036 p1.x = polygon[0].x_ + position.x; // 0:first point
2037 p1.y = polygon[0].y_ + position.y; // 0:first point
2038 p3.x = polygon[2].x_ + position.x; // 2:third point
2039 p3.y = polygon[2].y_ + position.y; // 2:third point
2040 Point p4;
2041 p4.x = polygon[3].x_ + position.x; // 3:fourth point
2042 p4.y = polygon[3].y_ + position.y; // 3:fourth point
2043 DrawTriangle::SortVertexs(p1, p3, p4);
2044 triangleInfo.p1 = p1;
2045 triangleInfo.p2 = p3;
2046 triangleInfo.p3 = p4;
2047 if ((triangleInfo.p1.y <= mask.GetBottom()) && (triangleInfo.p3.y >= mask.GetTop())) {
2048 DrawTriangleTransform(gfxDstBuffer, mask, position, color, opaScale, newTransMap, triangleInfo);
2049 }
2050 if (newDataInfo.data != dataInfo.data) {
2051 ImageCacheFree(imageinfo);
2052 }
2053 }
2054
2055 OpacityType DrawUtils::GetPxAlphaForAlphaImg(const TransformDataInfo& dataInfo, const Point& point)
2056 {
2057 Point tmpPoint = point;
2058 const uint8_t* bufU8 = const_cast<uint8_t*>(dataInfo.data);
2059 #if ENABLE_SPEC_FONT
2060 if (dataInfo.header.colorMode == A1) {
2061 uint8_t bit = tmpPoint.x & 0x7; // 0x7: 1 byte is 8 bit,
2062 tmpPoint.x = tmpPoint.x >> SHIFT_3;
2063
2064 uint32_t px = (dataInfo.header.width >> SHIFT_3) * tmpPoint.y + tmpPoint.x;
2065 // 1: A1 means 1 bit, 7: maximum offset in bytes
2066 uint8_t pxOpa = (bufU8[px] & (1 << (7 - bit))) >> (7 - bit);
2067 return pxOpa ? OPA_TRANSPARENT : OPA_OPAQUE;
2068 } else if (dataInfo.header.colorMode == A2) {
2069 uint8_t bit = (tmpPoint.x & 0x3) * 2; // 0x3: 0b0011, 2: A2 color mode
2070 tmpPoint.x = tmpPoint.x >> SHIFT_2;
2071
2072 uint32_t px = (dataInfo.header.width >> SHIFT_2) * tmpPoint.y + tmpPoint.x;
2073 // 3: the value of 0b0011
2074 uint8_t pxOpa = (bufU8[px] & (3 << (SHIFT_6 - bit))) >> (SHIFT_6 - bit);
2075 return pxOpa * OPACITY_STEP_A2;
2076 } else if (dataInfo.header.colorMode == A8) {
2077 uint32_t px = dataInfo.header.width * tmpPoint.y + tmpPoint.x;
2078 return bufU8[px];
2079 }
2080 #else
2081 uint8_t letterWidthInByte = (dataInfo.header.width * dataInfo.pxSize) >> SHIFT_3;
2082 // 0x7: for rounding
2083 if ((dataInfo.header.width * dataInfo.pxSize) & 0x7) {
2084 letterWidthInByte++;
2085 }
2086 uint8_t bit = (tmpPoint.x & 0x1) << SHIFT_2;
2087 bufU8 += (tmpPoint.y * letterWidthInByte) + ((tmpPoint.x * dataInfo.pxSize) >> SHIFT_3);
2088 // 0xF: 0b1111, get the data of the A4 color mode
2089 uint8_t pxOpa = (*bufU8 & (0xF << bit)) >> (bit);
2090 return pxOpa * OPACITY_STEP_A4;
2091 #endif // ENABLE_SPEC_FONT
2092 }
2093
2094 void DrawUtils::DrawTranspantArea(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask)
2095 {
2096 FillArea(gfxDstBuffer, rect, mask, true, nullptr);
2097 }
2098
2099 void DrawUtils::DrawWithBuffer(BufferInfo& gfxDstBuffer, const Rect& rect, const Rect& mask, const ColorType* colorBuf)
2100 {
2101 FillArea(gfxDstBuffer, rect, mask, false, colorBuf);
2102 }
2103
2104 void DrawUtils::FillArea(BufferInfo& gfxDstBuffer,
2105 const Rect& rect,
2106 const Rect& mask,
2107 bool isTransparent,
2108 const ColorType* colorBuf)
2109 {
2110 Rect maskedArea;
2111 if (!maskedArea.Intersect(rect, mask)) {
2112 return;
2113 }
2114
2115 int16_t left = maskedArea.GetLeft();
2116 int16_t right = maskedArea.GetRight();
2117 int16_t top = maskedArea.GetTop();
2118 int16_t bottom = maskedArea.GetBottom();
2119
2120 DRAW_UTILS_PREPROCESS(gfxDstBuffer, OPA_OPAQUE);
2121 uint8_t* mem = screenBuffer;
2122 mem += top * screenBufferWidth * bufferPxSize;
2123 if (isTransparent) {
2124 uint16_t sz = (right - left + 1) * bufferPxSize;
2125 for (int16_t row = top; row <= bottom; row++) {
2126 if (memset_s(mem + (left * bufferPxSize), sz, 0, sz) != EOK) {
2127 return;
2128 }
2129 mem += screenBufferWidth * bufferPxSize;
2130 }
2131 } else {
2132 if (colorBuf == nullptr) {
2133 return;
2134 }
2135 for (int16_t row = top; row <= bottom; row++) {
2136 for (int16_t col = left; col <= right; col++) {
2137 #if COLOR_DEPTH == 32
2138 COLOR_FILL_COVER(mem[col * bufferPxSize], bufferMode, colorBuf[row * screenBufferWidth + col].red,
2139 colorBuf[row * screenBufferWidth + col].green,
2140 colorBuf[row * screenBufferWidth + col].blue, ARGB8888);
2141 #else
2142 COLOR_FILL_COVER(mem[col * bufferPxSize], bufferMode, colorBuf[row * screenBufferWidth + col].red,
2143 colorBuf[row * screenBufferWidth + col].green,
2144 colorBuf[row * screenBufferWidth + col].blue, RGB565);
2145 #endif
2146 }
2147 mem += screenBufferWidth * bufferPxSize;
2148 }
2149 }
2150 }
2151
2152 void DrawUtils::DrawAdjPixelInLine(BufferInfo& gfxDstBuffer,
2153 int16_t x1,
2154 int16_t y1,
2155 int16_t x2,
2156 int16_t y2,
2157 const Rect& mask,
2158 const ColorType& color,
2159 OpacityType opa,
2160 uint16_t weight) const
2161 {
2162 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2163 Color32 result;
2164 result.full = Color::ColorTo32(color);
2165 if ((x1 >= mask.GetLeft()) && (x1 <= mask.GetRight()) && (y1 >= mask.GetTop()) && (y1 <= mask.GetBottom())) {
2166 screenBuffer += (y1 * screenBufferWidth + x1) * bufferPxSize;
2167 OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2168 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2169 }
2170 if ((x2 >= mask.GetLeft()) && (x2 <= mask.GetRight()) && (y2 >= mask.GetTop()) && (y2 <= mask.GetBottom())) {
2171 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2172 screenBuffer += (y2 * screenBufferWidth + x2) * bufferPxSize;
2173 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2174 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2175 }
2176 }
2177
2178 void DrawUtils::DrawPixelInLine(BufferInfo& gfxDstBuffer,
2179 int16_t x,
2180 int16_t y,
2181 const Rect& mask,
2182 const ColorType& color,
2183 OpacityType opa,
2184 uint16_t weight) const
2185 {
2186 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2187 Color32 result;
2188 result.full = Color::ColorTo32(color);
2189 if ((x >= mask.GetLeft()) && (x <= mask.GetRight()) && (y >= mask.GetTop()) && (y <= mask.GetBottom())) {
2190 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2191 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2192 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2193 }
2194 }
2195
2196 void DrawUtils::DrawVerPixelInLine(BufferInfo& gfxDstBuffer,
2197 int16_t x,
2198 int16_t y,
2199 int8_t dir,
2200 const Rect& mask,
2201 const ColorType& color,
2202 OpacityType opa,
2203 uint16_t weight) const
2204 {
2205 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2206 if ((y < mask.GetTop()) || (y > mask.GetBottom())) {
2207 return;
2208 }
2209 Color32 result;
2210 result.full = Color::ColorTo32(color);
2211 int16_t x0 = x + dir;
2212 int16_t x1 = x - dir;
2213 if ((x0 >= mask.GetLeft()) && (x0 <= mask.GetRight())) {
2214 screenBuffer += (y * screenBufferWidth + x0) * bufferPxSize;
2215 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2216 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2217 }
2218 if ((x >= mask.GetLeft()) && (x <= mask.GetRight())) {
2219 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2220 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2221 if (opa == OPA_OPAQUE) {
2222 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
2223 } else {
2224 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, opa);
2225 }
2226 }
2227 if ((x1 >= mask.GetLeft()) && (x1 <= mask.GetRight())) {
2228 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2229 screenBuffer += (y * screenBufferWidth + x1) * bufferPxSize;
2230 OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2231 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2232 }
2233 }
2234
2235 void DrawUtils::DrawHorPixelInLine(BufferInfo& gfxDstBuffer,
2236 int16_t x,
2237 int16_t y,
2238 int8_t dir,
2239 const Rect& mask,
2240 const ColorType& color,
2241 OpacityType opa,
2242 uint16_t weight) const
2243 {
2244 DRAW_UTILS_PREPROCESS(gfxDstBuffer, opa);
2245 if ((x < mask.GetLeft()) || (x > mask.GetRight())) {
2246 return;
2247 }
2248 Color32 result;
2249 result.full = Color::ColorTo32(color);
2250 int16_t y0 = y + dir;
2251 int16_t y1 = y - dir;
2252 if ((y0 >= mask.GetTop()) && (y0 <= mask.GetBottom())) {
2253 screenBuffer += (y0 * screenBufferWidth + x) * bufferPxSize;
2254 OpacityType fillOpa = weight * opa / OPA_OPAQUE;
2255 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2256 }
2257 if ((y >= mask.GetTop()) && (y <= mask.GetBottom())) {
2258 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2259 screenBuffer += (y * screenBufferWidth + x) * bufferPxSize;
2260 if (opa == OPA_OPAQUE) {
2261 COLOR_FILL_COVER(screenBuffer, bufferMode, result.red, result.green, result.blue, ARGB8888);
2262 } else {
2263 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, opa);
2264 }
2265 }
2266 if ((y1 >= mask.GetTop()) && (y1 <= mask.GetBottom())) {
2267 screenBuffer = static_cast<uint8_t*>(gfxDstBuffer.virAddr);
2268 screenBuffer += (y1 * screenBufferWidth + x) * bufferPxSize;
2269 OpacityType fillOpa = (weight ^ OPA_OPAQUE) * opa / OPA_OPAQUE;
2270 COLOR_FILL_BLEND(screenBuffer, bufferMode, &result, ARGB8888, fillOpa);
2271 }
2272 }
2273 } // namespace OHOS
2274