30 #include "freertos/task.h" 33 #include "images/cursors.h" 43 const RGB888 COLOR2RGB888[16] = {
68 bool RGB222::lowBitOnly =
false;
75 RGB222::RGB222(RGB888
const & value)
95 RGB888::RGB888(
Color color)
97 *
this = COLOR2RGB888[(int)color];
106 uint8_t RGB888toPackedRGB222(RGB888
const & rgb)
109 static const int CONVR64[4] = { 0 << 0,
113 static const int CONVG64[4] = { 0 << 2,
117 static const int CONVB64[4] = { 0 << 4,
122 static const int CONVR8[4] = { 0 << 0,
126 static const int CONVG8[4] = { 0 << 2,
130 static const int CONVB8[4] = { 0 << 4,
135 if (RGB222::lowBitOnly)
136 return (CONVR8[rgb.R >> 6]) | (CONVG8[rgb.G >> 6]) | (CONVB8[rgb.B >> 6]);
138 return (CONVR64[rgb.R >> 6]) | (CONVG64[rgb.G >> 6]) | (CONVB64[rgb.B >> 6]);
155 savedBackgroundWidth = 0;
156 savedBackgroundHeight = 0;
157 savedBackground =
nullptr;
160 collisionDetectorObject =
nullptr;
170 free(savedBackground);
174 void Sprite::clearBitmaps()
182 Sprite * Sprite::addBitmap(Bitmap * bitmap)
185 frames = (Bitmap**) realloc(frames,
sizeof(Bitmap*) * framesCount);
186 frames[framesCount - 1] = bitmap;
191 Sprite * Sprite::addBitmap(Bitmap * bitmap[],
int count)
193 frames = (Bitmap**) realloc(frames,
sizeof(Bitmap*) * (framesCount + count));
194 for (
int i = 0; i < count; ++i)
195 frames[framesCount + i] = bitmap[i];
196 framesCount += count;
201 Sprite * Sprite::moveBy(
int offsetX,
int offsetY)
209 Sprite * Sprite::moveBy(
int offsetX,
int offsetY,
int wrapAroundWidth,
int wrapAroundHeight)
213 if (x > wrapAroundWidth)
214 x = - (int) getWidth();
215 if (x < - (
int) getWidth())
217 if (y > wrapAroundHeight)
218 y = - (int) getHeight();
219 if (y < - (
int) getHeight())
220 y = wrapAroundHeight;
225 Sprite * Sprite::moveTo(
int x,
int y)
240 Bitmap::Bitmap(
int width_,
int height_,
void const * data_,
PixelFormat format_, RGB888 foregroundColor_,
bool copy)
244 foregroundColor(foregroundColor_),
245 data((uint8_t*)data_),
255 Bitmap::Bitmap(
int width_,
int height_,
void const * data_,
PixelFormat format_,
bool copy)
256 : Bitmap(width_, height_, data_, format_, RGB888(255, 255, 255), copy)
261 void Bitmap::allocate()
273 data = (uint8_t*) heap_caps_malloc((
width + 7) / 8 *
height, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
276 data = (uint8_t*) heap_caps_malloc(
width *
height, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
279 data = (uint8_t*) heap_caps_malloc(
width *
height * 4, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
286 void Bitmap::copyFrom(
void const * srcData)
305 void Bitmap::setPixel(
int x,
int y,
int value)
307 int rowlen = (
width + 7) / 8;
308 uint8_t * rowptr =
data + y * rowlen;
310 rowptr[x >> 3] |= 0x80 >> (x & 7);
312 rowptr[x >> 3] &= ~(0x80 >> (x & 7));
316 void Bitmap::setPixel(
int x,
int y,
RGBA2222 value)
322 void Bitmap::setPixel(
int x,
int y,
RGBA8888 value)
328 int Bitmap::getAlpha(
int x,
int y)
339 int rowlen = (
width + 7) / 8;
340 uint8_t * rowptr =
data + y * rowlen;
341 r = (rowptr[x >> 3] >> (7 - (x & 7))) & 1;
358 heap_caps_free((
void*)
data);
371 BitmappedDisplayController::BitmappedDisplayController()
372 : m_primDynMemPool(FABGLIB_PRIMITIVES_DYNBUFFERS_SIZE)
374 m_execQueue =
nullptr;
375 m_backgroundPrimitiveExecutionEnabled =
true;
378 m_doubleBuffered =
false;
379 m_mouseCursor.visible =
false;
380 m_backgroundPrimitiveTimeoutEnabled =
true;
381 m_spritesHidden =
true;
385 BitmappedDisplayController::~BitmappedDisplayController()
387 vQueueDelete(m_execQueue);
391 void BitmappedDisplayController::setDoubleBuffered(
bool value)
393 m_doubleBuffered = value;
395 vQueueDelete(m_execQueue);
401 void IRAM_ATTR BitmappedDisplayController::resetPaintState()
403 m_paintState.penColor = RGB888(255, 255, 255);
404 m_paintState.brushColor = RGB888(0, 0, 0);
405 m_paintState.position = Point(0, 0);
406 m_paintState.glyphOptions.value = 0;
407 m_paintState.paintOptions = PaintOptions();
409 m_paintState.origin = Point(0, 0);
411 m_paintState.absClippingRect = m_paintState.clippingRect;
412 m_paintState.penWidth = 1;
417 void BitmappedDisplayController::addPrimitive(Primitive & primitive)
419 if ((m_backgroundPrimitiveExecutionEnabled && m_doubleBuffered ==
false) || primitive.cmd == PrimitiveCmd::SwapBuffers) {
420 primitiveReplaceDynamicBuffers(primitive);
421 xQueueSendToBack(m_execQueue, &primitive, portMAX_DELAY);
423 if (m_doubleBuffered) {
425 ulTaskNotifyTake(
true, portMAX_DELAY);
429 Rect updateRect = Rect(SHRT_MAX, SHRT_MAX, SHRT_MIN, SHRT_MIN);
430 execPrimitive(primitive, updateRect,
false);
431 showSprites(updateRect);
439 void BitmappedDisplayController::primitiveReplaceDynamicBuffers(Primitive & primitive)
441 switch (primitive.cmd) {
442 case PrimitiveCmd::DrawPath:
443 case PrimitiveCmd::FillPath:
445 int sz = primitive.path.pointsCount *
sizeof(Point);
446 if (sz < FABGLIB_PRIMITIVES_DYNBUFFERS_SIZE) {
447 void * newbuf =
nullptr;
449 while ((newbuf = m_primDynMemPool.alloc(sz)) ==
nullptr)
451 memcpy(newbuf, primitive.path.points, sz);
452 primitive.path.points = (Point*)newbuf;
453 primitive.path.freePoints =
true;
465 bool IRAM_ATTR BitmappedDisplayController::getPrimitiveISR(Primitive * primitive)
467 return xQueueReceiveFromISR(m_execQueue, primitive,
nullptr);
471 bool BitmappedDisplayController::getPrimitive(Primitive * primitive,
int timeOutMS)
473 return xQueueReceive(m_execQueue, primitive, msToTicks(timeOutMS));
478 void BitmappedDisplayController::waitForPrimitives()
481 xQueuePeek(m_execQueue, &p, portMAX_DELAY);
485 void BitmappedDisplayController::primitivesExecutionWait()
487 if (m_backgroundPrimitiveExecutionEnabled) {
488 while (uxQueueMessagesWaiting(m_execQueue) > 0)
499 if (value != m_backgroundPrimitiveExecutionEnabled) {
506 m_backgroundPrimitiveExecutionEnabled = value;
516 Rect updateRect =
Rect(SHRT_MAX, SHRT_MAX, SHRT_MIN, SHRT_MIN);
518 while (xQueueReceive(m_execQueue, &prim, 0) == pdTRUE)
519 execPrimitive(prim, updateRect,
false);
520 showSprites(updateRect);
522 Primitive p(PrimitiveCmd::Refresh, updateRect);
530 primitivesExecutionWait();
532 m_spriteSize = spriteSize;
533 m_spritesCount = count;
537 uint8_t * spritePtr = (uint8_t*)m_sprites;
538 for (
int i = 0; i < m_spritesCount; ++i, spritePtr += m_spriteSize) {
540 int reqBackBufferSize = 0;
541 for (
int i = 0; i < sprite->framesCount; ++i)
542 reqBackBufferSize = tmax(reqBackBufferSize, sprite->frames[i]->
width * getBitmapSavePixelSize() * sprite->frames[i]->
height);
543 if (reqBackBufferSize > 0)
544 sprite->savedBackground = (uint8_t*) realloc(sprite->savedBackground, reqBackBufferSize);
550 Sprite * IRAM_ATTR BitmappedDisplayController::getSprite(
int index)
552 return (Sprite*) ((uint8_t*)m_sprites + index * m_spriteSize);
558 Primitive p(PrimitiveCmd::RefreshSprites);
563 void IRAM_ATTR BitmappedDisplayController::hideSprites(
Rect & updateRect)
565 if (!m_spritesHidden) {
566 m_spritesHidden =
true;
571 for (
int i = spritesCount() - 1; i >= 0; --i) {
572 Sprite * sprite = getSprite(i);
573 if (sprite->allowDraw && sprite->savedBackgroundWidth > 0) {
574 int savedX = sprite->savedX;
575 int savedY = sprite->savedY;
576 int savedWidth = sprite->savedBackgroundWidth;
577 int savedHeight = sprite->savedBackgroundHeight;
579 absDrawBitmap(savedX, savedY, &bitmap,
nullptr,
true);
580 updateRect = updateRect.merge(
Rect(savedX, savedY, savedX + savedWidth - 1, savedY + savedHeight - 1));
581 sprite->savedBackgroundWidth = sprite->savedBackgroundHeight = 0;
587 Sprite * mouseSprite = mouseCursor();
588 if (mouseSprite->savedBackgroundWidth > 0) {
589 int savedX = mouseSprite->savedX;
590 int savedY = mouseSprite->savedY;
591 int savedWidth = mouseSprite->savedBackgroundWidth;
592 int savedHeight = mouseSprite->savedBackgroundHeight;
594 absDrawBitmap(savedX, savedY, &bitmap,
nullptr,
true);
595 updateRect = updateRect.merge(Rect(savedX, savedY, savedX + savedWidth - 1, savedY + savedHeight - 1));
596 mouseSprite->savedBackgroundWidth = mouseSprite->savedBackgroundHeight = 0;
603 void IRAM_ATTR BitmappedDisplayController::showSprites(Rect & updateRect)
605 if (m_spritesHidden) {
606 m_spritesHidden =
false;
610 for (
int i = 0; i < spritesCount(); ++i) {
611 Sprite * sprite = getSprite(i);
612 if (sprite->visible && sprite->allowDraw && sprite->getFrame()) {
614 int spriteX = sprite->x;
615 int spriteY = sprite->y;
616 Bitmap
const * bitmap = sprite->getFrame();
617 int bitmapWidth = bitmap->width;
618 int bitmapHeight = bitmap->height;
619 absDrawBitmap(spriteX, spriteY, bitmap, sprite->savedBackground,
true);
620 sprite->savedX = spriteX;
621 sprite->savedY = spriteY;
622 sprite->savedBackgroundWidth = bitmapWidth;
623 sprite->savedBackgroundHeight = bitmapHeight;
624 if (sprite->isStatic)
625 sprite->allowDraw =
false;
626 updateRect = updateRect.merge(Rect(spriteX, spriteY, spriteX + bitmapWidth - 1, spriteY + bitmapHeight - 1));
632 Sprite * mouseSprite = mouseCursor();
633 if (mouseSprite->visible && mouseSprite->getFrame()) {
635 int spriteX = mouseSprite->x;
636 int spriteY = mouseSprite->y;
637 Bitmap
const * bitmap = mouseSprite->getFrame();
638 int bitmapWidth = bitmap->width;
639 int bitmapHeight = bitmap->height;
640 absDrawBitmap(spriteX, spriteY, bitmap, mouseSprite->savedBackground,
true);
641 mouseSprite->savedX = spriteX;
642 mouseSprite->savedY = spriteY;
643 mouseSprite->savedBackgroundWidth = bitmapWidth;
644 mouseSprite->savedBackgroundHeight = bitmapHeight;
645 updateRect = updateRect.merge(Rect(spriteX, spriteY, spriteX + bitmapWidth - 1, spriteY + bitmapHeight - 1));
655 if (cursor ==
nullptr || &cursor->
bitmap != m_mouseCursor.getFrame()) {
656 m_mouseCursor.visible =
false;
657 m_mouseCursor.clearBitmaps();
661 primitivesExecutionWait();
664 m_mouseCursor.moveBy(+m_mouseHotspotX, +m_mouseHotspotY);
667 m_mouseCursor.addBitmap(&cursor->
bitmap);
668 m_mouseCursor.visible =
true;
669 m_mouseCursor.moveBy(-m_mouseHotspotX, -m_mouseHotspotY);
671 m_mouseCursor.savedBackground = (uint8_t*) realloc(m_mouseCursor.savedBackground, cursor->
bitmap.
width * getBitmapSavePixelSize() * cursor->
bitmap.
height);
686 m_mouseCursor.moveTo(
X - m_mouseHotspotX,
Y - m_mouseHotspotY);
691 void IRAM_ATTR BitmappedDisplayController::execPrimitive(Primitive
const & prim,
Rect & updateRect,
bool insideISR)
694 case PrimitiveCmd::Flush:
696 case PrimitiveCmd::Refresh:
697 updateRect = updateRect.merge(prim.rect);
699 case PrimitiveCmd::Reset:
702 case PrimitiveCmd::SetPenColor:
703 paintState().penColor = prim.color;
705 case PrimitiveCmd::SetBrushColor:
706 paintState().brushColor = prim.color;
708 case PrimitiveCmd::SetPixel:
709 setPixelAt( (PixelDesc) { prim.position, getActualPenColor() }, updateRect );
711 case PrimitiveCmd::SetPixelAt:
712 setPixelAt(prim.pixelDesc, updateRect);
714 case PrimitiveCmd::MoveTo:
715 paintState().position = Point(prim.position.X + paintState().origin.X, prim.position.Y + paintState().origin.Y);
717 case PrimitiveCmd::LineTo:
718 lineTo(prim.position, updateRect);
720 case PrimitiveCmd::FillRect:
721 fillRect(prim.rect, getActualBrushColor(), updateRect);
723 case PrimitiveCmd::DrawRect:
724 drawRect(prim.rect, updateRect);
726 case PrimitiveCmd::FillEllipse:
727 fillEllipse(paintState().position.X, paintState().position.Y, prim.size, getActualBrushColor(), updateRect);
729 case PrimitiveCmd::DrawEllipse:
730 drawEllipse(prim.size, updateRect);
732 case PrimitiveCmd::Clear:
736 case PrimitiveCmd::VScroll:
737 updateRect = updateRect.merge(Rect(paintState().scrollingRegion.X1, paintState().scrollingRegion.Y1, paintState().scrollingRegion.X2, paintState().scrollingRegion.Y2));
738 VScroll(prim.ivalue, updateRect);
740 case PrimitiveCmd::HScroll:
741 updateRect = updateRect.merge(Rect(paintState().scrollingRegion.X1, paintState().scrollingRegion.Y1, paintState().scrollingRegion.X2, paintState().scrollingRegion.Y2));
742 HScroll(prim.ivalue, updateRect);
744 case PrimitiveCmd::DrawGlyph:
745 drawGlyph(prim.glyph, paintState().glyphOptions, paintState().penColor, paintState().brushColor, updateRect);
747 case PrimitiveCmd::SetGlyphOptions:
748 paintState().glyphOptions = prim.glyphOptions;
750 case PrimitiveCmd::SetPaintOptions:
751 paintState().paintOptions = prim.paintOptions;
753 case PrimitiveCmd::InvertRect:
754 invertRect(prim.rect, updateRect);
756 case PrimitiveCmd::CopyRect:
757 copyRect(prim.rect, updateRect);
759 case PrimitiveCmd::SetScrollingRegion:
760 paintState().scrollingRegion = prim.rect;
762 case PrimitiveCmd::SwapFGBG:
763 swapFGBG(prim.rect, updateRect);
765 case PrimitiveCmd::RenderGlyphsBuffer:
766 renderGlyphsBuffer(prim.glyphsBufferRenderInfo, updateRect);
768 case PrimitiveCmd::DrawBitmap:
769 drawBitmap(prim.bitmapDrawingInfo, updateRect);
771 case PrimitiveCmd::RefreshSprites:
772 hideSprites(updateRect);
773 showSprites(updateRect);
775 case PrimitiveCmd::SwapBuffers:
779 vTaskNotifyGiveFromISR(prim.notifyTask,
nullptr);
781 xTaskNotifyGive(prim.notifyTask);
783 case PrimitiveCmd::DrawPath:
784 drawPath(prim.path, updateRect);
786 case PrimitiveCmd::FillPath:
787 fillPath(prim.path, getActualBrushColor(), updateRect);
789 case PrimitiveCmd::SetOrigin:
790 paintState().origin = prim.position;
791 updateAbsoluteClippingRect();
793 case PrimitiveCmd::SetClippingRect:
794 paintState().clippingRect = prim.rect;
795 updateAbsoluteClippingRect();
797 case PrimitiveCmd::SetPenWidth:
798 paintState().penWidth = imax(1, prim.ivalue);
800 case PrimitiveCmd::SetLineEnds:
801 paintState().lineEnds = prim.lineEnds;
807 RGB888 IRAM_ATTR BitmappedDisplayController::getActualBrushColor()
809 return paintState().paintOptions.swapFGBG ? paintState().penColor : paintState().brushColor;
813 RGB888 IRAM_ATTR BitmappedDisplayController::getActualPenColor()
815 return paintState().paintOptions.swapFGBG ? paintState().brushColor : paintState().penColor;
819 void IRAM_ATTR BitmappedDisplayController::lineTo(Point
const & position, Rect & updateRect)
821 RGB888 color = getActualPenColor();
823 int origX = paintState().origin.X;
824 int origY = paintState().origin.Y;
825 int x1 = paintState().position.X;
826 int y1 = paintState().position.Y;
827 int x2 = position.X + origX;
828 int y2 = position.Y + origY;
830 int hw = paintState().penWidth / 2;
831 updateRect = updateRect.merge(Rect(imin(x1, x2) - hw, imin(y1, y2) - hw, imax(x1, x2) + hw, imax(y1, y2) + hw));
832 hideSprites(updateRect);
833 absDrawLine(x1, y1, x2, y2, color);
835 paintState().position = Point(x2, y2);
839 void IRAM_ATTR BitmappedDisplayController::updateAbsoluteClippingRect()
841 int X1 = iclamp(paintState().origin.X + paintState().clippingRect.X1, 0,
getViewPortWidth() - 1);
842 int Y1 = iclamp(paintState().origin.Y + paintState().clippingRect.Y1, 0,
getViewPortHeight() - 1);
843 int X2 = iclamp(paintState().origin.X + paintState().clippingRect.X2, 0,
getViewPortWidth() - 1);
844 int Y2 = iclamp(paintState().origin.Y + paintState().clippingRect.Y2, 0,
getViewPortHeight() - 1);
845 paintState().absClippingRect = Rect(
X1,
Y1,
X2,
Y2);
849 void IRAM_ATTR BitmappedDisplayController::drawRect(Rect
const & rect, Rect & updateRect)
851 int x1 = (rect.X1 < rect.X2 ? rect.X1 : rect.X2) + paintState().origin.X;
852 int y1 = (rect.Y1 < rect.Y2 ? rect.Y1 : rect.Y2) + paintState().origin.Y;
853 int x2 = (rect.X1 < rect.X2 ? rect.X2 : rect.X1) + paintState().origin.X;
854 int y2 = (rect.Y1 < rect.Y2 ? rect.Y2 : rect.Y1) + paintState().origin.Y;
856 int hw = paintState().penWidth / 2;
857 updateRect = updateRect.merge(Rect(x1 - hw, y1 - hw, x2 + hw, y2 + hw));
858 hideSprites(updateRect);
859 RGB888 color = getActualPenColor();
861 absDrawLine(x1 + 1, y1, x2, y1, color);
862 absDrawLine(x2, y1 + 1, x2, y2, color);
863 absDrawLine(x2 - 1, y2, x1, y2, color);
864 absDrawLine(x1, y2 - 1, x1, y1, color);
868 void IRAM_ATTR BitmappedDisplayController::fillRect(Rect
const & rect, RGB888
const & color, Rect & updateRect)
870 int x1 = (rect.X1 < rect.X2 ? rect.X1 : rect.X2) + paintState().origin.X;
871 int y1 = (rect.Y1 < rect.Y2 ? rect.Y1 : rect.Y2) + paintState().origin.Y;
872 int x2 = (rect.X1 < rect.X2 ? rect.X2 : rect.X1) + paintState().origin.X;
873 int y2 = (rect.Y1 < rect.Y2 ? rect.Y2 : rect.Y1) + paintState().origin.Y;
875 const int clipX1 = paintState().absClippingRect.X1;
876 const int clipY1 = paintState().absClippingRect.Y1;
877 const int clipX2 = paintState().absClippingRect.X2;
878 const int clipY2 = paintState().absClippingRect.Y2;
880 if (x1 > clipX2 || x2 < clipX1 || y1 > clipY2 || y2 < clipY1)
883 x1 = iclamp(x1, clipX1, clipX2);
884 y1 = iclamp(y1, clipY1, clipY2);
885 x2 = iclamp(x2, clipX1, clipX2);
886 y2 = iclamp(y2, clipY1, clipY2);
888 updateRect = updateRect.merge(Rect(x1, y1, x2, y2));
889 hideSprites(updateRect);
891 for (
int y = y1; y <= y2; ++y)
892 rawFillRow(y, x1, x2, color);
897 void IRAM_ATTR BitmappedDisplayController::fillEllipse(
int centerX,
int centerY, Size
const & size, RGB888
const & color, Rect & updateRect)
899 const int clipX1 = paintState().absClippingRect.X1;
900 const int clipY1 = paintState().absClippingRect.Y1;
901 const int clipX2 = paintState().absClippingRect.X2;
902 const int clipY2 = paintState().absClippingRect.Y2;
904 const int halfWidth = size.width / 2;
905 const int halfHeight = size.height / 2;
907 updateRect = updateRect.merge(Rect(centerX - halfWidth, centerY - halfHeight, centerX + halfWidth, centerY + halfHeight));
908 hideSprites(updateRect);
910 const int a2 = halfWidth * halfWidth;
911 const int b2 = halfHeight * halfHeight;
912 const int crit1 = -(a2 / 4 + halfWidth % 2 + b2);
913 const int crit2 = -(b2 / 4 + halfHeight % 2 + a2);
914 const int crit3 = -(b2 / 4 + halfHeight % 2);
915 const int d2xt = 2 * b2;
916 const int d2yt = 2 * a2;
921 int dxt = 2 * b2 * x;
922 int dyt = -2 * a2 * y;
924 while (y >= 0 && x <= halfWidth) {
925 if (t + b2 * x <= crit1 || t + a2 * y <= crit3) {
931 int col1 = centerX - x;
932 int col2 = centerX - x +
width - 1;
933 if (col1 <= clipX2 && col2 >= clipX1) {
934 col1 = iclamp(col1, clipX1, clipX2);
935 col2 = iclamp(col2, clipX1, clipX2);
936 int row1 = centerY - y;
937 int row2 = centerY + y;
938 if (row1 >= clipY1 && row1 <= clipY2)
939 rawFillRow(row1, col1, col2, color);
940 if (y != 0 && row2 >= clipY1 && row2 <= clipY2)
941 rawFillRow(row2, col1, col2, color);
943 if (t - a2 * y <= crit2) {
955 if (halfHeight == 0 && centerY >= clipY1 && centerY <= clipY2)
956 rawFillRow(centerY, iclamp(centerX - halfWidth, clipX1, clipX2), iclamp(centerX - halfWidth + 2 * halfWidth + 1, clipX1, clipX2), color);
960 void IRAM_ATTR BitmappedDisplayController::renderGlyphsBuffer(GlyphsBufferRenderInfo
const & glyphsBufferRenderInfo, Rect & updateRect)
962 int itemX = glyphsBufferRenderInfo.itemX;
963 int itemY = glyphsBufferRenderInfo.itemY;
965 int glyphsWidth = glyphsBufferRenderInfo.glyphsBuffer->glyphsWidth;
966 int glyphsHeight = glyphsBufferRenderInfo.glyphsBuffer->glyphsHeight;
968 uint32_t
const * mapItem = glyphsBufferRenderInfo.glyphsBuffer->map + itemX + itemY * glyphsBufferRenderInfo.glyphsBuffer->columns;
970 GlyphOptions glyphOptions = glyphMapItem_getOptions(mapItem);
971 auto fgColor = glyphMapItem_getFGColor(mapItem);
972 auto bgColor = glyphMapItem_getBGColor(mapItem);
975 glyph.X = (int16_t) (itemX * glyphsWidth * (glyphOptions.doubleWidth ? 2 : 1));
976 glyph.Y = (int16_t) (itemY * glyphsHeight);
977 glyph.width = glyphsWidth;
978 glyph.height = glyphsHeight;
979 glyph.data = glyphsBufferRenderInfo.glyphsBuffer->glyphsData + glyphMapItem_getIndex(mapItem) * glyphsHeight * ((glyphsWidth + 7) / 8);;
981 drawGlyph(glyph, glyphOptions, fgColor, bgColor, updateRect);
985 void IRAM_ATTR BitmappedDisplayController::drawPath(Path
const & path, Rect & updateRect)
987 RGB888 color = getActualPenColor();
989 const int clipX1 = paintState().absClippingRect.X1;
990 const int clipY1 = paintState().absClippingRect.Y1;
991 const int clipX2 = paintState().absClippingRect.X2;
992 const int clipY2 = paintState().absClippingRect.Y2;
994 int origX = paintState().origin.X;
995 int origY = paintState().origin.Y;
998 int maxX = clipX2 + 1;
1001 for (
int i = 0; i < path.pointsCount; ++i) {
1002 int py = path.points[i].Y + origY;
1008 minY = tmax(clipY1, minY);
1009 maxY = tmin(clipY2, maxY);
1011 int hw = paintState().penWidth / 2;
1012 updateRect = updateRect.merge(Rect(minX - hw, minY - hw, maxX + hw, maxY + hw));
1013 hideSprites(updateRect);
1016 for (; i < path.pointsCount - 1; ++i) {
1017 const int x1 = path.points[i].X + origX;
1018 const int y1 = path.points[i].Y + origY;
1019 const int x2 = path.points[i + 1].X + origX;
1020 const int y2 = path.points[i + 1].Y + origY;
1021 absDrawLine(x1, y1, x2, y2, color);
1023 const int x1 = path.points[i].X + origX;
1024 const int y1 = path.points[i].Y + origY;
1025 const int x2 = path.points[0].X + origX;
1026 const int y2 = path.points[0].Y + origY;
1027 absDrawLine(x1, y1, x2, y2, color);
1029 if (path.freePoints)
1030 m_primDynMemPool.free((
void*)path.points);
1034 void IRAM_ATTR BitmappedDisplayController::fillPath(Path
const & path, RGB888
const & color, Rect & updateRect)
1036 const int clipX1 = paintState().absClippingRect.X1;
1037 const int clipY1 = paintState().absClippingRect.Y1;
1038 const int clipX2 = paintState().absClippingRect.X2;
1039 const int clipY2 = paintState().absClippingRect.Y2;
1041 const int origX = paintState().origin.X;
1042 const int origY = paintState().origin.Y;
1045 int maxX = clipX2 + 1;
1048 for (
int i = 0; i < path.pointsCount; ++i) {
1049 int py = path.points[i].Y + origY;
1055 minY = tmax(clipY1, minY);
1056 maxY = tmin(clipY2, maxY);
1058 updateRect = updateRect.merge(Rect(minX, minY, maxX, maxY));
1059 hideSprites(updateRect);
1061 int16_t nodeX[path.pointsCount];
1063 for (
int pixelY = minY; pixelY <= maxY; ++pixelY) {
1066 int j = path.pointsCount - 1;
1067 for (
int i = 0; i < path.pointsCount; ++i) {
1068 int piy = path.points[i].Y + origY;
1069 int pjy = path.points[j].Y + origY;
1070 if ((piy < pixelY && pjy >= pixelY) || (pjy < pixelY && piy >= pixelY)) {
1071 int pjx = path.points[j].X + origX;
1072 int pix = path.points[i].X + origX;
1073 int a = (pixelY - piy) * (pjx - pix);
1074 int b = (pjy - piy);
1075 nodeX[nodes++] = pix + a / b + (((a < 0) ^ (b > 0)) && (a % b));
1081 while (i < nodes - 1) {
1082 if (nodeX[i] > nodeX[i + 1]) {
1083 tswap(nodeX[i], nodeX[i + 1]);
1090 for (
int i = 0; i < nodes; i += 2) {
1091 if (nodeX[i] >= maxX)
1093 if (nodeX[i + 1] > minX) {
1094 if (nodeX[i] < minX)
1096 if (nodeX[i + 1] > maxX)
1097 nodeX[i + 1] = maxX;
1098 rawFillRow(pixelY, nodeX[i], nodeX[i + 1] - 1, color);
1103 if (path.freePoints)
1104 m_primDynMemPool.free((
void*)path.points);
1108 void IRAM_ATTR BitmappedDisplayController::absDrawThickLine(
int X1,
int Y1,
int X2,
int Y2,
int penWidth, RGB888
const & color)
1111 const int origX = paintState().origin.X;
1112 const int origY = paintState().origin.Y;
1120 const double angle = atan2(
Y2 -
Y1,
X2 -
X1);
1121 const double pw = (double)penWidth / 2.0;
1122 const int ofs1 = lround(pw * cos(angle + M_PI_2));
1123 const int ofs2 = lround(pw * sin(angle + M_PI_2));
1124 const int ofs3 = lround(pw * cos(angle - M_PI_2));
1125 const int ofs4 = lround(pw * sin(angle - M_PI_2));
1126 pts[0].X =
X1 + ofs1;
1127 pts[0].Y =
Y1 + ofs2;
1128 pts[1].X =
X1 + ofs3;
1129 pts[1].Y =
Y1 + ofs4;
1130 pts[2].X =
X2 + ofs3;
1131 pts[2].Y =
Y2 + ofs4;
1132 pts[3].X =
X2 + ofs1;
1133 pts[3].Y =
Y2 + ofs2;
1136 Path path = { pts, 4,
false };
1137 fillPath(path, color, updateRect);
1139 switch (paintState().lineEnds) {
1141 if ((penWidth & 1) == 0)
1143 fillEllipse(
X1,
Y1, Size(penWidth, penWidth), color, updateRect);
1144 fillEllipse(
X2,
Y2, Size(penWidth, penWidth), color, updateRect);
1152 void IRAM_ATTR BitmappedDisplayController::drawBitmap(BitmapDrawingInfo
const & bitmapDrawingInfo, Rect & updateRect)
1154 int x = bitmapDrawingInfo.X + paintState().origin.X;
1155 int y = bitmapDrawingInfo.Y + paintState().origin.Y;
1156 updateRect = updateRect.merge(Rect(x, y, x + bitmapDrawingInfo.bitmap->width - 1, y + bitmapDrawingInfo.bitmap->height - 1));
1157 hideSprites(updateRect);
1158 absDrawBitmap(x, y, bitmapDrawingInfo.bitmap,
nullptr,
false);
1162 void IRAM_ATTR BitmappedDisplayController::absDrawBitmap(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
bool ignoreClippingRect)
1164 const int clipX1 = ignoreClippingRect ? 0 : paintState().absClippingRect.X1;
1165 const int clipY1 = ignoreClippingRect ? 0 : paintState().absClippingRect.Y1;
1166 const int clipX2 = ignoreClippingRect ?
getViewPortWidth() - 1 : paintState().absClippingRect.X2;
1167 const int clipY2 = ignoreClippingRect ?
getViewPortHeight() - 1 : paintState().absClippingRect.Y2;
1169 if (destX > clipX2 || destY > clipY2)
1172 int width = bitmap->width;
1173 int height = bitmap->height;
1178 if (destX < clipX1) {
1179 X1 = clipX1 - destX;
1185 if (destX + XCount > clipX2 + 1)
1186 XCount = clipX2 + 1 - destX;
1193 if (destY < clipY1) {
1194 Y1 = clipY1 - destY;
1200 if (destY + YCount > clipY2 + 1)
1201 YCount = clipY2 + 1 - destY;
1205 switch (bitmap->format) {
1211 rawDrawBitmap_Native(destX, destY, bitmap,
X1,
Y1, XCount, YCount);
1215 rawDrawBitmap_Mask(destX, destY, bitmap, saveBackground,
X1,
Y1, XCount, YCount);
1219 rawDrawBitmap_RGBA2222(destX, destY, bitmap, saveBackground,
X1,
Y1, XCount, YCount);
1223 rawDrawBitmap_RGBA8888(destX, destY, bitmap, saveBackground,
X1,
Y1, XCount, YCount);
void setSprites(T *sprites, int count)
Sets the list of active sprites.
virtual void resumeBackgroundPrimitiveExecution()=0
Resumes drawings after suspendBackgroundPrimitiveExecution().
This file contains fabgl::BitmappedDisplayController definition.
Color
This enum defines named colors.
virtual int getViewPortWidth()=0
Determines horizontal size of the viewport.
virtual int getViewPortHeight()=0
Determines vertical size of the viewport.
PixelFormat
This enum defines a pixel format.
void refreshSprites()
Forces the sprites to be updated.
This file contains some utility classes and functions.
void enableBackgroundPrimitiveExecution(bool value)
Enables or disables drawings inside vertical retracing time.
CursorName
This enum defines a set of predefined mouse cursors.
void setMouseCursor(Cursor *cursor)
Sets mouse cursor and make it visible.
static int queueSize
Size of display controller primitives queue.
virtual void suspendBackgroundPrimitiveExecution()=0
Suspends drawings.
void setMouseCursorPos(int X, int Y)
Sets mouse cursor position.
void processPrimitives()
Draws immediately all primitives in the queue.
bool isDoubleBuffered()
Determines whether BitmappedDisplayController is on double buffered mode.