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