34 #include "freertos/task.h" 37 #include "images/cursors.h" 40 #pragma GCC optimize ("O2") 49 const RGB888 COLOR2RGB888[16] = {
74 bool RGB222::lowBitOnly =
false;
81 RGB222::RGB222(RGB888
const & value)
101 RGB888::RGB888(
Color color)
103 *
this = COLOR2RGB888[(int)color];
112 uint8_t RGB888toPackedRGB222(RGB888
const & rgb)
115 static const int CONVR64[4] = { 0 << 0,
119 static const int CONVG64[4] = { 0 << 2,
123 static const int CONVB64[4] = { 0 << 4,
128 static const int CONVR8[4] = { 0 << 0,
132 static const int CONVG8[4] = { 0 << 2,
136 static const int CONVB8[4] = { 0 << 4,
141 if (RGB222::lowBitOnly)
142 return (CONVR8[rgb.R >> 6]) | (CONVG8[rgb.G >> 6]) | (CONVB8[rgb.B >> 6]);
144 return (CONVR64[rgb.R >> 6]) | (CONVG64[rgb.G >> 6]) | (CONVB64[rgb.B >> 6]);
161 savedBackgroundWidth = 0;
162 savedBackgroundHeight = 0;
163 savedBackground =
nullptr;
166 collisionDetectorObject =
nullptr;
176 free(savedBackground);
180 void Sprite::clearBitmaps()
188 Sprite * Sprite::addBitmap(Bitmap * bitmap)
191 frames = (Bitmap**) realloc(frames,
sizeof(Bitmap*) * framesCount);
192 frames[framesCount - 1] = bitmap;
197 Sprite * Sprite::addBitmap(Bitmap * bitmap[],
int count)
199 frames = (Bitmap**) realloc(frames,
sizeof(Bitmap*) * (framesCount + count));
200 for (
int i = 0; i < count; ++i)
201 frames[framesCount + i] = bitmap[i];
202 framesCount += count;
207 Sprite * Sprite::moveBy(
int offsetX,
int offsetY)
215 Sprite * Sprite::moveBy(
int offsetX,
int offsetY,
int wrapAroundWidth,
int wrapAroundHeight)
219 if (x > wrapAroundWidth)
220 x = - (int) getWidth();
221 if (x < - (
int) getWidth())
223 if (y > wrapAroundHeight)
224 y = - (int) getHeight();
225 if (y < - (
int) getHeight())
226 y = wrapAroundHeight;
231 Sprite * Sprite::moveTo(
int x,
int y)
246 Bitmap::Bitmap(
int width_,
int height_,
void const * data_,
PixelFormat format_, RGB888 foregroundColor_,
bool copy)
250 foregroundColor(foregroundColor_),
251 data((uint8_t*)data_),
261 Bitmap::Bitmap(
int width_,
int height_,
void const * data_,
PixelFormat format_,
bool copy)
262 : Bitmap(width_, height_, data_, format_, RGB888(255, 255, 255), copy)
267 void Bitmap::allocate()
279 data = (uint8_t*) heap_caps_malloc((
width + 7) / 8 *
height, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
282 data = (uint8_t*) heap_caps_malloc(
width *
height, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
285 data = (uint8_t*) heap_caps_malloc(
width *
height * 4, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
292 void Bitmap::copyFrom(
void const * srcData)
311 void Bitmap::setPixel(
int x,
int y,
int value)
313 int rowlen = (
width + 7) / 8;
314 uint8_t * rowptr =
data + y * rowlen;
316 rowptr[x >> 3] |= 0x80 >> (x & 7);
318 rowptr[x >> 3] &= ~(0x80 >> (x & 7));
322 void Bitmap::setPixel(
int x,
int y,
RGBA2222 value)
328 void Bitmap::setPixel(
int x,
int y,
RGBA8888 value)
334 int Bitmap::getAlpha(
int x,
int y)
345 int rowlen = (
width + 7) / 8;
346 uint8_t * rowptr =
data + y * rowlen;
347 r = (rowptr[x >> 3] >> (7 - (x & 7))) & 1;
364 heap_caps_free((
void*)
data);
377 BitmappedDisplayController::BitmappedDisplayController()
380 m_execQueue =
nullptr;
381 m_backgroundPrimitiveExecutionEnabled =
true;
384 m_doubleBuffered =
false;
385 m_mouseCursor.visible =
false;
386 m_backgroundPrimitiveTimeoutEnabled =
true;
387 m_spritesHidden =
true;
391 BitmappedDisplayController::~BitmappedDisplayController()
393 vQueueDelete(m_execQueue);
397 void BitmappedDisplayController::setDoubleBuffered(
bool value)
399 m_doubleBuffered = value;
401 vQueueDelete(m_execQueue);
407 void IRAM_ATTR BitmappedDisplayController::resetPaintState()
409 m_paintState.penColor = RGB888(255, 255, 255);
410 m_paintState.brushColor = RGB888(0, 0, 0);
411 m_paintState.position = Point(0, 0);
412 m_paintState.glyphOptions.value = 0;
413 m_paintState.paintOptions = PaintOptions();
415 m_paintState.origin = Point(0, 0);
417 m_paintState.absClippingRect = m_paintState.clippingRect;
418 m_paintState.penWidth = 1;
423 void BitmappedDisplayController::addPrimitive(Primitive & primitive)
425 if ((m_backgroundPrimitiveExecutionEnabled && m_doubleBuffered ==
false) || primitive.cmd == PrimitiveCmd::SwapBuffers) {
426 primitiveReplaceDynamicBuffers(primitive);
427 xQueueSendToBack(m_execQueue, &primitive, portMAX_DELAY);
429 if (m_doubleBuffered) {
431 ulTaskNotifyTake(
true, portMAX_DELAY);
435 Rect updateRect = Rect(SHRT_MAX, SHRT_MAX, SHRT_MIN, SHRT_MIN);
436 execPrimitive(primitive, updateRect,
false);
437 showSprites(updateRect);
445 void BitmappedDisplayController::primitiveReplaceDynamicBuffers(Primitive & primitive)
447 switch (primitive.cmd) {
448 case PrimitiveCmd::DrawPath:
449 case PrimitiveCmd::FillPath:
451 int sz = primitive.path.pointsCount *
sizeof(Point);
453 void * newbuf =
nullptr;
455 while ((newbuf = m_primDynMemPool.alloc(sz)) ==
nullptr)
457 memcpy(newbuf, primitive.path.points, sz);
458 primitive.path.points = (Point*)newbuf;
459 primitive.path.freePoints =
true;
471 bool IRAM_ATTR BitmappedDisplayController::getPrimitiveISR(Primitive * primitive)
473 return xQueueReceiveFromISR(m_execQueue, primitive,
nullptr);
477 bool BitmappedDisplayController::getPrimitive(Primitive * primitive,
int timeOutMS)
479 return xQueueReceive(m_execQueue, primitive, msToTicks(timeOutMS));
484 void BitmappedDisplayController::waitForPrimitives()
487 xQueuePeek(m_execQueue, &p, portMAX_DELAY);
491 void BitmappedDisplayController::primitivesExecutionWait()
493 if (m_backgroundPrimitiveExecutionEnabled) {
494 while (uxQueueMessagesWaiting(m_execQueue) > 0)
505 if (value != m_backgroundPrimitiveExecutionEnabled) {
512 m_backgroundPrimitiveExecutionEnabled = value;
522 Rect updateRect =
Rect(SHRT_MAX, SHRT_MAX, SHRT_MIN, SHRT_MIN);
524 while (xQueueReceive(m_execQueue, &prim, 0) == pdTRUE)
525 execPrimitive(prim, updateRect,
false);
526 showSprites(updateRect);
528 Primitive p(PrimitiveCmd::Refresh, updateRect);
536 primitivesExecutionWait();
538 m_spriteSize = spriteSize;
539 m_spritesCount = count;
543 uint8_t * spritePtr = (uint8_t*)m_sprites;
544 for (
int i = 0; i < m_spritesCount; ++i, spritePtr += m_spriteSize) {
546 int reqBackBufferSize = 0;
547 for (
int i = 0; i < sprite->framesCount; ++i)
548 reqBackBufferSize = tmax(reqBackBufferSize, sprite->frames[i]->
width * getBitmapSavePixelSize() * sprite->frames[i]->
height);
549 if (reqBackBufferSize > 0)
550 sprite->savedBackground = (uint8_t*) realloc(sprite->savedBackground, reqBackBufferSize);
556 Sprite * IRAM_ATTR BitmappedDisplayController::getSprite(
int index)
558 return (Sprite*) ((uint8_t*)m_sprites + index * m_spriteSize);
564 Primitive p(PrimitiveCmd::RefreshSprites);
569 void IRAM_ATTR BitmappedDisplayController::hideSprites(
Rect & updateRect)
571 if (!m_spritesHidden) {
572 m_spritesHidden =
true;
577 for (
int i = spritesCount() - 1; i >= 0; --i) {
578 Sprite * sprite = getSprite(i);
579 if (sprite->allowDraw && sprite->savedBackgroundWidth > 0) {
580 int savedX = sprite->savedX;
581 int savedY = sprite->savedY;
582 int savedWidth = sprite->savedBackgroundWidth;
583 int savedHeight = sprite->savedBackgroundHeight;
585 absDrawBitmap(savedX, savedY, &bitmap,
nullptr,
true);
586 updateRect = updateRect.merge(
Rect(savedX, savedY, savedX + savedWidth - 1, savedY + savedHeight - 1));
587 sprite->savedBackgroundWidth = sprite->savedBackgroundHeight = 0;
593 Sprite * mouseSprite = mouseCursor();
594 if (mouseSprite->savedBackgroundWidth > 0) {
595 int savedX = mouseSprite->savedX;
596 int savedY = mouseSprite->savedY;
597 int savedWidth = mouseSprite->savedBackgroundWidth;
598 int savedHeight = mouseSprite->savedBackgroundHeight;
600 absDrawBitmap(savedX, savedY, &bitmap,
nullptr,
true);
601 updateRect = updateRect.merge(Rect(savedX, savedY, savedX + savedWidth - 1, savedY + savedHeight - 1));
602 mouseSprite->savedBackgroundWidth = mouseSprite->savedBackgroundHeight = 0;
609 void IRAM_ATTR BitmappedDisplayController::showSprites(Rect & updateRect)
611 if (m_spritesHidden) {
612 m_spritesHidden =
false;
616 for (
int i = 0; i < spritesCount(); ++i) {
617 Sprite * sprite = getSprite(i);
618 if (sprite->visible && sprite->allowDraw && sprite->getFrame()) {
620 int spriteX = sprite->x;
621 int spriteY = sprite->y;
622 Bitmap
const * bitmap = sprite->getFrame();
623 int bitmapWidth = bitmap->width;
624 int bitmapHeight = bitmap->height;
625 absDrawBitmap(spriteX, spriteY, bitmap, sprite->savedBackground,
true);
626 sprite->savedX = spriteX;
627 sprite->savedY = spriteY;
628 sprite->savedBackgroundWidth = bitmapWidth;
629 sprite->savedBackgroundHeight = bitmapHeight;
630 if (sprite->isStatic)
631 sprite->allowDraw =
false;
632 updateRect = updateRect.merge(Rect(spriteX, spriteY, spriteX + bitmapWidth - 1, spriteY + bitmapHeight - 1));
638 Sprite * mouseSprite = mouseCursor();
639 if (mouseSprite->visible && mouseSprite->getFrame()) {
641 int spriteX = mouseSprite->x;
642 int spriteY = mouseSprite->y;
643 Bitmap
const * bitmap = mouseSprite->getFrame();
644 int bitmapWidth = bitmap->width;
645 int bitmapHeight = bitmap->height;
646 absDrawBitmap(spriteX, spriteY, bitmap, mouseSprite->savedBackground,
true);
647 mouseSprite->savedX = spriteX;
648 mouseSprite->savedY = spriteY;
649 mouseSprite->savedBackgroundWidth = bitmapWidth;
650 mouseSprite->savedBackgroundHeight = bitmapHeight;
651 updateRect = updateRect.merge(Rect(spriteX, spriteY, spriteX + bitmapWidth - 1, spriteY + bitmapHeight - 1));
661 if (cursor ==
nullptr || &cursor->
bitmap != m_mouseCursor.getFrame()) {
662 m_mouseCursor.visible =
false;
663 m_mouseCursor.clearBitmaps();
667 primitivesExecutionWait();
670 m_mouseCursor.moveBy(+m_mouseHotspotX, +m_mouseHotspotY);
673 m_mouseCursor.addBitmap(&cursor->
bitmap);
674 m_mouseCursor.visible =
true;
675 m_mouseCursor.moveBy(-m_mouseHotspotX, -m_mouseHotspotY);
677 m_mouseCursor.savedBackground = (uint8_t*) realloc(m_mouseCursor.savedBackground, cursor->
bitmap.
width * getBitmapSavePixelSize() * cursor->
bitmap.
height);
692 m_mouseCursor.moveTo(
X - m_mouseHotspotX,
Y - m_mouseHotspotY);
697 void IRAM_ATTR BitmappedDisplayController::execPrimitive(Primitive
const & prim,
Rect & updateRect,
bool insideISR)
700 case PrimitiveCmd::Flush:
702 case PrimitiveCmd::Refresh:
703 updateRect = updateRect.merge(prim.rect);
705 case PrimitiveCmd::Reset:
708 case PrimitiveCmd::SetPenColor:
709 paintState().penColor = prim.color;
711 case PrimitiveCmd::SetBrushColor:
712 paintState().brushColor = prim.color;
714 case PrimitiveCmd::SetPixel:
715 setPixelAt( (PixelDesc) { prim.position, getActualPenColor() }, updateRect );
717 case PrimitiveCmd::SetPixelAt:
718 setPixelAt(prim.pixelDesc, updateRect);
720 case PrimitiveCmd::MoveTo:
721 paintState().position = Point(prim.position.X + paintState().origin.X, prim.position.Y + paintState().origin.Y);
723 case PrimitiveCmd::LineTo:
724 lineTo(prim.position, updateRect);
726 case PrimitiveCmd::FillRect:
727 fillRect(prim.rect, getActualBrushColor(), updateRect);
729 case PrimitiveCmd::DrawRect:
730 drawRect(prim.rect, updateRect);
732 case PrimitiveCmd::FillEllipse:
733 fillEllipse(paintState().position.X, paintState().position.Y, prim.size, getActualBrushColor(), updateRect);
735 case PrimitiveCmd::DrawEllipse:
736 drawEllipse(prim.size, updateRect);
738 case PrimitiveCmd::Clear:
742 case PrimitiveCmd::VScroll:
743 updateRect = updateRect.merge(Rect(paintState().scrollingRegion.X1, paintState().scrollingRegion.Y1, paintState().scrollingRegion.X2, paintState().scrollingRegion.Y2));
744 VScroll(prim.ivalue, updateRect);
746 case PrimitiveCmd::HScroll:
747 updateRect = updateRect.merge(Rect(paintState().scrollingRegion.X1, paintState().scrollingRegion.Y1, paintState().scrollingRegion.X2, paintState().scrollingRegion.Y2));
748 HScroll(prim.ivalue, updateRect);
750 case PrimitiveCmd::DrawGlyph:
751 drawGlyph(prim.glyph, paintState().glyphOptions, paintState().penColor, paintState().brushColor, updateRect);
753 case PrimitiveCmd::SetGlyphOptions:
754 paintState().glyphOptions = prim.glyphOptions;
756 case PrimitiveCmd::SetPaintOptions:
757 paintState().paintOptions = prim.paintOptions;
759 case PrimitiveCmd::InvertRect:
760 invertRect(prim.rect, updateRect);
762 case PrimitiveCmd::CopyRect:
763 copyRect(prim.rect, updateRect);
765 case PrimitiveCmd::SetScrollingRegion:
766 paintState().scrollingRegion = prim.rect;
768 case PrimitiveCmd::SwapFGBG:
769 swapFGBG(prim.rect, updateRect);
771 case PrimitiveCmd::RenderGlyphsBuffer:
772 renderGlyphsBuffer(prim.glyphsBufferRenderInfo, updateRect);
774 case PrimitiveCmd::DrawBitmap:
775 drawBitmap(prim.bitmapDrawingInfo, updateRect);
777 case PrimitiveCmd::RefreshSprites:
778 hideSprites(updateRect);
779 showSprites(updateRect);
781 case PrimitiveCmd::SwapBuffers:
785 vTaskNotifyGiveFromISR(prim.notifyTask,
nullptr);
787 xTaskNotifyGive(prim.notifyTask);
789 case PrimitiveCmd::DrawPath:
790 drawPath(prim.path, updateRect);
792 case PrimitiveCmd::FillPath:
793 fillPath(prim.path, getActualBrushColor(), updateRect);
795 case PrimitiveCmd::SetOrigin:
796 paintState().origin = prim.position;
797 updateAbsoluteClippingRect();
799 case PrimitiveCmd::SetClippingRect:
800 paintState().clippingRect = prim.rect;
801 updateAbsoluteClippingRect();
803 case PrimitiveCmd::SetPenWidth:
804 paintState().penWidth = imax(1, prim.ivalue);
806 case PrimitiveCmd::SetLineEnds:
807 paintState().lineEnds = prim.lineEnds;
813 RGB888 IRAM_ATTR BitmappedDisplayController::getActualBrushColor()
815 return paintState().paintOptions.swapFGBG ? paintState().penColor : paintState().brushColor;
819 RGB888 IRAM_ATTR BitmappedDisplayController::getActualPenColor()
821 return paintState().paintOptions.swapFGBG ? paintState().brushColor : paintState().penColor;
825 void IRAM_ATTR BitmappedDisplayController::lineTo(Point
const & position, Rect & updateRect)
827 RGB888 color = getActualPenColor();
829 int origX = paintState().origin.X;
830 int origY = paintState().origin.Y;
831 int x1 = paintState().position.X;
832 int y1 = paintState().position.Y;
833 int x2 = position.X + origX;
834 int y2 = position.Y + origY;
836 int hw = paintState().penWidth / 2;
837 updateRect = updateRect.merge(Rect(imin(x1, x2) - hw, imin(y1, y2) - hw, imax(x1, x2) + hw, imax(y1, y2) + hw));
838 hideSprites(updateRect);
839 absDrawLine(x1, y1, x2, y2, color);
841 paintState().position = Point(x2, y2);
845 void IRAM_ATTR BitmappedDisplayController::updateAbsoluteClippingRect()
847 int X1 = iclamp(paintState().origin.X + paintState().clippingRect.X1, 0,
getViewPortWidth() - 1);
848 int Y1 = iclamp(paintState().origin.Y + paintState().clippingRect.Y1, 0,
getViewPortHeight() - 1);
849 int X2 = iclamp(paintState().origin.X + paintState().clippingRect.X2, 0,
getViewPortWidth() - 1);
850 int Y2 = iclamp(paintState().origin.Y + paintState().clippingRect.Y2, 0,
getViewPortHeight() - 1);
851 paintState().absClippingRect = Rect(
X1,
Y1,
X2,
Y2);
855 void IRAM_ATTR BitmappedDisplayController::drawRect(Rect
const & rect, Rect & updateRect)
857 int x1 = (rect.X1 < rect.X2 ? rect.X1 : rect.X2) + paintState().origin.X;
858 int y1 = (rect.Y1 < rect.Y2 ? rect.Y1 : rect.Y2) + paintState().origin.Y;
859 int x2 = (rect.X1 < rect.X2 ? rect.X2 : rect.X1) + paintState().origin.X;
860 int y2 = (rect.Y1 < rect.Y2 ? rect.Y2 : rect.Y1) + paintState().origin.Y;
862 int hw = paintState().penWidth / 2;
863 updateRect = updateRect.merge(Rect(x1 - hw, y1 - hw, x2 + hw, y2 + hw));
864 hideSprites(updateRect);
865 RGB888 color = getActualPenColor();
867 absDrawLine(x1 + 1, y1, x2, y1, color);
868 absDrawLine(x2, y1 + 1, x2, y2, color);
869 absDrawLine(x2 - 1, y2, x1, y2, color);
870 absDrawLine(x1, y2 - 1, x1, y1, color);
874 void IRAM_ATTR BitmappedDisplayController::fillRect(Rect
const & rect, RGB888
const & color, Rect & updateRect)
876 int x1 = (rect.X1 < rect.X2 ? rect.X1 : rect.X2) + paintState().origin.X;
877 int y1 = (rect.Y1 < rect.Y2 ? rect.Y1 : rect.Y2) + paintState().origin.Y;
878 int x2 = (rect.X1 < rect.X2 ? rect.X2 : rect.X1) + paintState().origin.X;
879 int y2 = (rect.Y1 < rect.Y2 ? rect.Y2 : rect.Y1) + paintState().origin.Y;
881 const int clipX1 = paintState().absClippingRect.X1;
882 const int clipY1 = paintState().absClippingRect.Y1;
883 const int clipX2 = paintState().absClippingRect.X2;
884 const int clipY2 = paintState().absClippingRect.Y2;
886 if (x1 > clipX2 || x2 < clipX1 || y1 > clipY2 || y2 < clipY1)
889 x1 = iclamp(x1, clipX1, clipX2);
890 y1 = iclamp(y1, clipY1, clipY2);
891 x2 = iclamp(x2, clipX1, clipX2);
892 y2 = iclamp(y2, clipY1, clipY2);
894 updateRect = updateRect.merge(Rect(x1, y1, x2, y2));
895 hideSprites(updateRect);
897 for (
int y = y1; y <= y2; ++y)
898 rawFillRow(y, x1, x2, color);
903 void IRAM_ATTR BitmappedDisplayController::fillEllipse(
int centerX,
int centerY, Size
const & size, RGB888
const & color, Rect & updateRect)
905 const int clipX1 = paintState().absClippingRect.X1;
906 const int clipY1 = paintState().absClippingRect.Y1;
907 const int clipX2 = paintState().absClippingRect.X2;
908 const int clipY2 = paintState().absClippingRect.Y2;
910 const int halfWidth = size.width / 2;
911 const int halfHeight = size.height / 2;
913 updateRect = updateRect.merge(Rect(centerX - halfWidth, centerY - halfHeight, centerX + halfWidth, centerY + halfHeight));
914 hideSprites(updateRect);
916 const int a2 = halfWidth * halfWidth;
917 const int b2 = halfHeight * halfHeight;
918 const int crit1 = -(a2 / 4 + halfWidth % 2 + b2);
919 const int crit2 = -(b2 / 4 + halfHeight % 2 + a2);
920 const int crit3 = -(b2 / 4 + halfHeight % 2);
921 const int d2xt = 2 * b2;
922 const int d2yt = 2 * a2;
927 int dxt = 2 * b2 * x;
928 int dyt = -2 * a2 * y;
930 while (y >= 0 && x <= halfWidth) {
931 if (t + b2 * x <= crit1 || t + a2 * y <= crit3) {
937 int col1 = centerX - x;
938 int col2 = centerX - x +
width - 1;
939 if (col1 <= clipX2 && col2 >= clipX1) {
940 col1 = iclamp(col1, clipX1, clipX2);
941 col2 = iclamp(col2, clipX1, clipX2);
942 int row1 = centerY - y;
943 int row2 = centerY + y;
944 if (row1 >= clipY1 && row1 <= clipY2)
945 rawFillRow(row1, col1, col2, color);
946 if (y != 0 && row2 >= clipY1 && row2 <= clipY2)
947 rawFillRow(row2, col1, col2, color);
949 if (t - a2 * y <= crit2) {
961 if (halfHeight == 0 && centerY >= clipY1 && centerY <= clipY2)
962 rawFillRow(centerY, iclamp(centerX - halfWidth, clipX1, clipX2), iclamp(centerX - halfWidth + 2 * halfWidth + 1, clipX1, clipX2), color);
966 void IRAM_ATTR BitmappedDisplayController::renderGlyphsBuffer(GlyphsBufferRenderInfo
const & glyphsBufferRenderInfo, Rect & updateRect)
968 int itemX = glyphsBufferRenderInfo.itemX;
969 int itemY = glyphsBufferRenderInfo.itemY;
971 int glyphsWidth = glyphsBufferRenderInfo.glyphsBuffer->glyphsWidth;
972 int glyphsHeight = glyphsBufferRenderInfo.glyphsBuffer->glyphsHeight;
974 uint32_t
const * mapItem = glyphsBufferRenderInfo.glyphsBuffer->map + itemX + itemY * glyphsBufferRenderInfo.glyphsBuffer->columns;
976 GlyphOptions glyphOptions = glyphMapItem_getOptions(mapItem);
977 auto fgColor = glyphMapItem_getFGColor(mapItem);
978 auto bgColor = glyphMapItem_getBGColor(mapItem);
981 glyph.X = (int16_t) (itemX * glyphsWidth * (glyphOptions.doubleWidth ? 2 : 1));
982 glyph.Y = (int16_t) (itemY * glyphsHeight);
983 glyph.width = glyphsWidth;
984 glyph.height = glyphsHeight;
985 glyph.data = glyphsBufferRenderInfo.glyphsBuffer->glyphsData + glyphMapItem_getIndex(mapItem) * glyphsHeight * ((glyphsWidth + 7) / 8);;
987 drawGlyph(glyph, glyphOptions, fgColor, bgColor, updateRect);
991 void IRAM_ATTR BitmappedDisplayController::drawPath(Path
const & path, Rect & updateRect)
993 RGB888 color = getActualPenColor();
995 const int clipX1 = paintState().absClippingRect.X1;
996 const int clipY1 = paintState().absClippingRect.Y1;
997 const int clipX2 = paintState().absClippingRect.X2;
998 const int clipY2 = paintState().absClippingRect.Y2;
1000 int origX = paintState().origin.X;
1001 int origY = paintState().origin.Y;
1004 int maxX = clipX2 + 1;
1007 for (
int i = 0; i < path.pointsCount; ++i) {
1008 int py = path.points[i].Y + origY;
1014 minY = tmax(clipY1, minY);
1015 maxY = tmin(clipY2, maxY);
1017 int hw = paintState().penWidth / 2;
1018 updateRect = updateRect.merge(Rect(minX - hw, minY - hw, maxX + hw, maxY + hw));
1019 hideSprites(updateRect);
1022 for (; i < path.pointsCount - 1; ++i) {
1023 const int x1 = path.points[i].X + origX;
1024 const int y1 = path.points[i].Y + origY;
1025 const int x2 = path.points[i + 1].X + origX;
1026 const int y2 = path.points[i + 1].Y + origY;
1027 absDrawLine(x1, y1, x2, y2, color);
1029 const int x1 = path.points[i].X + origX;
1030 const int y1 = path.points[i].Y + origY;
1031 const int x2 = path.points[0].X + origX;
1032 const int y2 = path.points[0].Y + origY;
1033 absDrawLine(x1, y1, x2, y2, color);
1035 if (path.freePoints)
1036 m_primDynMemPool.free((
void*)path.points);
1040 void IRAM_ATTR BitmappedDisplayController::fillPath(Path
const & path, RGB888
const & color, Rect & updateRect)
1042 const int clipX1 = paintState().absClippingRect.X1;
1043 const int clipY1 = paintState().absClippingRect.Y1;
1044 const int clipX2 = paintState().absClippingRect.X2;
1045 const int clipY2 = paintState().absClippingRect.Y2;
1047 const int origX = paintState().origin.X;
1048 const int origY = paintState().origin.Y;
1051 int maxX = clipX2 + 1;
1054 for (
int i = 0; i < path.pointsCount; ++i) {
1055 int py = path.points[i].Y + origY;
1061 minY = tmax(clipY1, minY);
1062 maxY = tmin(clipY2, maxY);
1064 updateRect = updateRect.merge(Rect(minX, minY, maxX, maxY));
1065 hideSprites(updateRect);
1067 int16_t nodeX[path.pointsCount];
1069 for (
int pixelY = minY; pixelY <= maxY; ++pixelY) {
1072 int j = path.pointsCount - 1;
1073 for (
int i = 0; i < path.pointsCount; ++i) {
1074 int piy = path.points[i].Y + origY;
1075 int pjy = path.points[j].Y + origY;
1076 if ((piy < pixelY && pjy >= pixelY) || (pjy < pixelY && piy >= pixelY)) {
1077 int pjx = path.points[j].X + origX;
1078 int pix = path.points[i].X + origX;
1079 int a = (pixelY - piy) * (pjx - pix);
1080 int b = (pjy - piy);
1081 nodeX[nodes++] = pix + a / b + (((a < 0) ^ (b > 0)) && (a % b));
1087 while (i < nodes - 1) {
1088 if (nodeX[i] > nodeX[i + 1]) {
1089 tswap(nodeX[i], nodeX[i + 1]);
1096 for (
int i = 0; i < nodes; i += 2) {
1097 if (nodeX[i] >= maxX)
1099 if (nodeX[i + 1] > minX) {
1100 if (nodeX[i] < minX)
1102 if (nodeX[i + 1] > maxX)
1103 nodeX[i + 1] = maxX;
1104 rawFillRow(pixelY, nodeX[i], nodeX[i + 1] - 1, color);
1109 if (path.freePoints)
1110 m_primDynMemPool.free((
void*)path.points);
1114 void IRAM_ATTR BitmappedDisplayController::absDrawThickLine(
int X1,
int Y1,
int X2,
int Y2,
int penWidth, RGB888
const & color)
1117 const int origX = paintState().origin.X;
1118 const int origY = paintState().origin.Y;
1126 const double angle = atan2(
Y2 -
Y1,
X2 -
X1);
1127 const double pw = (double)penWidth / 2.0;
1128 const int ofs1 = lround(pw * cos(angle + M_PI_2));
1129 const int ofs2 = lround(pw * sin(angle + M_PI_2));
1130 const int ofs3 = lround(pw * cos(angle - M_PI_2));
1131 const int ofs4 = lround(pw * sin(angle - M_PI_2));
1132 pts[0].X =
X1 + ofs1;
1133 pts[0].Y =
Y1 + ofs2;
1134 pts[1].X =
X1 + ofs3;
1135 pts[1].Y =
Y1 + ofs4;
1136 pts[2].X =
X2 + ofs3;
1137 pts[2].Y =
Y2 + ofs4;
1138 pts[3].X =
X2 + ofs1;
1139 pts[3].Y =
Y2 + ofs2;
1142 Path path = { pts, 4,
false };
1143 fillPath(path, color, updateRect);
1145 switch (paintState().lineEnds) {
1147 if ((penWidth & 1) == 0)
1149 fillEllipse(
X1,
Y1, Size(penWidth, penWidth), color, updateRect);
1150 fillEllipse(
X2,
Y2, Size(penWidth, penWidth), color, updateRect);
1158 void IRAM_ATTR BitmappedDisplayController::drawBitmap(BitmapDrawingInfo
const & bitmapDrawingInfo, Rect & updateRect)
1160 int x = bitmapDrawingInfo.X + paintState().origin.X;
1161 int y = bitmapDrawingInfo.Y + paintState().origin.Y;
1162 updateRect = updateRect.merge(Rect(x, y, x + bitmapDrawingInfo.bitmap->width - 1, y + bitmapDrawingInfo.bitmap->height - 1));
1163 hideSprites(updateRect);
1164 absDrawBitmap(x, y, bitmapDrawingInfo.bitmap,
nullptr,
false);
1168 void IRAM_ATTR BitmappedDisplayController::absDrawBitmap(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
bool ignoreClippingRect)
1170 const int clipX1 = ignoreClippingRect ? 0 : paintState().absClippingRect.X1;
1171 const int clipY1 = ignoreClippingRect ? 0 : paintState().absClippingRect.Y1;
1172 const int clipX2 = ignoreClippingRect ?
getViewPortWidth() - 1 : paintState().absClippingRect.X2;
1173 const int clipY2 = ignoreClippingRect ?
getViewPortHeight() - 1 : paintState().absClippingRect.Y2;
1175 if (destX > clipX2 || destY > clipY2)
1178 int width = bitmap->width;
1179 int height = bitmap->height;
1184 if (destX < clipX1) {
1185 X1 = clipX1 - destX;
1191 if (destX + XCount > clipX2 + 1)
1192 XCount = clipX2 + 1 - destX;
1199 if (destY < clipY1) {
1200 Y1 = clipY1 - destY;
1206 if (destY + YCount > clipY2 + 1)
1207 YCount = clipY2 + 1 - destY;
1211 switch (bitmap->format) {
1217 rawDrawBitmap_Native(destX, destY, bitmap,
X1,
Y1, XCount, YCount);
1221 rawDrawBitmap_Mask(destX, destY, bitmap, saveBackground,
X1,
Y1, XCount, YCount);
1225 rawDrawBitmap_RGBA2222(destX, destY, bitmap, saveBackground,
X1,
Y1, XCount, YCount);
1229 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.
#define FABGLIB_PRIMITIVES_DYNBUFFERS_SIZE
#define FABGLIB_DEFAULT_DISPLAYCONTROLLER_QUEUE_SIZE