diff --git a/src/Fonts/lgfx_fonts.cpp b/src/Fonts/lgfx_fonts.cpp index 7ed017c..9dab448 100644 --- a/src/Fonts/lgfx_fonts.cpp +++ b/src/Fonts/lgfx_fonts.cpp @@ -8,6 +8,22 @@ #endif namespace lgfx { + void BaseFont::getDefaultMetric(FontMetrics *metrics) const + { + metrics->width = width; + metrics->x_advance = width; + metrics->x_offset = 0; + metrics->height = height; + metrics->y_advance = height; + metrics->y_offset = 0; + metrics->baseline = baseline; + } + void BDFfont::getDefaultMetric(FontMetrics *metrics) const + { + BaseFont::getDefaultMetric(metrics); + metrics->y_advance = y_advance; + } + bool GLCDfont::updateFontMetric(FontMetrics*, std::uint16_t uniCode) const { return uniCode < 256; } @@ -182,9 +198,9 @@ namespace fonts { namespace lgfx { // deprecated array. - PROGMEM const IFont* fontdata [] = { + const IFont* fontdata [] = { &fonts::Font0, // GLCD font (Font 0) - &fonts::Font0, // GLCD font (or GFX font) + &fonts::Font0, // Font 1 current unused &fonts::Font2, &fonts::Font0, // Font 3 current unused &fonts::Font4, diff --git a/src/Fonts/lgfx_fonts.hpp b/src/Fonts/lgfx_fonts.hpp index 3451602..a4c0329 100644 --- a/src/Fonts/lgfx_fonts.hpp +++ b/src/Fonts/lgfx_fonts.hpp @@ -5,27 +5,6 @@ namespace lgfx { - enum textdatum_t : std::uint8_t - // 0:left 1:centre 2:right - // 0:top 4:middle 8:bottom 16:baseline - { top_left = 0 // Top left (default) - , top_center = 1 // Top center - , top_centre = 1 // Top center - , top_right = 2 // Top right - , middle_left = 4 // Middle left - , middle_center = 5 // Middle center - , middle_centre = 5 // Middle center - , middle_right = 6 // Middle right - , bottom_left = 8 // Bottom left - , bottom_center = 9 // Bottom center - , bottom_centre = 9 // Bottom center - , bottom_right = 10 // Bottom right - , baseline_left = 16 // Baseline left (Line the 'A' character would sit on) - , baseline_center = 17 // Baseline center - , baseline_centre = 17 // Baseline center - , baseline_right = 18 // Baseline right - }; - struct FontMetrics { std::int16_t width; std::int16_t x_advance; @@ -36,16 +15,6 @@ namespace lgfx std::int16_t baseline; }; - struct TextStyle { - std::uint32_t fore_rgb888 = 0xFFFFFFU; - std::uint32_t back_rgb888 = 0; - std::int_fast8_t size_x = 1; - std::int_fast8_t size_y = 1; - textdatum_t datum = textdatum_t::top_left; - bool utf8 = true; - bool cp437 = false; - }; - struct IFont { enum font_type_t @@ -62,16 +31,6 @@ namespace lgfx virtual void getDefaultMetric(FontMetrics *metrics) const = 0; virtual bool updateFontMetric(FontMetrics *metrics, std::uint16_t uniCode) const = 0; virtual bool unloadFont(void) { return false; } -/* - struct param { - int32_t clip_left ; - int32_t clip_right ; - int32_t clip_top ; - int32_t clip_bottom; - int32_t filled_x ; - TextStyle* style ; - }; -//*/ }; struct RunTimeFont : public IFont { @@ -92,15 +51,7 @@ namespace lgfx , height (height ) , baseline (baseline ) {} - void getDefaultMetric(FontMetrics *metrics) const override { - metrics->width = width; - metrics->x_advance = width; - metrics->x_offset = 0; - metrics->height = height; - metrics->y_advance = height; - metrics->y_offset = 0; - metrics->baseline = baseline; - } + void getDefaultMetric(FontMetrics *metrics) const override; }; struct GLCDfont : public BaseFont { @@ -126,15 +77,18 @@ namespace lgfx const std::uint16_t *indextbl; std::uint16_t indexsize; std::uint8_t halfwidth; + std::uint8_t y_advance; BDFfont() = default; - constexpr BDFfont(const std::uint8_t *chartbl, const std::uint16_t *indextbl, std::uint16_t indexsize, std::uint8_t width, std::uint8_t halfwidth, std::uint8_t height, std::uint8_t baseline) + constexpr BDFfont(const std::uint8_t *chartbl, const std::uint16_t *indextbl, std::uint16_t indexsize, std::uint8_t width, std::uint8_t halfwidth, std::uint8_t height, std::uint8_t baseline, std::uint8_t y_advance) : BaseFont(chartbl, nullptr, width, height, baseline ) , indextbl(indextbl) , indexsize(indexsize) , halfwidth(halfwidth) + , y_advance(y_advance) {} constexpr font_type_t getType(void) const override { return ft_bdf; } + void getDefaultMetric(FontMetrics *metrics) const override; bool updateFontMetric(FontMetrics *metrics, std::uint16_t uniCode) const override; }; @@ -144,64 +98,60 @@ namespace lgfx //---------------------------------------------------------------------------- // Adafruit GFX font - struct GFXglyph { // Data stored PER GLYPH - std::uint32_t bitmapOffset; // Pointer into GFXfont->bitmap - std::uint8_t width, height; // Bitmap dimensions in pixels - std::uint8_t xAdvance; // Distance to advance cursor (x axis) - std::int8_t xOffset, yOffset; // Dist from cursor pos to UL corner - }; - - struct GFXfont : public lgfx::IFont { // Data stored for FONT AS A WHOLE: - struct EncodeRange { - std::uint16_t start; - std::uint16_t end; - std::uint16_t base; - }; - - std::uint8_t *bitmap; // Glyph bitmaps, concatenated - GFXglyph *glyph; // Glyph array - std::uint16_t first, last; // ASCII extents - std::uint8_t yAdvance; // Newline distance (y axis) - - std::uint16_t range_num; // Number of EncodeRange - EncodeRange *range; // Array ofEncodeRange - - constexpr GFXfont ( std::uint8_t *bitmap - , GFXglyph *glyph - , std::uint16_t first - , std::uint16_t last - , std::uint8_t yAdvance - , std::uint16_t range_num = 0 - , EncodeRange *range = nullptr - ) - : bitmap (bitmap ) - , glyph (glyph ) - , first (first ) - , last (last ) - , yAdvance (yAdvance ) - , range_num(range_num) - , range (range ) - {} - - GFXglyph* getGlyph(std::uint16_t uniCode) const; - - constexpr font_type_t getType(void) const override { return font_type_t::ft_gfx; } - - void getDefaultMetric(lgfx::FontMetrics *metrics) const; - - bool updateFontMetric(lgfx::FontMetrics *metrics, std::uint16_t uniCode) const override; - }; +struct EncodeRange { + std::uint16_t start; + std::uint16_t end; + std::uint16_t base; +}; + +struct GFXglyph { // Data stored PER GLYPH + std::uint32_t bitmapOffset; // Pointer into GFXfont->bitmap + std::uint8_t width, height; // Bitmap dimensions in pixels + std::uint8_t xAdvance; // Distance to advance cursor (x axis) + std::int8_t xOffset, yOffset; // Dist from cursor pos to UL corner +}; + +struct GFXfont : public lgfx::IFont { // Data stored for FONT AS A WHOLE: + std::uint8_t *bitmap; // Glyph bitmaps, concatenated + GFXglyph *glyph; // Glyph array + std::uint16_t first, last; // ASCII extents + std::uint8_t yAdvance; // Newline distance (y axis) + + std::uint16_t range_num; // Number of EncodeRange + EncodeRange *range; // Array ofEncodeRange + + constexpr GFXfont ( std::uint8_t *bitmap + , GFXglyph *glyph + , std::uint16_t first + , std::uint16_t last + , std::uint8_t yAdvance + , std::uint16_t range_num = 0 + , EncodeRange *range = nullptr + ) + : bitmap (bitmap ) + , glyph (glyph ) + , first (first ) + , last (last ) + , yAdvance (yAdvance ) + , range_num(range_num) + , range (range ) + {} + + GFXglyph* getGlyph(std::uint16_t uniCode) const; + + constexpr font_type_t getType(void) const override { return font_type_t::ft_gfx; } + + void getDefaultMetric(lgfx::FontMetrics *metrics) const; + + bool updateFontMetric(lgfx::FontMetrics *metrics, std::uint16_t uniCode) const override; +}; //---------------------------------------------------------------------------- namespace fonts { #ifdef __EFONT_FONT_DATA_H__ - static constexpr lgfx::BDFfont efont = { (const std::uint8_t *)efontFontData, efontFontList, sizeof(efontFontList)>>1, 16, 8, 16, 14 }; -#endif - -#ifdef misakiUTF16FontData_h - static constexpr lgfx::BDFfont misaki = { (const std::uint8_t *)fdata, ftable, sizeof(ftable)>>1, 8, 4, 7, 6 }; + static constexpr lgfx::BDFfont efont = { (const std::uint8_t *)efontFontData, efontFontList, sizeof(efontFontList)>>1, 16, 8, 16, 14, 16 }; #endif extern const lgfx::GLCDfont Font0; diff --git a/src/Free_Fonts.h b/src/Free_Fonts.h new file mode 100644 index 0000000..23a382b --- /dev/null +++ b/src/Free_Fonts.h @@ -0,0 +1,377 @@ +// Attach this header file to your sketch to use the GFX Free Fonts. You can write +// sketches without it, but it makes referencing them easier. + +// This calls up ALL the fonts but they only get loaded if you actually +// use them in your sketch. +// +// No changes are needed to this header file unless new fonts are added to the +// library "Fonts/GFXFF" folder. +// +// To save a lot of typing long names, each font can easily be referenced in the +// sketch in three ways, either with: +// +// 1. Font file name with the & in front such as &FreeSansBoldOblique24pt7b +// an example being: +// +// tft.setFreeFont(&FreeSansBoldOblique24pt7b); +// +// 2. FF# where # is a number determined by looking at the list below +// an example being: +// +// tft.setFreeFont(FF32); +// +// 3. An abbreviation of the file name. Look at the list below to see +// the abbreviations used, for example: +// +// tft.setFreeFont(FSSBO24) +// +// Where the letters mean: +// F = Free font +// M = Mono +// SS = Sans Serif (double S to distinguish is form serif fonts) +// S = Serif +// B = Bold +// O = Oblique (letter O not zero) +// I = Italic +// # = point size, either 9, 12, 18 or 24 +// +// Setting the font to NULL will select the GLCD font: +// +// tft.setFreeFont(NULL); // Set font to GLCD + +#define LOAD_GFXFF + +#ifdef LOAD_GFXFF // Only include the fonts if LOAD_GFXFF is defined in User_Setup.h + +// Use these when printing or drawing text in GLCD and high rendering speed fonts +#define GFXFF 1 +#define GLCD &Font0 +#define FONT2 &Font2 +#define FONT4 &Font4 +#define FONT6 &Font6 +#define FONT7 &Font7 +#define FONT8 &Font8 + +// Use the following when calling setFont() +// +// Reserved for GLCD font // FF0 +// + +#define TT1 &TomThumb + +#define FM9 &FreeMono9pt7b +#define FM12 &FreeMono12pt7b +#define FM18 &FreeMono18pt7b +#define FM24 &FreeMono24pt7b + +#define FMB9 &FreeMonoBold9pt7b +#define FMB12 &FreeMonoBold12pt7b +#define FMB18 &FreeMonoBold18pt7b +#define FMB24 &FreeMonoBold24pt7b + +#define FMO9 &FreeMonoOblique9pt7b +#define FMO12 &FreeMonoOblique12pt7b +#define FMO18 &FreeMonoOblique18pt7b +#define FMO24 &FreeMonoOblique24pt7b + +#define FMBO9 &FreeMonoBoldOblique9pt7b +#define FMBO12 &FreeMonoBoldOblique12pt7b +#define FMBO18 &FreeMonoBoldOblique18pt7b +#define FMBO24 &FreeMonoBoldOblique24pt7b + +#define FSS9 &FreeSans9pt7b +#define FSS12 &FreeSans12pt7b +#define FSS18 &FreeSans18pt7b +#define FSS24 &FreeSans24pt7b + +#define FSSB9 &FreeSansBold9pt7b +#define FSSB12 &FreeSansBold12pt7b +#define FSSB18 &FreeSansBold18pt7b +#define FSSB24 &FreeSansBold24pt7b + +#define FSSO9 &FreeSansOblique9pt7b +#define FSSO12 &FreeSansOblique12pt7b +#define FSSO18 &FreeSansOblique18pt7b +#define FSSO24 &FreeSansOblique24pt7b + +#define FSSBO9 &FreeSansBoldOblique9pt7b +#define FSSBO12 &FreeSansBoldOblique12pt7b +#define FSSBO18 &FreeSansBoldOblique18pt7b +#define FSSBO24 &FreeSansBoldOblique24pt7b + +#define FS9 &FreeSerif9pt7b +#define FS12 &FreeSerif12pt7b +#define FS18 &FreeSerif18pt7b +#define FS24 &FreeSerif24pt7b + +#define FSI9 &FreeSerifItalic9pt7b +#define FSI12 &FreeSerifItalic12pt7b +#define FSI19 &FreeSerifItalic18pt7b +#define FSI24 &FreeSerifItalic24pt7b + +#define FSB9 &FreeSerifBold9pt7b +#define FSB12 &FreeSerifBold12pt7b +#define FSB18 &FreeSerifBold18pt7b +#define FSB24 &FreeSerifBold24pt7b + +#define FSBI9 &FreeSerifBoldItalic9pt7b +#define FSBI12 &FreeSerifBoldItalic12pt7b +#define FSBI18 &FreeSerifBoldItalic18pt7b +#define FSBI24 &FreeSerifBoldItalic24pt7b + +#define FF0 NULL //ff0 reserved for GLCD +#define FF1 &FreeMono9pt7b +#define FF2 &FreeMono12pt7b +#define FF3 &FreeMono18pt7b +#define FF4 &FreeMono24pt7b + +#define FF5 &FreeMonoBold9pt7b +#define FF6 &FreeMonoBold12pt7b +#define FF7 &FreeMonoBold18pt7b +#define FF8 &FreeMonoBold24pt7b + +#define FF9 &FreeMonoOblique9pt7b +#define FF10 &FreeMonoOblique12pt7b +#define FF11 &FreeMonoOblique18pt7b +#define FF12 &FreeMonoOblique24pt7b + +#define FF13 &FreeMonoBoldOblique9pt7b +#define FF14 &FreeMonoBoldOblique12pt7b +#define FF15 &FreeMonoBoldOblique18pt7b +#define FF16 &FreeMonoBoldOblique24pt7b + +#define FF17 &FreeSans9pt7b +#define FF18 &FreeSans12pt7b +#define FF19 &FreeSans18pt7b +#define FF20 &FreeSans24pt7b + +#define FF21 &FreeSansBold9pt7b +#define FF22 &FreeSansBold12pt7b +#define FF23 &FreeSansBold18pt7b +#define FF24 &FreeSansBold24pt7b + +#define FF25 &FreeSansOblique9pt7b +#define FF26 &FreeSansOblique12pt7b +#define FF27 &FreeSansOblique18pt7b +#define FF28 &FreeSansOblique24pt7b + +#define FF29 &FreeSansBoldOblique9pt7b +#define FF30 &FreeSansBoldOblique12pt7b +#define FF31 &FreeSansBoldOblique18pt7b +#define FF32 &FreeSansBoldOblique24pt7b + +#define FF33 &FreeSerif9pt7b +#define FF34 &FreeSerif12pt7b +#define FF35 &FreeSerif18pt7b +#define FF36 &FreeSerif24pt7b + +#define FF37 &FreeSerifItalic9pt7b +#define FF38 &FreeSerifItalic12pt7b +#define FF39 &FreeSerifItalic18pt7b +#define FF40 &FreeSerifItalic24pt7b + +#define FF41 &FreeSerifBold9pt7b +#define FF42 &FreeSerifBold12pt7b +#define FF43 &FreeSerifBold18pt7b +#define FF44 &FreeSerifBold24pt7b + +#define FF45 &FreeSerifBoldItalic9pt7b +#define FF46 &FreeSerifBoldItalic12pt7b +#define FF47 &FreeSerifBoldItalic18pt7b +#define FF48 &FreeSerifBoldItalic24pt7b + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// Now we define "s"tring versions for easy printing of the font name so: +// tft.println(sFF5); +// will print +// Mono bold 9 +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +#define sFF0 "GLCD" +#define sTT1 "Tom Thumb" +#define sFF1 "Mono 9" +#define sFF2 "Mono 12" +#define sFF3 "Mono 18" +#define sFF4 "Mono 24" + +#define sFF5 "Mono bold 9" +#define sFF6 "Mono bold 12" +#define sFF7 "Mono bold 18" +#define sFF8 "Mono bold 24" + +#define sFF9 "Mono oblique 9" +#define sFF10 "Mono oblique 12" +#define sFF11 "Mono oblique 18" +#define sFF12 "Mono oblique 24" + +#define sFF13 "Mono bold oblique 9" +#define sFF14 "Mono bold oblique 12" +#define sFF15 "Mono bold oblique 18" +#define sFF16 "Mono bold oblique 24" // Full text line is too big for 480 pixel wide screen + +#define sFF17 "Sans 9" +#define sFF18 "Sans 12" +#define sFF19 "Sans 18" +#define sFF20 "Sans 24" + +#define sFF21 "Sans bold 9" +#define sFF22 "Sans bold 12" +#define sFF23 "Sans bold 18" +#define sFF24 "Sans bold 24" + +#define sFF25 "Sans oblique 9" +#define sFF26 "Sans oblique 12" +#define sFF27 "Sans oblique 18" +#define sFF28 "Sans oblique 24" + +#define sFF29 "Sans bold oblique 9" +#define sFF30 "Sans bold oblique 12" +#define sFF31 "Sans bold oblique 18" +#define sFF32 "Sans bold oblique 24" + +#define sFF33 "Serif 9" +#define sFF34 "Serif 12" +#define sFF35 "Serif 18" +#define sFF36 "Serif 24" + +#define sFF37 "Serif italic 9" +#define sFF38 "Serif italic 12" +#define sFF39 "Serif italic 18" +#define sFF40 "Serif italic 24" + +#define sFF41 "Serif bold 9" +#define sFF42 "Serif bold 12" +#define sFF43 "Serif bold 18" +#define sFF44 "Serif bold 24" + +#define sFF45 "Serif bold italic 9" +#define sFF46 "Serif bold italic 12" +#define sFF47 "Serif bold italic 18" +#define sFF48 "Serif bold italic 24" + +#else // LOAD_GFXFF not defined so setup defaults to prevent error messages + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// Free fonts are not loaded in User_Setup.h so we must define all as font 1 +// to prevent compile error messages +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +#define GFXFF 1 +#define GLCD 1 +#define FONT2 2 +#define FONT4 4 +#define FONT6 6 +#define FONT7 7 +#define FONT8 8 + +#define FF0 1 +#define FF1 1 +#define FF2 1 +#define FF3 1 +#define FF4 1 +#define FF5 1 +#define FF6 1 +#define FF7 1 +#define FF8 1 +#define FF9 1 +#define FF10 1 +#define FF11 1 +#define FF12 1 +#define FF13 1 +#define FF14 1 +#define FF15 1 +#define FF16 1 +#define FF17 1 +#define FF18 1 +#define FF19 1 +#define FF20 1 +#define FF21 1 +#define FF22 1 +#define FF23 1 +#define FF24 1 +#define FF25 1 +#define FF26 1 +#define FF27 1 +#define FF28 1 +#define FF29 1 +#define FF30 1 +#define FF31 1 +#define FF32 1 +#define FF33 1 +#define FF34 1 +#define FF35 1 +#define FF36 1 +#define FF37 1 +#define FF38 1 +#define FF39 1 +#define FF40 1 +#define FF41 1 +#define FF42 1 +#define FF43 1 +#define FF44 1 +#define FF45 1 +#define FF46 1 +#define FF47 1 +#define FF48 1 + +#define FM9 1 +#define FM12 1 +#define FM18 1 +#define FM24 1 + +#define FMB9 1 +#define FMB12 1 +#define FMB18 1 +#define FMB24 1 + +#define FMO9 1 +#define FMO12 1 +#define FMO18 1 +#define FMO24 1 + +#define FMBO9 1 +#define FMBO12 1 +#define FMBO18 1 +#define FMBO24 1 + +#define FSS9 1 +#define FSS12 1 +#define FSS18 1 +#define FSS24 1 + +#define FSSB9 1 +#define FSSB12 1 +#define FSSB18 1 +#define FSSB24 1 + +#define FSSO9 1 +#define FSSO12 1 +#define FSSO18 1 +#define FSSO24 1 + +#define FSSBO9 1 +#define FSSBO12 1 +#define FSSBO18 1 +#define FSSBO24 1 + +#define FS9 1 +#define FS12 1 +#define FS18 1 +#define FS24 1 + +#define FSI9 1 +#define FSI12 1 +#define FSI19 1 +#define FSI24 1 + +#define FSB9 1 +#define FSB12 1 +#define FSB18 1 +#define FSB24 1 + +#define FSBI9 1 +#define FSBI12 1 +#define FSBI18 1 +#define FSBI24 1 + +#endif // LOAD_GFXFF diff --git a/src/M5Display.h b/src/M5Display.h index 0705d5f..e07f865 100644 --- a/src/M5Display.h +++ b/src/M5Display.h @@ -37,6 +37,36 @@ #include "utility/TouchButton.h" #endif + typedef lgfx::bgr888_t RGBColor; + + namespace textdatum + { + static constexpr textdatum_t TL_DATUM = textdatum_t::top_left; + static constexpr textdatum_t TC_DATUM = textdatum_t::top_center; + static constexpr textdatum_t TR_DATUM = textdatum_t::top_right; + static constexpr textdatum_t ML_DATUM = textdatum_t::middle_left; + static constexpr textdatum_t CL_DATUM = textdatum_t::middle_left; + static constexpr textdatum_t MC_DATUM = textdatum_t::middle_center; + static constexpr textdatum_t CC_DATUM = textdatum_t::middle_center; + static constexpr textdatum_t MR_DATUM = textdatum_t::middle_right; + static constexpr textdatum_t CR_DATUM = textdatum_t::middle_right; + static constexpr textdatum_t BL_DATUM = textdatum_t::bottom_left; + static constexpr textdatum_t BC_DATUM = textdatum_t::bottom_center; + static constexpr textdatum_t BR_DATUM = textdatum_t::bottom_right; + static constexpr textdatum_t L_BASELINE = textdatum_t::baseline_left; + static constexpr textdatum_t C_BASELINE = textdatum_t::baseline_center; + static constexpr textdatum_t R_BASELINE = textdatum_t::baseline_right; + }; + + namespace attribute + { + static constexpr attribute_t CP437_SWITCH = attribute_t::cp437_switch; + static constexpr attribute_t UTF8_SWITCH = attribute_t::utf8_switch; + } + + using namespace textdatum; + using namespace attribute; + namespace lgfx { #if defined( ARDUINO_M5Stack_Core_ESP32 ) || defined( ARDUINO_M5STACK_FIRE ) // M5Stack @@ -158,62 +188,6 @@ #endif } - - typedef lgfx::bgr888_t RGBColor; - - - // Font datum enumeration - // LEFT=0 CENTER=1 RIGHT=2 - // TOP=0 MIDDLE=4 BOTTOM=8 BASELINE=16 - - #define TL_DATUM 0 // Top left (default) - #define TC_DATUM 1 // Top centre - #define TR_DATUM 2 // Top right - #define ML_DATUM 4 // Middle left - #define CL_DATUM 4 // Centre left, same as above - #define MC_DATUM 5 // Middle centre - #define CC_DATUM 5 // Centre centre, same as above - #define MR_DATUM 6 // Middle right - #define CR_DATUM 6 // Centre right, same as above - #define BL_DATUM 8 // Bottom left - #define BC_DATUM 9// Bottom centre - #define BR_DATUM 10 // Bottom right - #define L_BASELINE 16 // Left character baseline (Line the 'A' character would sit on) - #define C_BASELINE 17 // Centre character baseline - #define R_BASELINE 18 // Right character baseline - - - // Colour enumeration - - // Default color definitions - #define TFT_BLACK 0x0000 /* 0, 0, 0 */ - #define TFT_NAVY 0x000F /* 0, 0, 128 */ - #define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */ - #define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */ - #define TFT_MAROON 0x7800 /* 128, 0, 0 */ - #define TFT_PURPLE 0x780F /* 128, 0, 128 */ - #define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */ - #define TFT_LIGHTGREY 0xD69A /* 211, 211, 211 */ - #define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */ - #define TFT_BLUE 0x001F /* 0, 0, 255 */ - #define TFT_GREEN 0x07E0 /* 0, 255, 0 */ - #define TFT_CYAN 0x07FF /* 0, 255, 255 */ - #define TFT_RED 0xF800 /* 255, 0, 0 */ - #define TFT_MAGENTA 0xF81F /* 255, 0, 255 */ - #define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */ - #define TFT_WHITE 0xFFFF /* 255, 255, 255 */ - #define TFT_ORANGE 0xFDA0 /* 255, 180, 0 */ - #define TFT_GREENYELLOW 0xB7E0 /* 180, 255, 0 */ - #define TFT_PINK 0xFE19 /* 255, 192, 203 */ //Lighter pink, was 0xFC9F - #define TFT_BROWN 0x9A60 /* 150, 75, 0 */ - #define TFT_GOLD 0xFEA0 /* 255, 215, 0 */ - #define TFT_SILVER 0xC618 /* 192, 192, 192 */ - #define TFT_SKYBLUE 0x867D /* 135, 206, 235 */ - #define TFT_VIOLET 0x915C /* 180, 46, 226 */ - - #define TFT_TRANSPARENT 0x0120 - - class LGFX : public lgfx::LGFX_SPI { public: diff --git a/src/lgfx/lgfx_base.cpp b/src/lgfx/lgfx_base.cpp new file mode 100644 index 0000000..42131ce --- /dev/null +++ b/src/lgfx/lgfx_base.cpp @@ -0,0 +1,1199 @@ +/*----------------------------------------------------------------------------/ + Lovyan GFX library - ESP32 hardware SPI graphics library . + + for Arduino and ESP-IDF + +Original Source: + https://github.com/lovyan03/LovyanGFX/ + +Licence: + [BSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) + +Author: + [lovyan03](https://twitter.com/lovyan03) + +Contributors: + [ciniml](https://github.com/ciniml) + [mongonta0716](https://github.com/mongonta0716) + [tobozo](https://github.com/tobozo) +/----------------------------------------------------------------------------*/ +#include "lgfx_base.hpp" + +#include +#include +#include +#include + +namespace lgfx +{ + static constexpr float deg_to_rad = 0.017453292519943295769236907684886; + + void LGFXBase::setAddrWindow(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) + { + if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; + bool tr = !_transaction_count; + if (tr) beginTransaction(); + setWindow(x, y, x + w - 1, y + h - 1); + if (tr) endTransaction(); + } + + void LGFXBase::setClipRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) + { + if (x < 0) { w += x; x = 0; } + if (w > _width - x) w = _width - x; + if (w < 1) { x = 0; w = 0; } + _clip_l = x; + _clip_r = x + w - 1; + + if (y < 0) { h += y; y = 0; } + if (h > _height - y) h = _height - y; + if (h < 1) { y = 0; h = 0; } + _clip_t = y; + _clip_b = y + h - 1; + } + + void LGFXBase::getClipRect(std::int32_t *x, std::int32_t *y, std::int32_t *w, std::int32_t *h) + { + *x = _clip_l; + *w = _clip_r - *x + 1; + *y = _clip_t; + *h = _clip_b - *y + 1; + } + + void LGFXBase::clearClipRect(void) + { + _clip_l = 0; + _clip_r = _width - 1; + _clip_t = 0; + _clip_b = _height - 1; + } + + void LGFXBase::setScrollRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) + { + _adjust_abs(x, w); + if (x < 0) { w += x; x = 0; } + if (w > _width - x) w = _width - x; + if (w < 0) w = 0; + _sx = x; + _sw = w; + + _adjust_abs(y, h); + if (y < 0) { h += y; y = 0; } + if (h > _height - y) h = _height - y; + if (h < 0) h = 0; + _sy = y; + _sh = h; + } + + void LGFXBase::getScrollRect(std::int32_t *x, std::int32_t *y, std::int32_t *w, std::int32_t *h) + { + *x = _sx; + *y = _sy; + *w = _sw; + *h = _sh; + } + + void LGFXBase::clearScrollRect(void) + { + _sx = 0; + _sw = _width; + _sy = 0; + _sh = _height; + } + + void LGFXBase::drawFastVLine(std::int32_t x, std::int32_t y, std::int32_t h) + { + _adjust_abs(y, h); + bool tr = !_transaction_count; + if (tr) beginTransaction(); + writeFastVLine(x, y, h); + if (tr) endTransaction(); + } + + void LGFXBase::writeFastVLine(std::int32_t x, std::int32_t y, std::int32_t h) + { + if (x < _clip_l || x > _clip_r) return; + auto ct = _clip_t; + if (y < ct) { h += y - ct; y = ct; } + auto cb = _clip_b + 1 - y; + if (h > cb) h = cb; + if (h < 1) return; + + writeFillRect_impl(x, y, 1, h); + } + + void LGFXBase::drawFastHLine(std::int32_t x, std::int32_t y, std::int32_t w) + { + _adjust_abs(x, w); + bool tr = !_transaction_count; + if (tr) beginTransaction(); + writeFastHLine(x, y, w); + if (tr) endTransaction(); + } + + void LGFXBase::writeFastHLine(std::int32_t x, std::int32_t y, std::int32_t w) + { + if (y < _clip_t || y > _clip_b) return; + auto cl = _clip_l; + if (x < cl) { w += x - cl; x = cl; } + auto cr = _clip_r + 1 - x; + if (w > cr) w = cr; + if (w < 1) return; + + writeFillRect_impl(x, y, w, 1); + } + + void LGFXBase::fillRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) + { + _adjust_abs(x, w); + _adjust_abs(y, h); + bool tr = !_transaction_count; + if (tr) beginTransaction(); + writeFillRect(x, y, w, h); + if (tr) endTransaction(); + } + + void LGFXBase::writeFillRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) + { + auto cl = _clip_l; + if (x < cl) { w += x - cl; x = cl; } + auto cr = _clip_r + 1 - x; + if (w > cr) w = cr; + if (w < 1) return; + + auto ct = _clip_t; + if (y < ct) { h += y - ct; y = ct; } + auto cb = _clip_b + 1 - y; + if (h > cb) h = cb; + if (h < 1) return; + + writeFillRect_impl(x, y, w, h); + } + + + void LGFXBase::drawRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) + { + if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; + bool tr = !_transaction_count; + if (tr) beginTransaction(); + writeFastHLine(x, y , w); + if (--h) { + writeFastHLine(x, y + h , w); + if (--h) { + writeFastVLine(x , ++y, h); + writeFastVLine(x + w - 1, y, h); + } + } + if (tr) endTransaction(); + } + + void LGFXBase::drawCircle(std::int32_t x, std::int32_t y, std::int32_t r) + { + if ( r <= 0 ) { + drawPixel(x, y); + return; + } + + startWrite(); + std::int32_t f = 1 - r; + std::int32_t ddF_y = - (r << 1); + std::int32_t ddF_x = 1; + std::int32_t i = 0; + std::int32_t j = -1; + do { + while (f < 0) { + ++i; + f += (ddF_x += 2); + } + f += (ddF_y += 2); + + writeFastHLine(x - i , y + r, i - j); + writeFastHLine(x - i , y - r, i - j); + writeFastHLine(x + j + 1, y - r, i - j); + writeFastHLine(x + j + 1, y + r, i - j); + + writeFastVLine(x + r, y + j + 1, i - j); + writeFastVLine(x + r, y - i , i - j); + writeFastVLine(x - r, y - i , i - j); + writeFastVLine(x - r, y + j + 1, i - j); + j = i; + } while (i < --r); + endWrite(); + } + + void LGFXBase::drawCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint_fast8_t cornername) + { + if (r <= 0) return; + std::int32_t f = 1 - r; + std::int32_t ddF_y = - (r << 1); + std::int32_t ddF_x = 1; + std::int32_t i = 0; + std::int32_t j = 0; + + startWrite(); + do { + while (f < 0) { + ++i; + f += (ddF_x += 2); + } + f += (ddF_y += 2); + + if (cornername & 0x1) { // left top + writeFastHLine(x - i, y - r, i - j); + writeFastVLine(x - r, y - i, i - j); + } + if (cornername & 0x2) { // right top + writeFastVLine(x + r , y - i, i - j); + writeFastHLine(x + j + 1, y - r, i - j); + } + if (cornername & 0x4) { // right bottom + writeFastHLine(x + j + 1, y + r , i - j); + writeFastVLine(x + r , y + j + 1, i - j); + } + if (cornername & 0x8) { // left bottom + writeFastVLine(x - r, y + j + 1, i - j); + writeFastHLine(x - i, y + r , i - j); + } + j = i; + } while (i < --r); + endWrite(); + } + + void LGFXBase::fillCircle(std::int32_t x, std::int32_t y, std::int32_t r) { + startWrite(); + writeFastHLine(x - r, y, (r << 1) + 1); + fillCircleHelper(x, y, r, 3, 0); + endWrite(); + } + + void LGFXBase::fillCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint_fast8_t corners, std::int32_t delta) + { + if (r <= 0) return; + + ++delta; + + std::int32_t f = 1 - r; + std::int32_t ddF_y = - (r << 1); + std::int32_t ddF_x = 1; + std::int32_t i = 0; + + startWrite(); + do { + std::int32_t len = 0; + while (f < 0) { + f += (ddF_x += 2); + ++len; + } + i += len; + f += (ddF_y += 2); + + if (corners & 0x1) { + if (len) writeFillRect(x - r, y + i - len + 1, (r << 1) + delta, len); + writeFastHLine(x - i, y + r, (i << 1) + delta); + } + if (corners & 0x2) { + writeFastHLine(x - i, y - r, (i << 1) + delta); + if (len) writeFillRect(x - r, y - i, (r << 1) + delta, len); + } + } while (i < --r); + endWrite(); + } + + void LGFXBase::drawEllipse(std::int32_t x, std::int32_t y, std::int32_t rx, std::int32_t ry) + { + if (ry == 0) { + drawFastHLine(x - rx, y, (ry << 2) + 1); + return; + } + if (rx == 0) { + drawFastVLine(x, y - ry, (rx << 2) + 1); + return; + } + if (rx < 0 || ry < 0) return; + + std::int32_t xt, yt, s, i; + std::int32_t rx2 = rx * rx; + std::int32_t ry2 = ry * ry; + + startWrite(); + + i = -1; + xt = 0; + yt = ry; + s = (ry2 << 1) + rx2 * (1 - (ry << 1)); + do { + while ( s < 0 ) s += ry2 * ((++xt << 2) + 2); + writeFastHLine(x - xt , y - yt, xt - i); + writeFastHLine(x + i + 1, y - yt, xt - i); + writeFastHLine(x + i + 1, y + yt, xt - i); + writeFastHLine(x - xt , y + yt, xt - i); + i = xt; + s -= (--yt) * rx2 << 2; + } while (ry2 * xt <= rx2 * yt); + + i = -1; + yt = 0; + xt = rx; + s = (rx2 << 1) + ry2 * (1 - (rx << 1)); + do { + while ( s < 0 ) s += rx2 * ((++yt << 2) + 2); + writeFastVLine(x - xt, y - yt , yt - i); + writeFastVLine(x - xt, y + i + 1, yt - i); + writeFastVLine(x + xt, y + i + 1, yt - i); + writeFastVLine(x + xt, y - yt , yt - i); + i = yt; + s -= (--xt) * ry2 << 2; + } while (rx2 * yt <= ry2 * xt); + + endWrite(); + } + + void LGFXBase::fillEllipse(std::int32_t x, std::int32_t y, std::int32_t rx, std::int32_t ry) + { + if (ry == 0) { + drawFastHLine(x - rx, y, (ry << 2) + 1); + return; + } + if (rx == 0) { + drawFastVLine(x, y - ry, (rx << 2) + 1); + return; + } + if (rx < 0 || ry < 0) return; + + std::int32_t xt, yt, i; + std::int32_t rx2 = rx * rx; + std::int32_t ry2 = ry * ry; + std::int32_t s; + + startWrite(); + + writeFastHLine(x - rx, y, (rx << 1) + 1); + i = 0; + yt = 0; + xt = rx; + s = (rx2 << 1) + ry2 * (1 - (rx << 1)); + do { + while (s < 0) s += rx2 * ((++yt << 2) + 2); + writeFillRect(x - xt, y - yt , (xt << 1) + 1, yt - i); + writeFillRect(x - xt, y + i + 1, (xt << 1) + 1, yt - i); + i = yt; + s -= (--xt) * ry2 << 2; + } while (rx2 * yt <= ry2 * xt); + + xt = 0; + yt = ry; + s = (ry2 << 1) + rx2 * (1 - (ry << 1)); + do { + while (s < 0) s += ry2 * ((++xt << 2) + 2); + writeFastHLine(x - xt, y - yt, (xt << 1) + 1); + writeFastHLine(x - xt, y + yt, (xt << 1) + 1); + s -= (--yt) * rx2 << 2; + } while(ry2 * xt <= rx2 * yt); + + endWrite(); + } + + void LGFXBase::drawRoundRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r) + { + if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; + startWrite(); + + w--; + h--; + std::int32_t len = (r << 1) + 1; + std::int32_t y1 = y + h - r; + std::int32_t y0 = y + r; + writeFastVLine(x , y0 + 1, h - len); + writeFastVLine(x + w , y0 + 1, h - len); + + std::int32_t x1 = x + w - r; + std::int32_t x0 = x + r; + writeFastHLine(x0 + 1, y , w - len); + writeFastHLine(x0 + 1, y + h , w - len); + + std::int32_t f = 1 - r; + std::int32_t ddF_y = -(r << 1); + std::int32_t ddF_x = 1; + + len = 0; + for (std::int32_t i = 0; i <= r; i++) { + len++; + if (f >= 0) { + writeFastHLine(x0 - i , y0 - r, len); + writeFastHLine(x0 - i , y1 + r, len); + writeFastHLine(x1 + i - len + 1, y1 + r, len); + writeFastHLine(x1 + i - len + 1, y0 - r, len); + writeFastVLine(x1 + r, y1 + i - len + 1, len); + writeFastVLine(x0 - r, y1 + i - len + 1, len); + writeFastVLine(x1 + r, y0 - i, len); + writeFastVLine(x0 - r, y0 - i, len); + len = 0; + r--; + ddF_y += 2; + f += ddF_y; + } + ddF_x += 2; + f += ddF_x; + } + endWrite(); + } + + void LGFXBase::fillRoundRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r) + { + if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; + startWrite(); + std::int32_t y2 = y + r; + std::int32_t y1 = y + h - r - 1; + std::int32_t ddF_y = - (r << 1); + std::int32_t delta = w + ddF_y; + writeFillRect(x, y2, w, h + ddF_y); + std::int32_t x0 = x + r; + std::int32_t f = 1 - r; + std::int32_t ddF_x = 1; + std::int32_t len = 0; + for (std::int32_t i = 0; i <= r; i++) { + len++; + if (f >= 0) { + writeFillRect(x0 - r, y2 - i , (r << 1) + delta, len); + writeFillRect(x0 - r, y1 + i - len + 1, (r << 1) + delta, len); + if (i == r) break; + len = 0; + writeFastHLine(x0 - i, y1 + r, (i << 1) + delta); + ddF_y += 2; + f += ddF_y; + writeFastHLine(x0 - i, y2 - r, (i << 1) + delta); + r--; + } + ddF_x += 2; + f += ddF_x; + } + endWrite(); + } + + void LGFXBase::drawLine(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1) + { + bool steep = abs(y1 - y0) > abs(x1 - x0); + + if (steep) { std::swap(x0, y0); std::swap(x1, y1); } + if (x0 > x1) { std::swap(x0, x1); std::swap(y0, y1); } + + std::int32_t dy = abs(y1 - y0); + std::int32_t ystep = (y1 > y0) ? 1 : -1; + std::int32_t dx = x1 - x0; + std::int32_t err = dx >> 1; + + std::int32_t xstart = steep ? _clip_t : _clip_l; + std::int32_t ystart = steep ? _clip_l : _clip_t; + std::int32_t yend = steep ? _clip_r : _clip_b; + while (x0 < xstart || y0 < ystart || y0 > yend) { + err -= dy; + if (err < 0) { + err += dx; + y0 += ystep; + } + if (++x0 > x1) return; + } + std::int32_t xs = x0; + std::int32_t dlen = 0; + + startWrite(); + if (steep) { + if (x1 > (_clip_b)) x1 = (_clip_b); + do { + ++dlen; + if ((err -= dy) < 0) { + writeFillRect(y0, xs, 1, dlen); + err += dx; + xs = x0 + 1; dlen = 0; y0 += ystep; + if ((y0 < _clip_l) || (y0 > _clip_r)) break; + } + } while (++x0 <= x1); + if (dlen) writeFillRect(y0, xs, 1, dlen); + } else { + if (x1 > (_clip_r)) x1 = (_clip_r); + do { + ++dlen; + if ((err -= dy) < 0) { + writeFillRect(xs, y0, dlen, 1); + err += dx; + xs = x0 + 1; dlen = 0; y0 += ystep; + if ((y0 < _clip_t) || (y0 > _clip_b)) break; + } + } while (++x0 <= x1); + if (dlen) writeFillRect(xs, y0, dlen, 1); + } + endWrite(); + } + + void LGFXBase::drawTriangle(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2) + { + startWrite(); + drawLine(x0, y0, x1, y1); + drawLine(x1, y1, x2, y2); + drawLine(x2, y2, x0, y0); + endWrite(); + } + + void LGFXBase::fillTriangle(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2) + { + std::int32_t a, b; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) { std::swap(y0, y1); std::swap(x0, x1); } + if (y1 > y2) { std::swap(y2, y1); std::swap(x2, x1); } + if (y0 > y1) { std::swap(y0, y1); std::swap(x0, x1); } + + if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if (x1 < a) a = x1; + else if (x1 > b) b = x1; + if (x2 < a) a = x2; + else if (x2 > b) b = x2; + drawFastHLine(a, y0, b - a + 1); + return; + } + if ((x1-x0) * (y2-y0) == (x2-x0) * (y1-y0)) { + drawLine(x0,y0,x2,y2); + return; + } + + std::int32_t dy1 = y1 - y0; + std::int32_t dy2 = y2 - y0; + bool change = ((x1 - x0) * dy2 > (x2 - x0) * dy1); + std::int32_t dx1 = abs(x1 - x0); + std::int32_t dx2 = abs(x2 - x0); + std::int32_t xstep1 = x1 < x0 ? -1 : 1; + std::int32_t xstep2 = x2 < x0 ? -1 : 1; + a = b = x0; + if (change) { + std::swap(dx1, dx2); + std::swap(dy1, dy2); + std::swap(xstep1, xstep2); + } + std::int32_t err1 = (std::max(dx1, dy1) >> 1) + + (xstep1 < 0 + ? std::min(dx1, dy1) + : dx1); + std::int32_t err2 = (std::max(dx2, dy2) >> 1) + + (xstep2 > 0 + ? std::min(dx2, dy2) + : dx2); + startWrite(); + if (y0 != y1) { + do { + err1 -= dx1; + while (err1 < 0) { err1 += dy1; a += xstep1; } + err2 -= dx2; + while (err2 < 0) { err2 += dy2; b += xstep2; } + writeFastHLine(a, y0, b - a + 1); + } while (++y0 < y1); + } + + if (change) { + b = x1; + xstep2 = x2 < x1 ? -1 : 1; + dx2 = abs(x2 - x1); + dy2 = y2 - y1; + err2 = (std::max(dx2, dy2) >> 1) + + (xstep2 > 0 + ? std::min(dx2, dy2) + : dx2); + } else { + a = x1; + dx1 = abs(x2 - x1); + dy1 = y2 - y1; + xstep1 = x2 < x1 ? -1 : 1; + err1 = (std::max(dx1, dy1) >> 1) + + (xstep1 < 0 + ? std::min(dx1, dy1) + : dx1); + } + do { + err1 -= dx1; + while (err1 < 0) { err1 += dy1; if ((a += xstep1) == x2) break; } + err2 -= dx2; + while (err2 < 0) { err2 += dy2; if ((b += xstep2) == x2) break; } + writeFastHLine(a, y0, b - a + 1); + } while (++y0 <= y2); + endWrite(); + } + + void LGFXBase::drawBezier( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2) + { + std::int32_t x = x0 - x1, y = y0 - y1; + double t = x0 - 2 * x1 + x2, r; + + startWrite(); + + if (x * (x2 - x1) > 0) { + if (y * (y2 - y1) > 0) + if (fabs((y0 - 2 * y1 + y2) / t * x) > abs(y)) { + x0 = x2; x2 = x + x1; y0 = y2; y2 = y + y1; + } + t = (x0 - x1) / t; + r = (1 - t) * ((1 - t) * y0 + 2.0 * t * y1) + t * t * y2; + t = (x0 * x2 - x1 * x1) * t / (x0 - x1); + x = floor(t + 0.5); y = floor(r + 0.5); + r = (y1 - y0) * (t - x0) / (x1 - x0) + y0; + drawBezierHelper(x0, y0, x, floor(r + 0.5), x, y); + r = (y1 - y2) * (t - x2) / (x1 - x2) + y2; + x0 = x1 = x; y0 = y; y1 = floor(r + 0.5); + } + if ((y0 - y1) * (y2 - y1) > 0) { + t = y0 - 2 * y1 + y2; t = (y0 - y1) / t; + r = (1 - t) * ((1 - t) * x0 + 2.0 * t * x1) + t * t * x2; + t = (y0 * y2 - y1 * y1) * t / (y0 - y1); + x = floor(r + 0.5); y = floor(t + 0.5); + r = (x1 - x0) * (t - y0) / (y1 - y0) + x0; + drawBezierHelper(x0, y0, floor(r + 0.5), y, x, y); + r = (x1 - x2) * (t - y2) / (y1 - y2) + x2; + x0 = x; x1 = floor(r + 0.5); y0 = y1 = y; + } + drawBezierHelper(x0, y0, x1, y1, x2, y2); + + endWrite(); + } + + void LGFXBase::drawBezierHelper( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2) + { + // Check if coordinates are sequential (replaces assert) + if (((x2 >= x1 && x1 >= x0) || (x2 <= x1 && x1 <= x0)) + && ((y2 >= y1 && y1 >= y0) || (y2 <= y1 && y1 <= y0))) + { + // Coordinates are sequential + std::int32_t sx = x2 - x1, sy = y2 - y1; + std::int32_t xx = x0 - x1, yy = y0 - y1, xy; + float dx, dy, err, cur = xx * sy - yy * sx; + + if (sx * (std::int32_t)sx + sy * (std::int32_t)sy > xx * xx + yy * yy) { + x2 = x0; x0 = sx + x1; y2 = y0; y0 = sy + y1; cur = -cur; + } + if (cur != 0) { + xx += sx; xx *= sx = x0 < x2 ? 1 : -1; + yy += sy; yy *= sy = y0 < y2 ? 1 : -1; + xy = 2 * xx * yy; xx *= xx; yy *= yy; + if (cur * sx * sy < 0) { + xx = -xx; yy = -yy; xy = -xy; cur = -cur; + } + dx = 4.0 * sy * cur * (x1 - x0) + xx - xy; + dy = 4.0 * sx * cur * (y0 - y1) + yy - xy; + xx += xx; yy += yy; err = dx + dy + xy; + do { + drawPixel(x0, y0); + if (x0 == x2 && y0 == y2) + { + return; + } + y1 = 2 * err < dx; + if (2 * err > dy) { + x0 += sx; + dx -= xy; + err += dy += yy; + } + if ( y1 ) { + y0 += sy; + dy -= xy; + err += dx += xx; + } + } while (dy < dx ); + } + drawLine(x0, y0, x2, y2); + } + } + + void LGFXBase::drawGradientLine( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, bgr888_t colorstart, bgr888_t colorend ) + { + if ( colorstart == colorend || (x0 == x1 && y0 == y1)) { + setColor(color888( colorstart.r, colorstart.g, colorstart.b ) ); + drawLine( x0, y0, x1, y1); + return; + } + + bool steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { // swap axis + std::swap(x0, y0); + std::swap(x1, y1); + } + + if (x0 > x1) { // swap points + std::swap(x0, x1); + std::swap(y0, y1); + std::swap(colorstart, colorend); + } + + std::int32_t dx = x1 - x0; + std::int32_t err = dx >> 1; + std::int32_t dy = abs(y1 - y0); + std::int32_t ystep = (y0 < y1) ? 1 : -1; + + std::int32_t diff_r = colorend.r - colorstart.r; + std::int32_t diff_g = colorend.g - colorstart.g; + std::int32_t diff_b = colorend.b - colorstart.b; + + startWrite(); + for (std::int32_t x = x0; x <= x1; x++) { + setColor(color888( (x - x0) * diff_r / dx + colorstart.r + , (x - x0) * diff_g / dx + colorstart.g + , (x - x0) * diff_b / dx + colorstart.b)); + if (steep) writePixel(y0, x); + else writePixel(x, y0); + err -= dy; + if (err < 0) { + err += dx; + y0 += ystep; + } + } + endWrite(); + } + + void LGFXBase::drawArc(std::int32_t x, std::int32_t y, std::int32_t r0, std::int32_t r1, float start, float end) + { + if (r0 < r1) std::swap(r0, r1); + if (r0 < 1) r0 = 1; + if (r1 < 1) r1 = 1; + + bool equal = fabsf(start - end) < std::numeric_limits::epsilon(); + start = fmodf(start, 360); + end = fmodf(end, 360); + if (start < 0) start += 360.0; + if (end < 0) end += 360.0; + + startWrite(); + fill_arc_helper(x, y, r0, r1, start, start); + fill_arc_helper(x, y, r0, r1, end , end); + if (!equal && (fabsf(start - end) <= 0.0001)) { start = .0; end = 360.0; } + fill_arc_helper(x, y, r0, r0, start, end); + fill_arc_helper(x, y, r1, r1, start, end); + endWrite(); + } + + void LGFXBase::fillArc(std::int32_t x, std::int32_t y, std::int32_t r0, std::int32_t r1, float start, float end) + { + if (r0 < r1) std::swap(r0, r1); + if (r0 < 1) r0 = 1; + if (r1 < 1) r1 = 1; + + bool equal = fabsf(start - end) < std::numeric_limits::epsilon(); + start = fmodf(start, 360); + end = fmodf(end, 360); + if (start < 0) start += 360.0; + if (end < 0) end += 360.0; + if (!equal && (fabsf(start - end) <= 0.0001)) { start = .0; end = 360.0; } + + startWrite(); + fill_arc_helper(x, y, r0, r1, start, end); + endWrite(); + } + + void LGFXBase::fill_arc_helper(std::int32_t cx, std::int32_t cy, std::int32_t oradius, std::int32_t iradius, float start, float end) + { + float s_cos = (cos(start * deg_to_rad)); + float e_cos = (cos(end * deg_to_rad)); + float sslope = s_cos / (sin(start * deg_to_rad)); + float eslope = -1000000; + if (end != 360.0) eslope = e_cos / (sin(end * deg_to_rad)); + float swidth = 0.5 / s_cos; + float ewidth = -0.5 / e_cos; + --iradius; + int ir2 = iradius * iradius + iradius; + int or2 = oradius * oradius + oradius; + + bool start180 = !(start < 180); + bool end180 = end < 180; + bool reversed = start + 180 < end || (end < start && start < end + 180); + + int xs = -oradius; + int y = -oradius; + int ye = oradius; + int xe = oradius + 1; + if (!reversed) { + if ( (end >= 270 || end < 90) && (start >= 270 || start < 90)) xs = 0; + else if (end < 270 && end >= 90 && start < 270 && start >= 90) xe = 1; + if ( end >= 180 && start >= 180) ye = 0; + else if (end < 180 && start < 180) y = 0; + } + do { + int y2 = y * y; + int x = xs; + if (x < 0) { + while (x * x + y2 >= or2) ++x; + if (xe != 1) xe = 1 - x; + } + float ysslope = (y + swidth) * sslope; + float yeslope = (y + ewidth) * eslope; + int len = 0; + do { + bool flg1 = start180 != (x <= ysslope); + bool flg2 = end180 != (x <= yeslope); + int distance = x * x + y2; + if (distance >= ir2 + && ((flg1 && flg2) || (reversed && (flg1 || flg2))) + && x != xe + && distance < or2 + ) { + ++len; + } else { + if (len) { + writeFastHLine(cx + x - len, cy + y, len); + len = 0; + } + if (distance >= or2) break; + if (x < 0 && distance < ir2) { x = -x; } + } + } while (++x <= xe); + } while (++y <= ye); + } + + void LGFXBase::draw_bitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, std::uint32_t fg_rawcolor, std::uint32_t bg_rawcolor) + { + if (w < 1 || h < 1) return; + setRawColor(fg_rawcolor); + std::int32_t byteWidth = (w + 7) >> 3; + std::uint_fast8_t byte = 0; + + bool fg = true; + std::int32_t j = 0; + startWrite(); + do { + std::int32_t i = 0; + do { + std::int32_t ip = i; + for (;;) { + if (!(i & 7)) byte = bitmap[i >> 3]; + if (fg != (bool)(byte & 0x80) || (++i >= w)) break; + byte <<= 1; + } + if ((ip != i) && (fg || bg_rawcolor != ~0u)) { + writeFastHLine(x + ip, y + j, i - ip); + } + fg = !fg; + if (bg_rawcolor != ~0u) setRawColor(fg ? fg_rawcolor : bg_rawcolor); + } while (i < w); + bitmap += byteWidth; + } while (++j < h); + endWrite(); + } + + void LGFXBase::draw_xbitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, std::uint32_t fg_rawcolor, std::uint32_t bg_rawcolor) + { + if (w < 1 || h < 1) return; + setRawColor(fg_rawcolor); + std::int32_t byteWidth = (w + 7) >> 3; + std::uint_fast8_t byte = 0; + + bool fg = true; + std::int32_t j = 0; + startWrite(); + do { + std::int32_t i = 0; + do { + std::int32_t ip = i; + for (;;) { + if (!(i & 7)) byte = bitmap[i >> 3]; + if (fg != (bool)(byte & 0x01) || (++i >= w)) break; + byte >>= 1; + } + if ((ip != i) && (fg || bg_rawcolor != ~0u)) { + writeFastHLine(x + ip, y + j, i - ip); + } + fg = !fg; + if (bg_rawcolor != ~0u) setRawColor(fg ? fg_rawcolor : bg_rawcolor); + } while (i < w); + bitmap += byteWidth; + } while (++j < h); + endWrite(); + } + + void LGFXBase::push_image(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, pixelcopy_t *param, bool use_dma) + { + param->src_width = w; + if (param->src_bits < 8) { // get bitwidth +// std::uint32_t x_mask = (1 << (4 - __builtin_ffs(param->src_bits))) - 1; +// std::uint32_t x_mask = (1 << ((~(param->src_bits>>1)) & 3)) - 1; + std::uint32_t x_mask = (param->src_bits == 1) ? 7 + : (param->src_bits == 2) ? 3 + : 1; + param->src_width = (w + x_mask) & (~x_mask); + } + + std::int32_t dx=0, dw=w; + if (0 < _clip_l - x) { dx = _clip_l - x; dw -= dx; x = _clip_l; } + + if (_adjust_width(x, dx, dw, _clip_l, _clip_r - _clip_l + 1)) return; + param->src_x = dx; + + + std::int32_t dy=0, dh=h; + if (0 < _clip_t - y) { dy = _clip_t - y; dh -= dy; y = _clip_t; } + if (_adjust_width(y, dy, dh, _clip_t, _clip_b - _clip_t + 1)) return; + param->src_y = dy; + + startWrite(); + pushImage_impl(x, y, dw, dh, param, use_dma); + endWrite(); + } + + bool LGFXBase::pushImageRotateZoom(std::int32_t dst_x, std::int32_t dst_y, const void* data, std::int32_t src_x, std::int32_t src_y, std::int32_t w, std::int32_t h, float angle, float zoom_x, float zoom_y, std::uint32_t transparent, const std::uint8_t bits, const bgr888_t* palette) + { + if (nullptr == data) return false; + if (zoom_x == 0.0 || zoom_y == 0.0) return true; + pixelcopy_t pc(data, getColorDepth(), (color_depth_t)bits, hasPalette(), palette, transparent ); + push_image_rotate_zoom(dst_x, dst_y, src_x, src_y, w, h, angle, zoom_x, zoom_y, &pc); + return true; + } + + void LGFXBase::push_image_rotate_zoom(std::int32_t dst_x, std::int32_t dst_y, std::int32_t src_x, std::int32_t src_y, std::int32_t w, std::int32_t h, float angle, float zoom_x, float zoom_y, pixelcopy_t *param) + { + angle *= - deg_to_rad; // Convert degrees to radians + float sin_f = sin(angle) * (1 << FP_SCALE); + float cos_f = cos(angle) * (1 << FP_SCALE); + std::int32_t min_y, max_y; + { + std::int32_t sinra = round(sin_f * zoom_x); + std::int32_t cosra = round(cos_f * zoom_y); + std::int32_t wp = (src_x - w) * sinra; + std::int32_t sx = (src_x + 1) * sinra; + std::int32_t hp = (h - src_y) * cosra; + std::int32_t sy = (-1 -src_y) * cosra; + std::int32_t tmp; + if ((sinra < 0) == (cosra < 0)) { + min_y = max_y = wp + sy; + tmp = sx + hp; + } else { + min_y = max_y = sx + sy; + tmp = wp + hp; + } + if (tmp < min_y) { + min_y = tmp; + } else { + max_y = tmp; + } + } + + max_y = std::min(_clip_b, ((max_y + (1 << (FP_SCALE - 1))) >> FP_SCALE) + dst_y) + 1; + min_y = std::max(_clip_t, ((min_y + (1 << (FP_SCALE - 1))) >> FP_SCALE) + dst_y); + if (min_y >= max_y) return; + + param->no_convert = false; + if (param->src_bits < 8) { // get bitwidth +// std::uint32_t x_mask = (1 << (4 - __builtin_ffs(param->src_bits))) - 1; +// std::uint32_t x_mask = (1 << ((~(param->src_bits>>1)) & 3)) - 1; + std::uint32_t x_mask = (param->src_bits == 1) ? 7 + : (param->src_bits == 2) ? 3 + : 1; + param->src_width = (w + x_mask) & (~x_mask); + } else { + param->src_width = w; + } + + std::int32_t xt = - dst_x; + std::int32_t yt = min_y - dst_y - 1; + + std::int32_t cos_x = round(cos_f / zoom_x); + param->src_x32_add = cos_x; + std::int32_t sin_x = - round(sin_f / zoom_x); + std::int32_t xstart = cos_x * xt + sin_x * yt + (src_x << FP_SCALE) + (1 << (FP_SCALE - 1)); + std::int32_t scale_w = w << FP_SCALE; + std::int32_t xs1 = (cos_x < 0 ? - scale_w : 1) - cos_x; + std::int32_t xs2 = (cos_x < 0 ? 0 : (1 - scale_w)) - cos_x; + if (cos_x == 0) cos_x = 1; + cos_x = -cos_x; + + std::int32_t sin_y = round(sin_f / zoom_y); + param->src_y32_add = sin_y; + std::int32_t cos_y = round(cos_f / zoom_y); + std::int32_t ystart = sin_y * xt + cos_y * yt + (src_y << FP_SCALE) + (1 << (FP_SCALE - 1)); + std::int32_t scale_h = h << FP_SCALE; + std::int32_t ys1 = (sin_y < 0 ? - scale_h : 1) - sin_y; + std::int32_t ys2 = (sin_y < 0 ? 0 : (1 - scale_h)) - sin_y; + if (sin_y == 0) sin_y = 1; + sin_y = -sin_y; + + std::int32_t cl = _clip_l; + std::int32_t cr = _clip_r + 1; + + startWrite(); + do { + std::int32_t left = cl; + std::int32_t right = cr; + xstart += sin_x; + //if (cos_x != 0) + { + std::int32_t tmp = (xstart + xs1) / cos_x; if (left < tmp) left = tmp; + tmp = (xstart + xs2) / cos_x; if (right > tmp) right = tmp; + } + ystart += cos_y; + //if (sin_y != 0) + { + std::int32_t tmp = (ystart + ys1) / sin_y; if (left < tmp) left = tmp; + tmp = (ystart + ys2) / sin_y; if (right > tmp) right = tmp; + } + if (left < right) { + param->src_x32 = xstart - left * cos_x; + std::int32_t y32 = ystart - left * sin_y; + if (y32 >= 0) { + param->src_y32 = y32; + pushImage_impl(left, min_y, right - left, 1, param, true); + } + } + } while (++min_y != max_y); + endWrite(); + } + + void LGFXBase::scroll(std::int_fast16_t dx, std::int_fast16_t dy) + { + setColor(_base_rgb888); + std::int32_t absx = abs(dx); + std::int32_t absy = abs(dy); + if (absx >= _sw || absy >= _sh) { + writeFillRect(_sx, _sy, _sw, _sh); + return; + } + + std::int32_t w = _sw - absx; + std::int32_t h = _sh - absy; + + std::int32_t src_x = dx < 0 ? _sx - dx : _sx; + std::int32_t dst_x = src_x + dx; + std::int32_t src_y = dy < 0 ? _sy - dy : _sy; + std::int32_t dst_y = src_y + dy; + + startWrite(); + copyRect_impl(dst_x, dst_y, w, h, src_x, src_y); + + if ( dx > 0) writeFillRect(_sx , dst_y, dx, h); + else if (dx < 0) writeFillRect(_sx + _sw + dx, dst_y, -dx, h); + if ( dy > 0) writeFillRect(_sx, _sy , _sw, dy); + else if (dy < 0) writeFillRect(_sx, _sy + _sh + dy, _sw, -dy); + endWrite(); + } + + void LGFXBase::copyRect(std::int32_t dst_x, std::int32_t dst_y, std::int32_t w, std::int32_t h, std::int32_t src_x, std::int32_t src_y) + { + if (src_x < dst_x) { if (src_x < 0) { w += src_x; dst_x -= src_x; src_x = 0; } if (w > _width - dst_x) w = _width - dst_x; } + else { if (dst_x < 0) { w += dst_x; src_x -= dst_x; dst_x = 0; } if (w > _width - src_x) w = _width - src_x; } + if (w < 1) return; + + if (src_y < dst_y) { if (src_y < 0) { h += src_y; dst_y -= src_y; src_y = 0; } if (h > _height - dst_y) h = _height - dst_y; } + else { if (dst_y < 0) { h += dst_y; src_y -= dst_y; dst_y = 0; } if (h > _height - src_y) h = _height - src_y; } + if (h < 1) return; + + startWrite(); + copyRect_impl(dst_x, dst_y, w, h, src_x, src_y); + endWrite(); + } + + struct paint_point_t { std::int32_t lx,rx,y,oy; }; + + static void paint_add_points(std::list& points, int lx, int rx, int y, int oy, bool* linebuf) + { + paint_point_t pt { 0, 0, y, oy }; + while (lx <= rx) { + while (lx < rx && !linebuf[lx]) ++lx; + if (!linebuf[lx]) break; + pt.lx = lx; + while (++lx <= rx && linebuf[lx]); + pt.rx = lx - 1; + points.push_back(pt); + } + } + void LGFXBase::paint(std::int32_t x, std::int32_t y) { + if (x < _clip_l || x > _clip_r || y < _clip_t || y > _clip_b) return; + bgr888_t target; + readRectRGB(x, y, 1, 1, &target); + if (_color.raw == _write_conv.convert(lgfx::color888(target.r, target.g, target.b))) return; + + pixelcopy_t p; + p.transp = _read_conv.convert(lgfx::color888(target.r, target.g, target.b)); + switch (_read_conv.depth) { + case 24: p.fp_copy = pixelcopy_t::normalcompare; break; + case 18: p.fp_copy = pixelcopy_t::normalcompare; break; + case 16: p.fp_copy = pixelcopy_t::normalcompare; break; + case 8: p.fp_copy = pixelcopy_t::normalcompare; break; + default: p.fp_copy = pixelcopy_t::bitcompare; + p.src_bits = _read_conv.depth; + p.src_mask = (1 << p.src_bits) - 1; + p.transp &= p.src_mask; + break; + } + + std::int32_t cl = _clip_l; + int w = _clip_r - cl + 1; + std::uint8_t bufIdx = 0; + bool buf0[w], buf1[w], buf2[w]; + bool* linebufs[3] = { buf0, buf1, buf2 }; + std::int32_t bufY[3] = {-2, -2, -2}; // default is out of range. + bufY[0] = y; + read_rect(cl, y, w, 1, linebufs[0], &p); + std::list points; + points.push_back({x, x, y, y}); + + startWrite(); + while (!points.empty()) { + std::int32_t y0 = bufY[bufIdx]; + auto it = points.begin(); + std::int32_t counter = 0; + while (it->y != y0 && ++it != points.end()) ++counter; + if (it == points.end()) { + if (counter < 256) { + ++bufIdx; + std::int32_t y1 = bufY[(bufIdx )%3]; + std::int32_t y2 = bufY[(bufIdx+1)%3]; + it = points.begin(); + while ((it->y != y1) && (it->y != y2) && (++it != points.end())); + } + } + + bufIdx = 0; + if (it == points.end()) { + it = points.begin(); + bufY[0] = it->y; + read_rect(cl, it->y, w, 1, linebufs[0], &p); + } else { + for (; bufIdx < 2; ++bufIdx) if (it->y == bufY[bufIdx]) break; + } + bool* linebuf = &linebufs[bufIdx][- cl]; + + int lx = it->lx; + int rx = it->rx; + int ly = it->y; + int oy = it->oy; + points.erase(it); + if (!linebuf[lx]) continue; + + int lxsav = lx - 1; + int rxsav = rx + 1; + + int cr = _clip_r; + while (lx > cl && linebuf[lx - 1]) --lx; + while (rx < cr && linebuf[rx + 1]) ++rx; + + writeFastHLine(lx, ly, rx - lx + 1); + memset(&linebuf[lx], 0, rx - lx + 1); + + int newy = ly - 1; + do { + if (newy == oy && lx >= lxsav && rxsav >= rx) continue; + if (newy < _clip_t) continue; + if (newy > _clip_b) continue; + int bidx = 0; + for (; bidx < 3; ++bidx) if (newy == bufY[bidx]) break; + if (bidx == 3) { + for (bidx = 0; bidx < 2 && (abs(bufY[bidx] - ly) <= 1); ++bidx); + bufY[bidx] = newy; + read_rect(cl, newy, w, 1, linebufs[bidx], &p); + } + bool* linebuf = &linebufs[bidx][- cl]; + if (newy == oy) { + paint_add_points(points, lx ,lxsav, newy, ly, linebuf); + paint_add_points(points, rxsav ,rx, newy, ly, linebuf); + } else { + paint_add_points(points, lx ,rx, newy, ly, linebuf); + } + } while ((newy += 2) < ly + 2); + } + endWrite(); + } + +} + diff --git a/src/lgfx/lgfx_base.hpp b/src/lgfx/lgfx_base.hpp index 4eefc80..1a283aa 100644 --- a/src/lgfx/lgfx_base.hpp +++ b/src/lgfx/lgfx_base.hpp @@ -20,20 +20,8 @@ Original Source: #ifndef LGFX_BASE_HPP_ #define LGFX_BASE_HPP_ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "lgfx_common.hpp" - namespace lgfx { class LGFXBase @@ -50,6 +38,8 @@ namespace lgfx template __attribute__ ((always_inline)) inline void setColor(T c) { _color.raw = _write_conv.convert(c); } __attribute__ ((always_inline)) inline void setRawColor(std::uint32_t c) { _color.raw = c; } + template __attribute__ ((always_inline)) inline void setBaseColor(T c) { _base_rgb888 = convert_to_rgb888(c); } + inline void clear ( void ) { _color.raw = 0; fillRect(0, 0, _width, _height); } template inline void clear ( const T& color) { setColor(color); fillRect(0, 0, _width, _height); } inline void fillScreen ( void ) { fillRect(0, 0, _width, _height); } @@ -67,31 +57,59 @@ namespace lgfx // If you do not want to the counter, call the transaction function directly. __attribute__ ((always_inline)) inline void startWrite(void) { if (1 == ++_transaction_count) beginTransaction(); } __attribute__ ((always_inline)) inline void endWrite(void) { if (_transaction_count) { if (0 == --_transaction_count) endTransaction(); } } - template inline void writePixel ( std::int32_t x, std::int32_t y , const T& color) { setColor(color); writePixel (x, y ); } - template inline void writeFastVLine( std::int32_t x, std::int32_t y , std::int32_t h, const T& color) { setColor(color); writeFastVLine(x, y , h ); } - template inline void writeFastHLine( std::int32_t x, std::int32_t y, std::int32_t w , const T& color) { setColor(color); writeFastHLine(x, y, w ); } + template inline void writePixel ( std::int32_t x, std::int32_t y , const T& color) { setColor(color); writePixel (x, y ); } + template inline void writeFastVLine( std::int32_t x, std::int32_t y , std::int32_t h, const T& color) { setColor(color); writeFastVLine(x, y , h ); } + void writeFastVLine( std::int32_t x, std::int32_t y , std::int32_t h); + template inline void writeFastHLine( std::int32_t x, std::int32_t y, std::int32_t w , const T& color) { setColor(color); writeFastHLine(x, y, w ); } + void writeFastHLine( std::int32_t x, std::int32_t y, std::int32_t w); template inline void writeFillRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T& color) { setColor(color); writeFillRect (x, y, w, h ); } - template inline void writeColor ( const T& color, std::int32_t length) { if (0 >= length) return; setColor(color); pushBlock_impl(length); } - inline void writeRawColor ( std::uint32_t color, std::int32_t length) { if (0 >= length) return; setRawColor(color); pushBlock_impl(length); } - - template inline void drawPixel ( std::int32_t x, std::int32_t y , const T& color) { setColor(color); drawPixel (x, y ); } - template inline void drawFastVLine ( std::int32_t x, std::int32_t y , std::int32_t h , const T& color) { setColor(color); drawFastVLine(x, y , h ); } - template inline void drawFastHLine ( std::int32_t x, std::int32_t y, std::int32_t w , const T& color) { setColor(color); drawFastHLine(x, y, w ); } + void writeFillRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h); + template inline void writeColor ( const T& color, std::int32_t length) { if (0 >= length) return; setColor(color); pushBlock_impl(length); } + inline void writeRawColor ( std::uint32_t color, std::int32_t length) { if (0 >= length) return; setRawColor(color); pushBlock_impl(length); } + + template inline void drawPixel ( std::int32_t x, std::int32_t y , const T& color) { setColor(color); drawPixel (x, y ); } + template inline void drawFastVLine ( std::int32_t x, std::int32_t y , std::int32_t h , const T& color) { setColor(color); drawFastVLine(x, y , h ); } + void drawFastVLine ( std::int32_t x, std::int32_t y , std::int32_t h); + template inline void drawFastHLine ( std::int32_t x, std::int32_t y, std::int32_t w , const T& color) { setColor(color); drawFastHLine(x, y, w ); } + void drawFastHLine ( std::int32_t x, std::int32_t y, std::int32_t w); template inline void fillRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h , const T& color) { setColor(color); fillRect (x, y, w, h ); } + void fillRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h); template inline void drawRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h , const T& color) { setColor(color); drawRect (x, y, w, h ); } + void drawRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h); template inline void drawRoundRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r, const T& color) { setColor(color); drawRoundRect(x, y, w, h, r); } + void drawRoundRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r); template inline void fillRoundRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r, const T& color) { setColor(color); fillRoundRect(x, y, w, h, r); } - template inline void drawCircle ( std::int32_t x, std::int32_t y , std::int32_t r, const T& color) { setColor(color); drawCircle (x, y , r); } - template inline void fillCircle ( std::int32_t x, std::int32_t y , std::int32_t r, const T& color) { setColor(color); fillCircle (x, y , r); } + void fillRoundRect ( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r); + template inline void drawCircle ( std::int32_t x, std::int32_t y , std::int32_t r, const T& color) { setColor(color); drawCircle (x, y , r); } + void drawCircle ( std::int32_t x, std::int32_t y , std::int32_t r); + template inline void fillCircle ( std::int32_t x, std::int32_t y , std::int32_t r, const T& color) { setColor(color); fillCircle (x, y , r); } + void fillCircle ( std::int32_t x, std::int32_t y , std::int32_t r); template inline void drawEllipse ( std::int32_t x, std::int32_t y, std::int32_t rx, std::int32_t ry , const T& color) { setColor(color); drawEllipse (x, y, rx, ry ); } + void drawEllipse ( std::int32_t x, std::int32_t y, std::int32_t rx, std::int32_t ry); template inline void fillEllipse ( std::int32_t x, std::int32_t y, std::int32_t rx, std::int32_t ry , const T& color) { setColor(color); fillEllipse (x, y, rx, ry ); } + void fillEllipse ( std::int32_t x, std::int32_t y, std::int32_t rx, std::int32_t ry); template inline void drawLine ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1 , const T& color) { setColor(color); drawLine( x0, y0, x1, y1 ); } + void drawLine ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1); template inline void drawTriangle ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2, const T& color) { setColor(color); drawTriangle(x0, y0, x1, y1, x2, y2); } + void drawTriangle ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2); template inline void fillTriangle ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2, const T& color) { setColor(color); fillTriangle(x0, y0, x1, y1, x2, y2); } - template inline void drawArc ( std::int32_t x, std::int32_t y, std::int32_t r1, std::int32_t r2, float start, float end, const T& color) { setColor(color); drawArc( x, y, r1, r2, start, end); } - template inline void fillArc ( std::int32_t x, std::int32_t y, std::int32_t r1, std::int32_t r2, float start, float end, const T& color) { setColor(color); fillArc( x, y, r1, r2, start, end); } + void fillTriangle ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2); + template inline void drawBezier ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2, const T& color) { setColor(color); drawBezier(x0, y0, x1, y1, x2, y2); } + void drawBezier ( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2); + template inline void drawBezierHelper(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2, const T& color) { setColor(color); drawBezierHelper(x0, y0, x1, y1, x2, y2); } + void drawBezierHelper(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2); + template inline void drawArc ( std::int32_t x, std::int32_t y, std::int32_t r0, std::int32_t r1, float angle0, float angle1, const T& color) { setColor(color); drawArc( x, y, r0, r1, angle0, angle1); } + void drawArc ( std::int32_t x, std::int32_t y, std::int32_t r0, std::int32_t r1, float angle0, float angle1); + template inline void fillArc ( std::int32_t x, std::int32_t y, std::int32_t r0, std::int32_t r1, float angle0, float angle1, const T& color) { setColor(color); fillArc( x, y, r0, r1, angle0, angle1); } + void fillArc ( std::int32_t x, std::int32_t y, std::int32_t r0, std::int32_t r1, float angle0, float angle1); template inline void drawCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint_fast8_t cornername , const T& color) { setColor(color); drawCircleHelper(x, y, r, cornername ); } + void drawCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint_fast8_t cornername); template inline void fillCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint_fast8_t corners, std::int32_t delta, const T& color) { setColor(color); fillCircleHelper(x, y, r, corners, delta); } + void fillCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint_fast8_t corners, std::int32_t delta); + + template inline void paint ( std::int32_t x, std::int32_t y, const T& color) { setColor(color); paint(x, y); } + template inline void floodFill( std::int32_t x, std::int32_t y, const T& color) { setColor(color); paint(x, y); } + inline void floodFill( std::int32_t x, std::int32_t y ) { paint(x, y); } __attribute__ ((always_inline)) inline static std::uint8_t color332(std::uint8_t r, std::uint8_t g, std::uint8_t b) { return lgfx::color332(r, g, b); } __attribute__ ((always_inline)) inline static std::uint16_t color565(std::uint8_t r, std::uint8_t g, std::uint8_t b) { return lgfx::color565(r, g, b); } @@ -109,6 +127,7 @@ namespace lgfx __attribute__ ((always_inline)) inline color_conv_t* getColorConverter(void) { return &_write_conv; } __attribute__ ((always_inline)) inline bool hasPalette (void) const { return _palette_count; } __attribute__ ((always_inline)) inline bool isSPIShared(void) const { return _spi_shared; } + __attribute__ ((always_inline)) inline bool isReadable(void) const { return isReadable_impl(); } __attribute__ ((always_inline)) inline bool getSwapBytes (void) const { return _swapBytes; } __attribute__ ((always_inline)) inline void setSwapBytes(bool swap) { _swapBytes = swap; } @@ -119,42 +138,19 @@ namespace lgfx void setSPIShared(bool shared) { _spi_shared = shared; } - void setAddrWindow(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) - { - if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; - bool tr = !_transaction_count; - if (tr) beginTransaction(); - setWindow(x, y, x + w - 1, y + h - 1); - if (tr) endTransaction(); - } - - void setClipRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) { - if (x < 0) { w += x; x = 0; } - if (w > _width - x) w = _width - x; - if (w < 1) { x = 0; w = 0; } - _clip_l = x; - _clip_r = x + w - 1; + void setAddrWindow(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h); + void setClipRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h); + void getClipRect(std::int32_t *x, std::int32_t *y, std::int32_t *w, std::int32_t *h); + void clearClipRect(void); - if (y < 0) { h += y; y = 0; } - if (h > _height - y) h = _height - y; - if (h < 1) { y = 0; h = 0; } - _clip_t = y; - _clip_b = y + h - 1; - } - - void getClipRect(std::int32_t *x, std::int32_t *y, std::int32_t *w, std::int32_t *h) { - *x = _clip_l; - *w = _clip_r - *x + 1; - *y = _clip_t; - *h = _clip_b - *y + 1; - } - - void clearClipRect(void) { - _clip_l = 0; - _clip_r = _width - 1; - _clip_t = 0; - _clip_b = _height - 1; + template + void setScrollRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T& color) { + _base_rgb888 = convert_to_rgb888(color); + setScrollRect(x, y, w, h); } + void setScrollRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h); + void getScrollRect(std::int32_t *x, std::int32_t *y, std::int32_t *w, std::int32_t *h); + void clearScrollRect(void); __attribute__ ((always_inline)) inline void drawPixel(std::int32_t x, std::int32_t y) @@ -172,529 +168,12 @@ namespace lgfx writeFillRect_impl(x, y, 1, 1); } - void drawFastVLine(std::int32_t x, std::int32_t y, std::int32_t h) - { - _adjust_abs(y, h); - bool tr = !_transaction_count; - if (tr) beginTransaction(); - writeFastVLine(x, y, h); - if (tr) endTransaction(); - } - - void writeFastVLine(std::int32_t x, std::int32_t y, std::int32_t h) - { - if (x < _clip_l || x > _clip_r) return; - auto ct = _clip_t; - if (y < ct) { h += y - ct; y = ct; } - auto cb = _clip_b + 1 - y; - if (h > cb) h = cb; - if (h < 1) return; - - writeFillRect_impl(x, y, 1, h); - } - - void drawFastHLine(std::int32_t x, std::int32_t y, std::int32_t w) - { - _adjust_abs(x, w); - bool tr = !_transaction_count; - if (tr) beginTransaction(); - writeFastHLine(x, y, w); - if (tr) endTransaction(); - } - - void writeFastHLine(std::int32_t x, std::int32_t y, std::int32_t w) - { - if (y < _clip_t || y > _clip_b) return; - auto cl = _clip_l; - if (x < cl) { w += x - cl; x = cl; } - auto cr = _clip_r + 1 - x; - if (w > cr) w = cr; - if (w < 1) return; - - writeFillRect_impl(x, y, w, 1); - } - - void fillRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) - { - _adjust_abs(x, w); - _adjust_abs(y, h); - bool tr = !_transaction_count; - if (tr) beginTransaction(); - writeFillRect(x, y, w, h); - if (tr) endTransaction(); - } - - void writeFillRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) - { - auto cl = _clip_l; - if (x < cl) { w += x - cl; x = cl; } - auto cr = _clip_r + 1 - x; - if (w > cr) w = cr; - if (w < 1) return; - - auto ct = _clip_t; - if (y < ct) { h += y - ct; y = ct; } - auto cb = _clip_b + 1 - y; - if (h > cb) h = cb; - if (h < 1) return; - - writeFillRect_impl(x, y, w, h); - } - __attribute__ ((always_inline)) inline void writeFillRectPreclipped(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) { writeFillRect_impl(x, y, w, h); } - void drawRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) - { - if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; - bool tr = !_transaction_count; - if (tr) beginTransaction(); - writeFastHLine(x, y , w); - if (--h) { - writeFastHLine(x, y + h , w); - if (--h) { - writeFastVLine(x , ++y, h); - writeFastVLine(x + w - 1, y, h); - } - } - if (tr) endTransaction(); - } - - void drawCircle(std::int32_t x, std::int32_t y, std::int32_t r) - { - if ( r <= 0 ) { - drawPixel(x, y); - return; - } - - startWrite(); - std::int32_t f = 1 - r; - std::int32_t ddF_y = - (r << 1); - std::int32_t ddF_x = 1; - std::int32_t i = 0; - std::int32_t j = -1; - do { - while (f < 0) { - ++i; - f += (ddF_x += 2); - } - f += (ddF_y += 2); - - writeFastHLine(x - i , y + r, i - j); - writeFastHLine(x - i , y - r, i - j); - writeFastHLine(x + j + 1, y - r, i - j); - writeFastHLine(x + j + 1, y + r, i - j); - - writeFastVLine(x + r, y + j + 1, i - j); - writeFastVLine(x + r, y - i , i - j); - writeFastVLine(x - r, y - i , i - j); - writeFastVLine(x - r, y + j + 1, i - j); - j = i; - } while (i < --r); - endWrite(); - } - - void drawCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint8_t cornername) - { - if (r <= 0) return; - std::int32_t f = 1 - r; - std::int32_t ddF_y = - (r << 1); - std::int32_t ddF_x = 1; - std::int32_t i = 0; - std::int32_t j = 0; - - startWrite(); - do { - while (f < 0) { - ++i; - f += (ddF_x += 2); - } - f += (ddF_y += 2); - - if (cornername & 0x1) { // left top - writeFastHLine(x - i, y - r, i - j); - writeFastVLine(x - r, y - i, i - j); - } - if (cornername & 0x2) { // right top - writeFastVLine(x + r , y - i, i - j); - writeFastHLine(x + j + 1, y - r, i - j); - } - if (cornername & 0x4) { // right bottom - writeFastHLine(x + j + 1, y + r , i - j); - writeFastVLine(x + r , y + j + 1, i - j); - } - if (cornername & 0x8) { // left bottom - writeFastVLine(x - r, y + j + 1, i - j); - writeFastHLine(x - i, y + r , i - j); - } - j = i; - } while (i < --r); - endWrite(); - } - - void fillCircle(std::int32_t x, std::int32_t y, std::int32_t r) { - startWrite(); - writeFastHLine(x - r, y, (r << 1) + 1); - fillCircleHelper(x, y, r, 3, 0); - endWrite(); - } - - void fillCircleHelper(std::int32_t x, std::int32_t y, std::int32_t r, std::uint_fast8_t corners, std::int32_t delta) - { - if (r <= 0) return; - - ++delta; - - std::int32_t f = 1 - r; - std::int32_t ddF_y = - (r << 1); - std::int32_t ddF_x = 1; - std::int32_t i = 0; - - startWrite(); - do { - std::int32_t len = 0; - while (f < 0) { - f += (ddF_x += 2); - ++len; - } - i += len; - f += (ddF_y += 2); - - if (corners & 0x1) { - if (len) writeFillRect(x - r, y + i - len + 1, (r << 1) + delta, len); - writeFastHLine(x - i, y + r, (i << 1) + delta); - } - if (corners & 0x2) { - writeFastHLine(x - i, y - r, (i << 1) + delta); - if (len) writeFillRect(x - r, y - i, (r << 1) + delta, len); - } - } while (i < --r); - endWrite(); - } - - void drawEllipse(std::int32_t x0, std::int32_t y0, std::int32_t rx, std::int32_t ry) - { - if (ry == 0) { - drawFastHLine(x0 - rx, y0, (ry << 2) + 1); - return; - } - if (rx == 0) { - drawFastVLine(x0, y0 - ry, (rx << 2) + 1); - return; - } - if (rx < 0 || ry < 0) return; - - std::int32_t x, y, s, i; - std::int32_t rx2 = rx * rx; - std::int32_t ry2 = ry * ry; - - startWrite(); - - i = -1; - x = 0; - y = ry; - s = (ry2 << 1) + rx2 * (1 - (ry << 1)); - do { - while ( s < 0 ) s += ry2 * ((++x << 2) + 2); - writeFastHLine(x0 - x , y0 - y, x - i); - writeFastHLine(x0 + i + 1, y0 - y, x - i); - writeFastHLine(x0 + i + 1, y0 + y, x - i); - writeFastHLine(x0 - x , y0 + y, x - i); - i = x; - s -= (--y) * rx2 << 2; - } while (ry2 * x <= rx2 * y); - - i = -1; - y = 0; - x = rx; - s = (rx2 << 1) + ry2 * (1 - (rx << 1)); - do { - while ( s < 0 ) s += rx2 * ((++y << 2) + 2); - writeFastVLine(x0 - x, y0 - y , y - i); - writeFastVLine(x0 - x, y0 + i + 1, y - i); - writeFastVLine(x0 + x, y0 + i + 1, y - i); - writeFastVLine(x0 + x, y0 - y , y - i); - i = y; - s -= (--x) * ry2 << 2; - } while (rx2 * y <= ry2 * x); - - endWrite(); - } - - void fillEllipse(std::int32_t x0, std::int32_t y0, std::int32_t rx, std::int32_t ry) - { - if (ry == 0) { - drawFastHLine(x0 - rx, y0, (ry << 2) + 1); - return; - } - if (rx == 0) { - drawFastVLine(x0, y0 - ry, (rx << 2) + 1); - return; - } - if (rx < 0 || ry < 0) return; - - std::int32_t x, y, i; - std::int32_t rx2 = rx * rx; - std::int32_t ry2 = ry * ry; - std::int32_t s; - - startWrite(); - - writeFastHLine(x0 - rx, y0, (rx << 1) + 1); - i = 0; - y = 0; - x = rx; - s = (rx2 << 1) + ry2 * (1 - (rx << 1)); - do { - while (s < 0) s += rx2 * ((++y << 2) + 2); - writeFillRect(x0 - x, y0 - y , (x << 1) + 1, y - i); - writeFillRect(x0 - x, y0 + i + 1, (x << 1) + 1, y - i); - i = y; - s -= (--x) * ry2 << 2; - } while (rx2 * y <= ry2 * x); - - x = 0; - y = ry; - s = (ry2 << 1) + rx2 * (1 - (ry << 1)); - do { - while (s < 0) s += ry2 * ((++x << 2) + 2); - writeFastHLine(x0 - x, y0 - y, (x << 1) + 1); - writeFastHLine(x0 - x, y0 + y, (x << 1) + 1); - s -= (--y) * rx2 << 2; - } while(ry2 * x <= rx2 * y); - - endWrite(); - } - - - void drawRoundRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r) - { - if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; - startWrite(); - - w--; - h--; - std::int32_t len = (r << 1) + 1; - std::int32_t y1 = y + h - r; - std::int32_t y0 = y + r; - writeFastVLine(x , y0 + 1, h - len); - writeFastVLine(x + w , y0 + 1, h - len); - - std::int32_t x1 = x + w - r; - std::int32_t x0 = x + r; - writeFastHLine(x0 + 1, y , w - len); - writeFastHLine(x0 + 1, y + h , w - len); - - std::int32_t f = 1 - r; - std::int32_t ddF_y = -(r << 1); - std::int32_t ddF_x = 1; - - len = 0; - for (std::int32_t i = 0; i <= r; i++) { - len++; - if (f >= 0) { - writeFastHLine(x0 - i , y0 - r, len); - writeFastHLine(x0 - i , y1 + r, len); - writeFastHLine(x1 + i - len + 1, y1 + r, len); - writeFastHLine(x1 + i - len + 1, y0 - r, len); - writeFastVLine(x1 + r, y1 + i - len + 1, len); - writeFastVLine(x0 - r, y1 + i - len + 1, len); - writeFastVLine(x1 + r, y0 - i, len); - writeFastVLine(x0 - r, y0 - i, len); - len = 0; - r--; - ddF_y += 2; - f += ddF_y; - } - ddF_x += 2; - f += ddF_x; - } - endWrite(); - } - - void fillRoundRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, std::int32_t r) - { - if (_adjust_abs(x, w)||_adjust_abs(y, h)) return; - startWrite(); - std::int32_t y2 = y + r; - std::int32_t y1 = y + h - r - 1; - std::int32_t ddF_y = - (r << 1); - std::int32_t delta = w + ddF_y; - writeFillRect(x, y2, w, h + ddF_y); - std::int32_t x0 = x + r; - std::int32_t f = 1 - r; - std::int32_t ddF_x = 1; - std::int32_t len = 0; - for (std::int32_t i = 0; i <= r; i++) { - len++; - if (f >= 0) { - writeFillRect(x0 - r, y2 - i , (r << 1) + delta, len); - writeFillRect(x0 - r, y1 + i - len + 1, (r << 1) + delta, len); - if (i == r) break; - len = 0; - writeFastHLine(x0 - i, y1 + r, (i << 1) + delta); - ddF_y += 2; - f += ddF_y; - writeFastHLine(x0 - i, y2 - r, (i << 1) + delta); - r--; - } - ddF_x += 2; - f += ddF_x; - } - endWrite(); - } - - void drawLine(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1) - { - bool steep = abs(y1 - y0) > abs(x1 - x0); - - if (steep) { std::swap(x0, y0); std::swap(x1, y1); } - if (x0 > x1) { std::swap(x0, x1); std::swap(y0, y1); } - - std::int32_t dy = abs(y1 - y0); - std::int32_t ystep = (y1 > y0) ? 1 : -1; - std::int32_t dx = x1 - x0; - std::int32_t err = dx >> 1; - - std::int32_t xstart = steep ? _clip_t : _clip_l; - std::int32_t ystart = steep ? _clip_l : _clip_t; - std::int32_t yend = steep ? _clip_r : _clip_b; - while (x0 < xstart || y0 < ystart || y0 > yend) { - err -= dy; - if (err < 0) { - err += dx; - y0 += ystep; - } - if (++x0 > x1) return; - } - std::int32_t xs = x0; - std::int32_t dlen = 0; - - startWrite(); - if (steep) { - if (x1 > (_clip_b)) x1 = (_clip_b); - do { - ++dlen; - if ((err -= dy) < 0) { - writeFillRect(y0, xs, 1, dlen); - err += dx; - xs = x0 + 1; dlen = 0; y0 += ystep; - if ((y0 < _clip_l) || (y0 > _clip_r)) break; - } - } while (++x0 <= x1); - if (dlen) writeFillRect(y0, xs, 1, dlen); - } else { - if (x1 > (_clip_r)) x1 = (_clip_r); - do { - ++dlen; - if ((err -= dy) < 0) { - writeFillRect(xs, y0, dlen, 1); - err += dx; - xs = x0 + 1; dlen = 0; y0 += ystep; - if ((y0 < _clip_t) || (y0 > _clip_b)) break; - } - } while (++x0 <= x1); - if (dlen) writeFillRect(xs, y0, dlen, 1); - } - endWrite(); - } - - void drawTriangle(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2) - { - startWrite(); - drawLine(x0, y0, x1, y1); - drawLine(x1, y1, x2, y2); - drawLine(x2, y2, x0, y0); - endWrite(); - } - - void fillTriangle(std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, std::int32_t x2, std::int32_t y2) - { - std::int32_t a, b; - - // Sort coordinates by Y order (y2 >= y1 >= y0) - if (y0 > y1) { std::swap(y0, y1); std::swap(x0, x1); } - if (y1 > y2) { std::swap(y2, y1); std::swap(x2, x1); } - if (y0 > y1) { std::swap(y0, y1); std::swap(x0, x1); } - - if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing - a = b = x0; - if (x1 < a) a = x1; - else if (x1 > b) b = x1; - if (x2 < a) a = x2; - else if (x2 > b) b = x2; - drawFastHLine(a, y0, b - a + 1); - return; - } - if ((x1-x0) * (y2-y0) == (x2-x0) * (y1-y0)) { - drawLine(x0,y0,x2,y2); - return; - } - - std::int32_t dy1 = y1 - y0; - std::int32_t dy2 = y2 - y0; - bool change = ((x1 - x0) * dy2 > (x2 - x0) * dy1); - std::int32_t dx1 = abs(x1 - x0); - std::int32_t dx2 = abs(x2 - x0); - std::int32_t xstep1 = x1 < x0 ? -1 : 1; - std::int32_t xstep2 = x2 < x0 ? -1 : 1; - a = b = x0; - if (change) { - std::swap(dx1, dx2); - std::swap(dy1, dy2); - std::swap(xstep1, xstep2); - } - std::int32_t err1 = (std::max(dx1, dy1) >> 1) - + (xstep1 < 0 - ? std::min(dx1, dy1) - : dx1); - std::int32_t err2 = (std::max(dx2, dy2) >> 1) - + (xstep2 > 0 - ? std::min(dx2, dy2) - : dx2); - startWrite(); - if (y0 != y1) { - do { - err1 -= dx1; - while (err1 < 0) { err1 += dy1; a += xstep1; } - err2 -= dx2; - while (err2 < 0) { err2 += dy2; b += xstep2; } - writeFastHLine(a, y0, b - a + 1); - } while (++y0 < y1); - } - - if (change) { - b = x1; - xstep2 = x2 < x1 ? -1 : 1; - dx2 = abs(x2 - x1); - dy2 = y2 - y1; - err2 = (std::max(dx2, dy2) >> 1) - + (xstep2 > 0 - ? std::min(dx2, dy2) - : dx2); - } else { - a = x1; - dx1 = abs(x2 - x1); - dy1 = y2 - y1; - xstep1 = x2 < x1 ? -1 : 1; - err1 = (std::max(dx1, dy1) >> 1) - + (xstep1 < 0 - ? std::min(dx1, dy1) - : dx1); - } - do { - err1 -= dx1; - while (err1 < 0) { err1 += dy1; if ((a += xstep1) == x2) break; } - err2 -= dx2; - while (err2 < 0) { err2 += dy2; if ((b += xstep2) == x2) break; } - writeFastHLine(a, y0, b - a + 1); - } while (++y0 <= y2); - endWrite(); - } - __attribute__ ((always_inline)) inline void drawGradientHLine( std::int32_t x, std::int32_t y, std::int32_t w, bgr888_t colorstart, bgr888_t colorend ) { drawGradientLine( x, y, x + w - 1, y, colorstart, colorend ); @@ -705,155 +184,13 @@ namespace lgfx drawGradientLine( x, y, x, y + h - 1, colorstart, colorend ); } - void drawGradientLine( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, bgr888_t colorstart, bgr888_t colorend ) - { - if ( colorstart == colorend || (x0 == x1 && y0 == y1)) { - setColor(color888( colorstart.r, colorstart.g, colorstart.b ) ); - drawLine( x0, y0, x1, y1); - return; - } - - bool steep = abs(y1 - y0) > abs(x1 - x0); - if (steep) { // swap axis - std::swap(x0, y0); - std::swap(x1, y1); - } - - if (x0 > x1) { // swap points - std::swap(x0, x1); - std::swap(y0, y1); - std::swap(colorstart, colorend); - } - - std::int32_t dx = x1 - x0; - std::int32_t err = dx >> 1; - std::int32_t dy = abs(y1 - y0); - std::int32_t ystep = (y0 < y1) ? 1 : -1; - - std::int32_t diff_r = colorend.r - colorstart.r; - std::int32_t diff_g = colorend.g - colorstart.g; - std::int32_t diff_b = colorend.b - colorstart.b; - - startWrite(); - for (std::int32_t x = x0; x <= x1; x++) { - setColor(color888( (x - x0) * diff_r / dx + colorstart.r - , (x - x0) * diff_g / dx + colorstart.g - , (x - x0) * diff_b / dx + colorstart.b)); - if (steep) writePixel(y0, x); - else writePixel(x, y0); - err -= dy; - if (err < 0) { - err += dx; - y0 += ystep; - } - } - endWrite(); - } - - void drawArc(std::int32_t x, std::int32_t y, std::int32_t r1, std::int32_t r2, float start, float end) - { - if (r1 < r2) std::swap(r1, r2); - if (r1 < 1) r1 = 1; - if (r2 < 1) r2 = 1; - - bool equal = fabsf(start - end) < std::numeric_limits::epsilon(); - start = fmodf(start, 360); - end = fmodf(end, 360); - if (start < 0) start += 360.0; - if (end < 0) end += 360.0; - - startWrite(); - fill_arc_helper(x, y, r1, r2, start, start); - fill_arc_helper(x, y, r1, r2, end , end); - if (!equal && (fabsf(start - end) <= 0.0001)) { start = .0; end = 360.0; } - fill_arc_helper(x, y, r1, r1, start, end); - fill_arc_helper(x, y, r2, r2, start, end); - endWrite(); - } - - void fillArc(std::int32_t x, std::int32_t y, std::int32_t r1, std::int32_t r2, float start, float end) - { - if (r1 < r2) std::swap(r1, r2); - if (r1 < 1) r1 = 1; - if (r2 < 1) r2 = 1; - - bool equal = fabsf(start - end) < std::numeric_limits::epsilon(); - start = fmodf(start, 360); - end = fmodf(end, 360); - if (start < 0) start += 360.0; - if (end < 0) end += 360.0; - if (!equal && (fabsf(start - end) <= 0.0001)) { start = .0; end = 360.0; } - - startWrite(); - fill_arc_helper(x, y, r1, r2, start, end); - endWrite(); - } + void drawGradientLine( std::int32_t x0, std::int32_t y0, std::int32_t x1, std::int32_t y1, bgr888_t colorstart, bgr888_t colorend ); template void drawBitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, const T& color ) { draw_bitmap(x, y, bitmap, w, h, _write_conv.convert(color)); } template void drawBitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, const T& fgcolor, const T& bgcolor) { draw_bitmap(x, y, bitmap, w, h, _write_conv.convert(fgcolor), _write_conv.convert(bgcolor)); } template void drawXBitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, const T& color ) { draw_xbitmap(x, y, bitmap, w, h, _write_conv.convert(color)); } template void drawXBitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, const T& fgcolor, const T& bgcolor) { draw_xbitmap(x, y, bitmap, w, h, _write_conv.convert(fgcolor), _write_conv.convert(bgcolor)); } - void draw_bitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, std::uint32_t fg_rawcolor, std::uint32_t bg_rawcolor = ~0u) - { - if (w < 1 || h < 1) return; - setRawColor(fg_rawcolor); - std::int32_t byteWidth = (w + 7) >> 3; - std::uint_fast8_t byte = 0; - - bool fg = true; - std::int32_t j = 0; - startWrite(); - do { - std::int32_t i = 0; - do { - std::int32_t ip = i; - for (;;) { - if (!(i & 7)) byte = bitmap[i >> 3]; - if (fg != (bool)(byte & 0x80) || (++i >= w)) break; - byte <<= 1; - } - if ((ip != i) && (fg || bg_rawcolor != ~0u)) { - writeFastHLine(x + ip, y + j, i - ip); - } - fg = !fg; - if (bg_rawcolor != ~0u) setRawColor(fg ? fg_rawcolor : bg_rawcolor); - } while (i < w); - bitmap += byteWidth; - } while (++j < h); - endWrite(); - } - - void draw_xbitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, std::uint32_t fg_rawcolor, std::uint32_t bg_rawcolor = ~0u) - { - if (w < 1 || h < 1) return; - setRawColor(fg_rawcolor); - std::int32_t byteWidth = (w + 7) >> 3; - std::uint_fast8_t byte = 0; - - bool fg = true; - std::int32_t j = 0; - startWrite(); - do { - std::int32_t i = 0; - do { - std::int32_t ip = i; - for (;;) { - if (!(i & 7)) byte = bitmap[i >> 3]; - if (fg != (bool)(byte & 0x01) || (++i >= w)) break; - byte >>= 1; - } - if ((ip != i) && (fg || bg_rawcolor != ~0u)) { - writeFastHLine(x + ip, y + j, i - ip); - } - fg = !fg; - if (bg_rawcolor != ~0u) setRawColor(fg ? fg_rawcolor : bg_rawcolor); - } while (i < w); - bitmap += byteWidth; - } while (++j < h); - endWrite(); - } - void pushColors(const std::uint8_t* data, std::int32_t len) { pushColors((rgb332_t*)data, len); @@ -883,7 +220,7 @@ namespace lgfx template void pushColors(const T *src, std::int32_t len) { - pixelcopy_t p(src, _write_conv.depth, T::depth, _palette_count); + pixelcopy_t p(src, _write_conv.depth, get_depth::value, _palette_count); startWrite(); pushColors_impl(len, &p); endWrite(); @@ -908,7 +245,7 @@ namespace lgfx template inline void readRect( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, T* data) { - pixelcopy_t p(nullptr, T::depth, _read_conv.depth, false, _palette); + pixelcopy_t p(nullptr, get_depth::value, _read_conv.depth, false, _palette); if (p.fp_copy==nullptr) { p.fp_copy = pixelcopy_t::get_fp_normalcopy_dst(_read_conv.depth); } read_rect(x, y, w, h, data, &p); } @@ -938,276 +275,131 @@ namespace lgfx } template void pushRect( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data) { pushImage(x, y, w, h, data); } - template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data) { - pixelcopy_t p(data, _write_conv.depth, T::depth, _palette_count, nullptr); - if (p.fp_copy==nullptr) { p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } - push_image(x, y, w, h, &p); - } - template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data, const T& transparent) { - pixelcopy_t p(data, _write_conv.depth, T::depth, _palette_count, nullptr, _write_conv.convert(transparent)); - if (p.fp_copy==nullptr) { p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } - if (p.fp_skip==nullptr) { p.fp_skip = pixelcopy_t::normalskip; } - push_image(x, y, w, h, &p); - } - template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data , const std::uint8_t bits, const T* palette) { - pixelcopy_t p(data, _write_conv.depth, (color_depth_t)bits, _palette_count, palette ); - p.fp_copy = pixelcopy_t::get_fp_palettecopy(_write_conv.depth); - push_image(x, y, w, h, &p); - } - template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, std::uint32_t transparent, const std::uint8_t bits, const T* palette) { - pixelcopy_t p(data, _write_conv.depth, (color_depth_t)bits, _palette_count, palette, transparent ); - p.fp_copy = pixelcopy_t::get_fp_palettecopy(_write_conv.depth); - push_image(x, y, w, h, &p); - } - - void pushImage(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const std::uint16_t* data, std::uint32_t transp = ~0u) + template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data) { - pixelcopy_t p(data, _write_conv.depth, rgb565_2Byte, _palette_count, nullptr, transp == ~0u ? ~0u : _write_conv.convert((std::uint16_t)transp)); - if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + pixelcopy_t p(data, _write_conv.depth, get_depth::value, _palette_count, nullptr); + if (std::is_same::value) { p.no_convert = false; p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } - push_image(x, y, w, h, &p); - } - void pushImage(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, std::uint32_t transp = ~0u) - { - pixelcopy_t p(data, _write_conv.depth, rgb888_3Byte, _palette_count, nullptr, transp == ~0u ? ~0u : _write_conv.convert(transp)); - if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + if (std::is_same::value) { p.no_convert = false; p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } + if (p.fp_copy==nullptr) { p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } push_image(x, y, w, h, &p); } - template void pushImageDMA( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data) { pixelcopy_t p(data, _write_conv.depth, T::depth, _palette_count, nullptr ); push_image(x, y, w, h, &p, true); } - template void pushImageDMA( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data , const T& transparent) { pixelcopy_t p(data, _write_conv.depth, T::depth, _palette_count, nullptr, _write_conv.convert(transparent)); push_image(x, y, w, h, &p, true); } - template void pushImageDMA( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data , const std::uint8_t bits, const T* palette) { pixelcopy_t p(data, _write_conv.depth, (color_depth_t)bits, _palette_count, palette ); push_image(x, y, w, h, &p, true); } - template void pushImageDMA( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, std::uint32_t transparent, const std::uint8_t bits, const T* palette) { pixelcopy_t p(data, _write_conv.depth, (color_depth_t)bits, _palette_count, palette, transparent ); push_image(x, y, w, h, &p, true); } - - void pushImageDMA(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const std::uint16_t* data, std::uint32_t transp = ~0u) + template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data, const U& transparent) { - pixelcopy_t p(data, _write_conv.depth, rgb565_2Byte, _palette_count, nullptr, transp == ~0u? ~0u : _write_conv.convert((std::uint16_t)transp)); - if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + uint32_t tr = (std::is_same::value) + ? transparent + : get_fp_convert_src(get_depth::value, false)(transparent); + pixelcopy_t p(data, _write_conv.depth, get_depth::value, _palette_count, nullptr, tr); + if (std::is_same::value) { + p.transp = getSwap16(tr); p.no_convert = false; p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } - push_image(x, y, w, h, &p, true); - } - void pushImageDMA(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, std::uint32_t transp = ~0u) - { - pixelcopy_t p(data, _write_conv.depth, rgb888_3Byte, _palette_count, nullptr, transp == ~0u ? ~0u : _write_conv.convert(transp)); - if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + if (std::is_same::value) { + p.transp = getSwap24(tr); p.no_convert = false; p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } - push_image(x, y, w, h, &p, true); + if (p.fp_copy==nullptr) { p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } + if (p.fp_skip==nullptr) { p.fp_skip = pixelcopy_t::normalskip; } + push_image(x, y, w, h, &p); } - void push_image(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, pixelcopy_t *param, bool use_dma = false) + void pushImage(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const std::uint16_t* data) { - param->src_width = w; - if (param->src_bits < 8) { // get bitwidth -// std::uint32_t x_mask = (1 << (4 - __builtin_ffs(param->src_bits))) - 1; -// std::uint32_t x_mask = (1 << ((~(param->src_bits>>1)) & 3)) - 1; - std::uint32_t x_mask = (param->src_bits == 1) ? 7 - : (param->src_bits == 2) ? 3 - : 1; - param->src_width = (w + x_mask) & (~x_mask); + if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + pushImage(x, y, w, h, (const rgb565_t*)data); + } else { + pushImage(x, y, w, h, (const swap565_t*)data); } - - std::int32_t dx=0, dw=w; - if (0 < _clip_l - x) { dx = _clip_l - x; dw -= dx; x = _clip_l; } - - if (_adjust_width(x, dx, dw, _clip_l, _clip_r - _clip_l + 1)) return; - param->src_x = dx; - - - std::int32_t dy=0, dh=h; - if (0 < _clip_t - y) { dy = _clip_t - y; dh -= dy; y = _clip_t; } - if (_adjust_width(y, dy, dh, _clip_t, _clip_b - _clip_t + 1)) return; - param->src_y = dy; - - startWrite(); - pushImage_impl(x, y, dw, dh, param, use_dma); - endWrite(); } - bool pushImageRotateZoom(std::int32_t dst_x, std::int32_t dst_y, const void* data, std::int32_t src_x, std::int32_t src_y, std::int32_t w, std::int32_t h, float angle, float zoom_x, float zoom_y, std::uint32_t transparent, const std::uint8_t bits, const bgr888_t* palette) { - if (nullptr == data) return false; - if (zoom_x == 0.0 || zoom_y == 0.0) return true; - pixelcopy_t pc(data, getColorDepth(), (color_depth_t)bits, hasPalette(), palette, transparent ); - push_image_rotate_zoom(dst_x, dst_y, src_x, src_y, w, h, angle, zoom_x, zoom_y, &pc); - return true; + void pushImage(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data) + { + if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + pushImage(x, y, w, h, (const rgb888_t*)data); + } else { + pushImage(x, y, w, h, (const bgr888_t*)data); + } } - void push_image_rotate_zoom(std::int32_t dst_x, std::int32_t dst_y, std::int32_t src_x, std::int32_t src_y, std::int32_t w, std::int32_t h, float angle, float zoom_x, float zoom_y, pixelcopy_t *param) + template + void pushImage(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const std::uint16_t* data, const U& transparent) { - angle *= - deg_to_rad; // Convert degrees to radians - float sin_f = sin(angle) * (1 << FP_SCALE); - float cos_f = cos(angle) * (1 << FP_SCALE); - std::int32_t min_y, max_y; - { - std::int32_t sinra = round(sin_f * zoom_x); - std::int32_t cosra = round(cos_f * zoom_y); - std::int32_t wp = (src_x - w) * sinra; - std::int32_t sx = (src_x + 1) * sinra; - std::int32_t hp = (h - src_y) * cosra; - std::int32_t sy = (-1 -src_y) * cosra; - std::int32_t tmp; - if ((sinra < 0) == (cosra < 0)) { - min_y = max_y = wp + sy; - tmp = sx + hp; - } else { - min_y = max_y = sx + sy; - tmp = wp + hp; - } - if (tmp < min_y) { - min_y = tmp; - } else { - max_y = tmp; - } + if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + pushImage(x, y, w, h, (const rgb565_t*)data, transparent); + } else { + pushImage(x, y, w, h, (const swap565_t*)data, transparent); } + } - max_y = std::min(_clip_b, ((max_y + (1 << (FP_SCALE - 1))) >> FP_SCALE) + dst_y) + 1; - min_y = std::max(_clip_t, ((min_y + (1 << (FP_SCALE - 1))) >> FP_SCALE) + dst_y); - if (min_y >= max_y) return; - - param->no_convert = false; - if (param->src_bits < 8) { // get bitwidth -// std::uint32_t x_mask = (1 << (4 - __builtin_ffs(param->src_bits))) - 1; -// std::uint32_t x_mask = (1 << ((~(param->src_bits>>1)) & 3)) - 1; - std::uint32_t x_mask = (param->src_bits == 1) ? 7 - : (param->src_bits == 2) ? 3 - : 1; - param->src_width = (w + x_mask) & (~x_mask); + template + void pushImage(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, const U& transparent) + { + if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + pushImage(x, y, w, h, (const rgb888_t*)data, transparent); } else { - param->src_width = w; + pushImage(x, y, w, h, (const bgr888_t*)data, transparent); } - - std::int32_t xt = - dst_x; - std::int32_t yt = min_y - dst_y - 1; - - std::int32_t cos_x = round(cos_f / zoom_x); - param->src_x32_add = cos_x; - std::int32_t sin_x = - round(sin_f / zoom_x); - std::int32_t xstart = cos_x * xt + sin_x * yt + (src_x << FP_SCALE) + (1 << (FP_SCALE - 1)); - std::int32_t scale_w = w << FP_SCALE; - std::int32_t xs1 = (cos_x < 0 ? - scale_w : 1) - cos_x; - std::int32_t xs2 = (cos_x < 0 ? 0 : (1 - scale_w)) - cos_x; - if (cos_x == 0) cos_x = 1; - cos_x = -cos_x; - - std::int32_t sin_y = round(sin_f / zoom_y); - param->src_y32_add = sin_y; - std::int32_t cos_y = round(cos_f / zoom_y); - std::int32_t ystart = sin_y * xt + cos_y * yt + (src_y << FP_SCALE) + (1 << (FP_SCALE - 1)); - std::int32_t scale_h = h << FP_SCALE; - std::int32_t ys1 = (sin_y < 0 ? - scale_h : 1) - sin_y; - std::int32_t ys2 = (sin_y < 0 ? 0 : (1 - scale_h)) - sin_y; - if (sin_y == 0) sin_y = 1; - sin_y = -sin_y; - - std::int32_t cl = _clip_l; - std::int32_t cr = _clip_r + 1; - - startWrite(); - do { - std::int32_t left = cl; - std::int32_t right = cr; - xstart += sin_x; - //if (cos_x != 0) - { - std::int32_t tmp = (xstart + xs1) / cos_x; if (left < tmp) left = tmp; - tmp = (xstart + xs2) / cos_x; if (right > tmp) right = tmp; - } - ystart += cos_y; - //if (sin_y != 0) - { - std::int32_t tmp = (ystart + ys1) / sin_y; if (left < tmp) left = tmp; - tmp = (ystart + ys2) / sin_y; if (right > tmp) right = tmp; - } - if (left < right) { - param->src_x32 = xstart - left * cos_x; - std::int32_t y32 = ystart - left * sin_y; - if (y32 >= 0) { - param->src_y32 = y32; - pushImage_impl(left, min_y, right - left, 1, param, true); - } - } - } while (++min_y != max_y); - endWrite(); } - template - void setScrollRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T& color) { - _scolor = _write_conv.convert(color); - setScrollRect(x, y, w, h); + template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, const std::uint8_t bits, const T* palette) { + pixelcopy_t p(data, _write_conv.depth, (color_depth_t)bits, _palette_count, palette); + p.fp_copy = pixelcopy_t::get_fp_palettecopy(_write_conv.depth); + push_image(x, y, w, h, &p); + } + template void pushImage( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, std::uint32_t transparent, const std::uint8_t bits, const T* palette) { + pixelcopy_t p(data, _write_conv.depth, (color_depth_t)bits, _palette_count, palette, transparent ); + p.fp_copy = pixelcopy_t::get_fp_palettecopy(_write_conv.depth); + push_image(x, y, w, h, &p); } - void setScrollRect(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h) { - _adjust_abs(x, w); - if (x < 0) { w += x; x = 0; } - if (w > _width - x) w = _width - x; - if (w < 0) w = 0; - _sx = x; - _sw = w; - _adjust_abs(y, h); - if (y < 0) { h += y; y = 0; } - if (h > _height - y) h = _height - y; - if (h < 0) h = 0; - _sy = y; - _sh = h; + template void pushImageDMA( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const T* data) + { + pixelcopy_t p(data, _write_conv.depth, get_depth::value, _palette_count, nullptr ); + push_image(x, y, w, h, &p, true); } - void getScrollRect(std::int32_t *x, std::int32_t *y, std::int32_t *w, std::int32_t *h) { - *x = _sx; - *y = _sy; - *w = _sw; - *h = _sh; + template void pushImageDMA( std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data, const std::uint8_t bits, const T* palette) + { + pixelcopy_t p(data, _write_conv.depth, (color_depth_t)bits, _palette_count, palette); + push_image(x, y, w, h, &p, true); } - void scroll(std::int_fast16_t dx, std::int_fast16_t dy = 0) + void pushImageDMA(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const std::uint16_t* data) { - _color.raw = _scolor; - std::int32_t absx = abs(dx); - std::int32_t absy = abs(dy); - if (absx >= _sw || absy >= _sh) { - writeFillRect(_sx, _sy, _sw, _sh); - return; + pixelcopy_t p(data, _write_conv.depth, rgb565_2Byte, _palette_count, nullptr); + if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + p.no_convert = false; + p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); } + push_image(x, y, w, h, &p, true); + } + void pushImageDMA(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, const void* data) + { + pixelcopy_t p(data, _write_conv.depth, rgb888_3Byte, _palette_count, nullptr); + if (_swapBytes && !_palette_count && _write_conv.depth >= 8) { + p.no_convert = false; + p.fp_copy = pixelcopy_t::get_fp_normalcopy(_write_conv.depth); + } + push_image(x, y, w, h, &p, true); + } - std::int32_t w = _sw - absx; - std::int32_t h = _sh - absy; + void push_image(std::int32_t x, std::int32_t y, std::int32_t w, std::int32_t h, pixelcopy_t *param, bool use_dma = false); - std::int32_t src_x = dx < 0 ? _sx - dx : _sx; - std::int32_t dst_x = src_x + dx; - std::int32_t src_y = dy < 0 ? _sy - dy : _sy; - std::int32_t dst_y = src_y + dy; + bool pushImageRotateZoom(std::int32_t dst_x, std::int32_t dst_y, const void* data, std::int32_t src_x, std::int32_t src_y, std::int32_t w, std::int32_t h, float angle, float zoom_x, float zoom_y, std::uint32_t transparent, const std::uint8_t bits, const bgr888_t* palette); - startWrite(); - copyRect_impl(dst_x, dst_y, w, h, src_x, src_y); + void scroll(std::int_fast16_t dx, std::int_fast16_t dy = 0); - if ( dx > 0) writeFillRect(_sx , dst_y, dx, h); - else if (dx < 0) writeFillRect(_sx + _sw + dx, dst_y, -dx, h); - if ( dy > 0) writeFillRect(_sx, _sy , _sw, dy); - else if (dy < 0) writeFillRect(_sx, _sy + _sh + dy, _sw, -dy); - endWrite(); - } + void copyRect(std::int32_t dst_x, std::int32_t dst_y, std::int32_t w, std::int32_t h, std::int32_t src_x, std::int32_t src_y); - void copyRect(std::int32_t dst_x, std::int32_t dst_y, std::int32_t w, std::int32_t h, std::int32_t src_x, std::int32_t src_y) - { - if (src_x < dst_x) { if (src_x < 0) { w += src_x; dst_x -= src_x; src_x = 0; } if (w > _width - dst_x) w = _width - dst_x; } - else { if (dst_x < 0) { w += dst_x; src_x -= dst_x; dst_x = 0; } if (w > _width - src_x) w = _width - src_x; } - if (w < 1) return; - - if (src_y < dst_y) { if (src_y < 0) { h += src_y; dst_y -= src_y; src_y = 0; } if (h > _height - dst_y) h = _height - dst_y; } - else { if (dst_y < 0) { h += dst_y; src_y -= dst_y; dst_y = 0; } if (h > _height - src_y) h = _height - src_y; } - if (h < 1) return; - - startWrite(); - copyRect_impl(dst_x, dst_y, w, h, src_x, src_y); - endWrite(); - } + void paint(std::int32_t x, std::int32_t y); #ifdef _LGFX_QRCODE_H_ @@ -1251,105 +443,6 @@ namespace lgfx } #endif - template inline void paint( std::int32_t x, std::int32_t y, const T& color) { setColor(color); paint(x, y); } - void paint(std::int32_t x, std::int32_t y) { - if (x < _clip_l || x > _clip_r || y < _clip_t || y > _clip_b) return; - bgr888_t target; - readRectRGB(x, y, 1, 1, &target); - if (_color.raw == _write_conv.convert(lgfx::color888(target.r, target.g, target.b))) return; - - pixelcopy_t p; - p.transp = _read_conv.convert(lgfx::color888(target.r, target.g, target.b)); - switch (_read_conv.depth) { - case 24: p.fp_copy = pixelcopy_t::normalcompare; break; - case 18: p.fp_copy = pixelcopy_t::normalcompare; break; - case 16: p.fp_copy = pixelcopy_t::normalcompare; break; - case 8: p.fp_copy = pixelcopy_t::normalcompare; break; - default: p.fp_copy = pixelcopy_t::bitcompare; - p.src_bits = _read_conv.depth; - p.src_mask = (1 << p.src_bits) - 1; - p.transp &= p.src_mask; - break; - } - - std::int32_t cl = _clip_l; - int w = _clip_r - cl + 1; - std::uint8_t bufIdx = 0; - bool buf0[w], buf1[w], buf2[w]; - bool* linebufs[3] = { buf0, buf1, buf2 }; - std::int32_t bufY[3] = {-2, -2, -2}; - bufY[0] = y; - read_rect(cl, y, w, 1, linebufs[0], &p); - std::list points; - points.push_back({x, x, y, y}); - - startWrite(); - while (!points.empty()) { - std::int32_t y0 = bufY[bufIdx]; - auto it = points.begin(); - std::int32_t counter = 0; - while (it->y != y0 && ++it != points.end()) ++counter; - if (it == points.end()) { - if (counter < 256) { - ++bufIdx; - std::int32_t y1 = bufY[(bufIdx )%3]; - std::int32_t y2 = bufY[(bufIdx+1)%3]; - it = points.begin(); - while ((it->y != y1) && (it->y != y2) && (++it != points.end())); - } - } - - bufIdx = 0; - if (it == points.end()) { - it = points.begin(); - bufY[0] = it->y; - read_rect(cl, it->y, w, 1, linebufs[0], &p); - } else { - for (; bufIdx < 2; ++bufIdx) if (it->y == bufY[bufIdx]) break; - } - bool* linebuf = &linebufs[bufIdx][- cl]; - - int lx = it->lx; - int rx = it->rx; - int ly = it->y; - int oy = it->oy; - points.erase(it); - if (!linebuf[lx]) continue; - - int lxsav = lx - 1; - int rxsav = rx + 1; - - int cr = _clip_r; - while (lx > cl && linebuf[lx - 1]) --lx; - while (rx < cr && linebuf[rx + 1]) ++rx; - - writeFastHLine(lx, ly, rx - lx + 1); - memset(&linebuf[lx], 0, rx - lx + 1); - - int newy = ly - 1; - do { - if (newy == oy && lx >= lxsav && rxsav >= rx) continue; - if (newy < _clip_t) continue; - if (newy > _clip_b) continue; - int bidx = 0; - for (; bidx < 3; ++bidx) if (newy == bufY[bidx]) break; - if (bidx == 3) { - for (bidx = 0; bidx < 2 && (abs(bufY[bidx] - ly) <= 1); ++bidx); - bufY[bidx] = newy; - read_rect(cl, newy, w, 1, linebufs[bidx], &p); - } - bool* linebuf = &linebufs[bidx][- cl]; - if (newy == oy) { - paint_add_points(points, lx ,lxsav, newy, ly, linebuf); - paint_add_points(points, rxsav ,rx, newy, ly, linebuf); - } else { - paint_add_points(points, lx ,rx, newy, ly, linebuf); - } - } while ((newy += 2) < ly + 2); - } - endWrite(); - } - //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -1359,7 +452,7 @@ namespace lgfx std::int32_t _sx, _sy, _sw, _sh; // for scroll zone std::int32_t _clip_l = 0, _clip_r = -1, _clip_t = 0, _clip_b = -1; // clip rect - std::uint32_t _scolor; // gap fill colour for scroll zone + std::uint32_t _base_rgb888 = 0; // gap fill colour for scroll zone raw_color_t _color = 0xFFFFFFU; color_conv_t _write_conv; @@ -1399,77 +492,11 @@ namespace lgfx readRect_impl(x, y, w, h, dst, param); endWrite(); } - void fill_arc_helper(std::int32_t cx, std::int32_t cy, std::int32_t oradius, std::int32_t iradius, float start, float end) - { - float s_cos = (cos(start * deg_to_rad)); - float e_cos = (cos(end * deg_to_rad)); - float sslope = s_cos / (sin(start * deg_to_rad)); - float eslope = -1000000; - if (end != 360.0) eslope = e_cos / (sin(end * deg_to_rad)); - float swidth = 0.5 / s_cos; - float ewidth = -0.5 / e_cos; - --iradius; - int ir2 = iradius * iradius + iradius; - int or2 = oradius * oradius + oradius; - - bool start180 = !(start < 180); - bool end180 = end < 180; - bool reversed = start + 180 < end || (end < start && start < end + 180); - - int xs = -oradius; - int y = -oradius; - int ye = oradius; - int xe = oradius + 1; - if (!reversed) { - if ( (end >= 270 || end < 90) && (start >= 270 || start < 90)) xs = 0; - else if (end < 270 && end >= 90 && start < 270 && start >= 90) xe = 1; - if ( end >= 180 && start >= 180) ye = 0; - else if (end < 180 && start < 180) y = 0; - } - do { - int y2 = y * y; - int x = xs; - if (x < 0) { - while (x * x + y2 >= or2) ++x; - if (xe != 1) xe = 1 - x; - } - float ysslope = (y + swidth) * sslope; - float yeslope = (y + ewidth) * eslope; - int len = 0; - do { - bool flg1 = start180 != (x <= ysslope); - bool flg2 = end180 != (x <= yeslope); - int distance = x * x + y2; - if (distance >= ir2 - && ((flg1 && flg2) || (reversed && (flg1 || flg2))) - && x != xe - && distance < or2 - ) { - ++len; - } else { - if (len) { - writeFastHLine(cx + x - len, cy + y, len); - len = 0; - } - if (distance >= or2) break; - if (x < 0 && distance < ir2) { x = -x; } - } - } while (++x <= xe); - } while (++y <= ye); - } - struct paint_point_t { std::int32_t lx,rx,y,oy; }; - static void paint_add_points(std::list& points, int lx, int rx, int y, int oy, bool* linebuf) { - paint_point_t pt { 0, 0, y, oy }; - while (lx <= rx) { - while (lx < rx && !linebuf[lx]) ++lx; - if (!linebuf[lx]) break; - pt.lx = lx; - while (++lx <= rx && linebuf[lx]); - pt.rx = lx - 1; - points.push_back(pt); - } - } + void fill_arc_helper(std::int32_t cx, std::int32_t cy, std::int32_t oradius, std::int32_t iradius, float start, float end); + void draw_bitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, std::uint32_t fg_rawcolor, std::uint32_t bg_rawcolor = ~0u); + void draw_xbitmap(std::int32_t x, std::int32_t y, const std::uint8_t *bitmap, std::int32_t w, std::int32_t h, std::uint32_t fg_rawcolor, std::uint32_t bg_rawcolor = ~0u); + void push_image_rotate_zoom(std::int32_t dst_x, std::int32_t dst_y, std::int32_t src_x, std::int32_t src_y, std::int32_t w, std::int32_t h, float angle, float zoom_x, float zoom_y, pixelcopy_t *param); virtual void beginTransaction_impl(void) = 0; virtual void endTransaction_impl(void) = 0; @@ -1483,6 +510,7 @@ namespace lgfx virtual void pushColors_impl(std::int32_t length, pixelcopy_t* param) = 0; virtual void pushBlock_impl(std::int32_t len) = 0; virtual void setWindow_impl(std::int32_t xs, std::int32_t ys, std::int32_t xe, std::int32_t ye) = 0; + virtual bool isReadable_impl(void) const { return true; } static void tmpBeginTransaction(void* lgfx) { auto me = (LGFXBase*)lgfx; diff --git a/src/lgfx/lgfx_common.hpp b/src/lgfx/lgfx_common.hpp index 1f55f2d..7b79bb0 100644 --- a/src/lgfx/lgfx_common.hpp +++ b/src/lgfx/lgfx_common.hpp @@ -21,8 +21,7 @@ Original Source: #define LGFX_COMMON_HPP_ #include -#include -#include +#include #include enum jpeg_div_t { @@ -35,7 +34,68 @@ enum jpeg_div_t { namespace lgfx { - static constexpr float deg_to_rad = 0.017453292519943295769236907684886; + namespace colors // Colour enumeration + { + static constexpr int TFT_BLACK = 0x0000; /* 0, 0, 0 */ + static constexpr int TFT_NAVY = 0x000F; /* 0, 0, 128 */ + static constexpr int TFT_DARKGREEN = 0x03E0; /* 0, 128, 0 */ + static constexpr int TFT_DARKCYAN = 0x03EF; /* 0, 128, 128 */ + static constexpr int TFT_MAROON = 0x7800; /* 128, 0, 0 */ + static constexpr int TFT_PURPLE = 0x780F; /* 128, 0, 128 */ + static constexpr int TFT_OLIVE = 0x7BE0; /* 128, 128, 0 */ + static constexpr int TFT_LIGHTGREY = 0xD69A; /* 211, 211, 211 */ + static constexpr int TFT_DARKGREY = 0x7BEF; /* 128, 128, 128 */ + static constexpr int TFT_BLUE = 0x001F; /* 0, 0, 255 */ + static constexpr int TFT_GREEN = 0x07E0; /* 0, 255, 0 */ + static constexpr int TFT_CYAN = 0x07FF; /* 0, 255, 255 */ + static constexpr int TFT_RED = 0xF800; /* 255, 0, 0 */ + static constexpr int TFT_MAGENTA = 0xF81F; /* 255, 0, 255 */ + static constexpr int TFT_YELLOW = 0xFFE0; /* 255, 255, 0 */ + static constexpr int TFT_WHITE = 0xFFFF; /* 255, 255, 255 */ + static constexpr int TFT_ORANGE = 0xFDA0; /* 255, 180, 0 */ + static constexpr int TFT_GREENYELLOW = 0xB7E0; /* 180, 255, 0 */ + static constexpr int TFT_PINK = 0xFE19; /* 255, 192, 203 */ //Lighter pink, was 0xFC9F + static constexpr int TFT_BROWN = 0x9A60; /* 150, 75, 0 */ + static constexpr int TFT_GOLD = 0xFEA0; /* 255, 215, 0 */ + static constexpr int TFT_SILVER = 0xC618; /* 192, 192, 192 */ + static constexpr int TFT_SKYBLUE = 0x867D; /* 135, 206, 235 */ + static constexpr int TFT_VIOLET = 0x915C; /* 180, 46, 226 */ + static constexpr int TFT_TRANSPARENT = 0x0120; + } + + namespace textdatum + { + enum textdatum_t : std::uint8_t + // 0:left 1:centre 2:right + // 0:top 4:middle 8:bottom 16:baseline + { top_left = 0 // Top left (default) + , top_center = 1 // Top center + , top_centre = 1 // Top center + , top_right = 2 // Top right + , middle_left = 4 // Middle left + , middle_center = 5 // Middle center + , middle_centre = 5 // Middle center + , middle_right = 6 // Middle right + , bottom_left = 8 // Bottom left + , bottom_center = 9 // Bottom center + , bottom_centre = 9 // Bottom center + , bottom_right = 10 // Bottom right + , baseline_left = 16 // Baseline left (Line the 'A' character would sit on) + , baseline_center = 17 // Baseline center + , baseline_centre = 17 // Baseline center + , baseline_right = 18 // Baseline right + }; + }; + using namespace textdatum; + + namespace attribute + { + enum attribute_t + { cp437_switch = 1 + , utf8_switch = 2 + }; + } + using namespace attribute; enum color_depth_t : std::uint8_t { palette_1bit = 1 // 2 color @@ -48,9 +108,6 @@ namespace lgfx , argb8888_4Byte = 32 // AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB }; - - - __attribute__ ((always_inline)) inline static std::uint8_t color332(std::uint8_t r, std::uint8_t g, std::uint8_t b) { return (r >> 5) << 5 | (g >> 5) << 2 | b >> 6; } __attribute__ ((always_inline)) inline static std::uint16_t color565(std::uint8_t r, std::uint8_t g, std::uint8_t b) { return (r >> 3) <<11 | (g >> 2) << 5 | b >> 3; } __attribute__ ((always_inline)) inline static std::uint32_t color888(std::uint8_t r, std::uint8_t g, std::uint8_t b) { return r << 16 | g << 8 | b; } @@ -95,7 +152,7 @@ namespace lgfx struct rgb888_t; // 24bpp struct argb8888_t; // 32bpp struct swap565_t; // 16bpp - struct bgr666_t; // 18bpp + struct bgr666_t; // 18bpp (24bpp xxRRRRRRxxGGGGGGxxBBBBBB (for OLED SSD1351) struct bgr888_t; // 24bpp @@ -403,6 +460,56 @@ namespace lgfx inline operator bool() const { return raw & 0x00FFFFFF; } }; + struct get_depth_impl { + template static constexpr std::integral_constant check(decltype(T::depth)*); + template static constexpr std::integral_constant check(...); + }; + template class get_depth : public decltype(get_depth_impl::check(nullptr)) {}; + + template + static auto get_fp_convert_src(color_depth_t dst_depth, bool has_palette) -> std::uint32_t(*)(std::uint32_t) + { + if (std::is_same::value || std::is_same::value) { + switch (dst_depth) { + case rgb888_3Byte: return convert_rgb332_to_bgr888; + case rgb666_3Byte: return convert_rgb332_to_bgr666; + case rgb565_2Byte: return convert_rgb332_to_swap565; + case rgb332_1Byte: return has_palette + ? convert_uint32_to_palette8 + : no_convert; + default: break; + } + } else if (std::is_same::value || std::is_same::value || std::is_same::value) { + switch (dst_depth) { + case rgb888_3Byte: return convert_rgb565_to_bgr888; + case rgb666_3Byte: return convert_rgb565_to_bgr666; + case rgb565_2Byte: return convert_rgb565_to_swap565; + case rgb332_1Byte: return has_palette + ? convert_uint32_to_palette8 + : convert_rgb565_to_rgb332; + default: break; + } + } else if (std::is_same::value || std::is_same::value) { + switch (dst_depth) { + case rgb888_3Byte: return convert_rgb888_to_bgr888; + case rgb666_3Byte: return convert_rgb888_to_bgr666; + case rgb565_2Byte: return convert_rgb888_to_swap565; + case rgb332_1Byte: return has_palette + ? convert_uint32_to_palette8 + : convert_rgb888_to_rgb332; + default: break; + } + } + + switch (dst_depth) { + case palette_4bit: return convert_uint32_to_palette4; + case palette_2bit: return convert_uint32_to_palette2; + case palette_1bit: return convert_uint32_to_palette1; + default: return no_convert; + } + } + + struct color_conv_t { // std::uint32_t (*convert_bgr888)(std::uint32_t) = convert_bgr888_to_swap565; @@ -418,7 +525,7 @@ namespace lgfx color_conv_t() = default; color_conv_t(const color_conv_t&) = default; - void setColorDepth(color_depth_t bpp, bool hasPalette = false) { + void setColorDepth(color_depth_t bpp, bool has_palette = false) { x_mask = 0; if ( bpp > 18) { bpp = rgb888_3Byte; bytes = 3; bits = 24; } else if (bpp > 16) { bpp = rgb666_3Byte; bytes = 3; bits = 24; } @@ -430,6 +537,10 @@ namespace lgfx colormask = (1 << bits) - 1; depth = bpp; + convert_rgb888 = get_fp_convert_src(bpp, has_palette); + convert_rgb565 = get_fp_convert_src(bpp, has_palette); + convert_rgb332 = get_fp_convert_src(bpp, has_palette); +/* switch (bpp) { case rgb888_3Byte: // convert_bgr888 = no_convert; @@ -451,7 +562,7 @@ namespace lgfx convert_rgb332 = convert_rgb332_to_swap565; break; case rgb332_1Byte: - if (!hasPalette) { + if (!has_palette) { // convert_bgr888 = convert_bgr888_to_rgb332; convert_rgb888 = convert_rgb888_to_rgb332; convert_rgb565 = convert_rgb565_to_rgb332; @@ -482,6 +593,7 @@ namespace lgfx convert_rgb332 = convert_uint32_to_palette1; break; } +//*/ } #define TYPECHECK(dType) template < typename T, typename std::enable_if < (sizeof(T) == sizeof(dType)) && (std::is_signed::value == std::is_signed::value), std::nullptr_t >::type=nullptr > @@ -956,6 +1068,7 @@ namespace lgfx __attribute__ ((always_inline)) inline void preRead(void) { if (fp_pre_read) fp_pre_read(parent); } __attribute__ ((always_inline)) inline void postRead(void) { if (fp_post_read) fp_post_read(parent); } + __attribute__ ((always_inline)) inline bool hasParent(void) const { return parent; } void* parent = nullptr; void (*fp_pre_read)(void*) = nullptr; void (*fp_post_read)(void*) = nullptr; @@ -982,6 +1095,12 @@ namespace lgfx //---------------------------------------------------------------------------- } +using namespace lgfx::colors; +using namespace lgfx::textdatum; +using namespace lgfx::attribute; + + +typedef lgfx::bgr888_t RGBColor; #if defined (ESP32) || (CONFIG_IDF_TARGET_ESP32) || (ESP_PLATFORM) diff --git a/src/lgfx/lgfx_font_support.hpp b/src/lgfx/lgfx_font_support.hpp index c9c88ac..5f2b914 100644 --- a/src/lgfx/lgfx_font_support.hpp +++ b/src/lgfx/lgfx_font_support.hpp @@ -22,6 +22,7 @@ Original Source: #include "../Fonts/lgfx_fonts.hpp" #include +#include #include #include @@ -31,26 +32,16 @@ Original Source: namespace lgfx { - enum attribute_t - { cp437_switch = 1 - , utf8_switch = 2 + struct TextStyle { + std::uint32_t fore_rgb888 = 0xFFFFFFU; + std::uint32_t back_rgb888 = 0; + float size_x = 1; + float size_y = 1; + textdatum_t datum = textdatum_t::top_left; + bool utf8 = true; + bool cp437 = false; }; -/* - // deprecated array. - static PROGMEM const IFont* fontdata [] = { - &fonts::Font0, // GLCD font (Font 0) - &fonts::Font0, // GLCD font (or GFX font) - &fonts::Font2, - &fonts::Font0, // Font 3 current unused - &fonts::Font4, - &fonts::Font0, // Font 5 current unused - &fonts::Font6, - &fonts::Font7, - &fonts::Font8, - }; -//*/ - //---------------------------------------------------------------------------- struct VLWfont : public RunTimeFont { @@ -241,19 +232,20 @@ namespace lgfx std::int16_t getCursorX(void) const { return _cursor_x; } std::int16_t getCursorY(void) const { return _cursor_y; } - std::int16_t getTextSizeX(void) const { return _text_style.size_x; } - std::int16_t getTextSizeY(void) const { return _text_style.size_y; } + float getTextSizeX(void) const { return _text_style.size_x; } + float getTextSizeY(void) const { return _text_style.size_y; } textdatum_t getTextDatum(void) const { return _text_style.datum; } std::int16_t fontHeight(void) const { return _font_metrics.height * _text_style.size_y; } std::int16_t fontHeight(std::uint8_t font) const { return ((const BaseFont*)fontdata[font])->height * _text_style.size_y; } void setCursor( std::int16_t x, std::int16_t y) { _filled_x = 0; _cursor_x = x; _cursor_y = y; } void setCursor( std::int16_t x, std::int16_t y, std::uint8_t font) { _filled_x = 0; _cursor_x = x; _cursor_y = y; _font = fontdata[font]; } - void setTextSize(std::uint8_t s) { setTextSize(s,s); } - void setTextSize(std::uint8_t sx, std::uint8_t sy) { _text_style.size_x = (sx > 0) ? sx : 1; _text_style.size_y = (sy > 0) ? sy : 1; } - void setTextDatum(std::uint8_t datum) { _text_style.datum = (textdatum_t)datum; } + void setTextSize(float size) { setTextSize(size, size); } + void setTextSize(float sx, float sy) { _text_style.size_x = (sx > 0) ? sx : 1; _text_style.size_y = (sy > 0) ? sy : 1; } void setTextDatum(textdatum_t datum) { _text_style.datum = datum; } - void setTextPadding(std::uint16_t padding_x) { _padding_x = padding_x; } + [[deprecated("use textdatum_t")]] + void setTextDatum(std::uint8_t datum) { _text_style.datum = (textdatum_t)datum; } + void setTextPadding(std::uint32_t padding_x) { _padding_x = padding_x; } void setTextWrap( bool wrapX, bool wrapY = false) { _textwrap_x = wrapX; _textwrap_y = wrapY; } void setTextScroll(bool scroll) { _textscroll = scroll; if (_cursor_x < this->_sx) { _cursor_x = this->_sx; } if (_cursor_y < this->_sy) { _cursor_y = this->_sy; } } @@ -279,6 +271,8 @@ namespace lgfx std::int32_t textWidth(const char *string) { if (!string) return 0; + auto sx = _text_style.size_x; + std::int32_t left = 0; std::int32_t right = 0; do { @@ -291,12 +285,12 @@ namespace lgfx } if (!_font->updateFontMetric(&_font_metrics, uniCode)) continue; - if (left == 0 && right == 0 && _font_metrics.x_offset < 0) left = right = -_font_metrics.x_offset; - right = left + std::max(_font_metrics.x_advance, _font_metrics.width + _font_metrics.x_offset); - left += _font_metrics.x_advance; + if (left == 0 && right == 0 && _font_metrics.x_offset < 0) left = right = - (int)(_font_metrics.x_offset * sx); + right = left + std::max(_font_metrics.x_advance*sx, int(_font_metrics.width*sx) + int(_font_metrics.x_offset * sx)); + //right = left + (int)(std::max(_font_metrics.x_advance, _font_metrics.width + _font_metrics.x_offset) * sx); + left += (int)(_font_metrics.x_advance * sx); } while (*(++string)); - - return right * _text_style.size_x; + return right; } #if defined (ARDUINO) @@ -362,9 +356,9 @@ namespace lgfx inline size_t drawChar(std::uint16_t uniCode, std::int32_t x, std::int32_t y) { _filled_x = 0; return (fpDrawChar)(this, x, y, uniCode, &_text_style, _font); } template - inline size_t drawChar(std::int32_t x, std::int32_t y, std::uint16_t uniCode, T color, T bg, std::int_fast8_t size) { return drawChar(x, y, uniCode, color, bg, size, size); } + inline size_t drawChar(std::int32_t x, std::int32_t y, std::uint16_t uniCode, T color, T bg, float size) { return drawChar(x, y, uniCode, color, bg, size, size); } template - inline size_t drawChar(std::int32_t x, std::int32_t y, std::uint16_t uniCode, T color, T bg, std::int_fast8_t size_x, std::int_fast8_t size_y) { + inline size_t drawChar(std::int32_t x, std::int32_t y, std::uint16_t uniCode, T color, T bg, float size_x, float size_y) { TextStyle style = _text_style; style.back_rgb888 = convert_to_rgb888(color); style.fore_rgb888 = convert_to_rgb888(bg); @@ -433,7 +427,6 @@ namespace lgfx void cp437(bool enable = true) { _text_style.cp437 = enable; } // AdafruitGFX compatible. - void setAttribute(std::uint8_t attr_id, std::uint8_t param) { setAttribute((attribute_t)attr_id, param); } void setAttribute(attribute_t attr_id, std::uint8_t param) { switch (attr_id) { case cp437_switch: @@ -643,10 +636,10 @@ namespace lgfx std::int_fast16_t xo = _font_metrics.x_offset * _text_style.size_x; std::int_fast16_t w = std::max(xo + _font_metrics.width * _text_style.size_x, _font_metrics.x_advance * _text_style.size_x); if (_textscroll || _textwrap_x) { - std::int32_t llimit = _textscroll ? this->_sx : 0; + std::int32_t llimit = _textscroll ? this->_sx : this->_clip_l; if (_cursor_x < llimit - xo) _cursor_x = llimit - xo; else { - std::int32_t rlimit = _textscroll ? this->_sx + this->_sw : this->_width; + std::int32_t rlimit = _textscroll ? this->_sx + this->_sw : (this->_clip_r + 1); if (_cursor_x + w > rlimit) { _filled_x = llimit; _cursor_x = llimit - xo; @@ -655,7 +648,7 @@ namespace lgfx } } - std::int_fast16_t h = _font_metrics.height * _text_style.size_y; + std::int_fast16_t h = _font_metrics.height * _text_style.size_y; std::int_fast16_t ydiff = 0; if (_text_style.datum & middle_left) { // vertical: middle @@ -663,7 +656,7 @@ namespace lgfx } else if (_text_style.datum & bottom_left) { // vertical: bottom ydiff -= h; } else if (_text_style.datum & baseline_left) { // vertical: baseline - ydiff -= _font_metrics.baseline * _text_style.size_y; + ydiff -= (int)(_font_metrics.baseline * _text_style.size_y); } std::int_fast16_t y = _cursor_y + ydiff; @@ -677,15 +670,15 @@ namespace lgfx } } } else if (_textwrap_y) { - if (y + h > this->_height) { + if (y + h > (this->_clip_b + 1)) { _filled_x = 0; _cursor_x = - xo; y = 0; } else - if (y < 0) y = 0; + if (y < this->_clip_t) y = this->_clip_t; } _cursor_y = y - ydiff; - y -= _font_metrics.y_offset * _text_style.size_y; + y -= int(_font_metrics.y_offset * _text_style.size_y); _cursor_x += (fpDrawChar)(this, _cursor_x, y, uniCode, &_text_style, _font); } @@ -751,6 +744,7 @@ namespace lgfx std::int32_t _cursor_x = 0; std::int32_t _cursor_y = 0; std::int32_t _filled_x = 0; + std::int32_t _padding_x = 0; TextStyle _text_style; FontMetrics _font_metrics = { 6, 6, 0, 8, 8, 0, 7 }; // Font0 Metric @@ -760,8 +754,6 @@ namespace lgfx FileWrapper _font_file; PointerWrapper _font_data; - std::int16_t _padding_x = 0; - bool _textwrap_x = true; bool _textwrap_y = false; bool _textscroll = false; @@ -887,7 +879,7 @@ namespace lgfx } else if (datum & bottom_left) { // vertical: bottom y -= cheight; } else if (datum & baseline_left) { // vertical: baseline - y -= _font_metrics.baseline * _text_style.size_y; + y -= (int)(_font_metrics.baseline * _text_style.size_y); } this->startWrite(); @@ -914,7 +906,7 @@ namespace lgfx x -= cwidth; } - y -= _font_metrics.y_offset * _text_style.size_y; + y -= int(_font_metrics.y_offset * _text_style.size_y); _filled_x = 0; do { @@ -953,38 +945,42 @@ namespace lgfx std::int32_t clip_top = me->_clip_t; std::int32_t clip_bottom = me->_clip_b; - if ((x <= clip_right) && (clip_left < (x + fontWidth * style->size_x )) - && (y <= clip_bottom) && (clip_top < (y + fontHeight * style->size_y ))) { - if (!fillbg || style->size_y > 1 || x < clip_left || y < clip_top || y + fontHeight > clip_bottom || x + fontWidth * style->size_x > clip_right) { - std::int32_t xpos = x; + float sy = style->size_y; + float sx = style->size_x; + if ((x <= clip_right) && (clip_left < (x + fontWidth * sx )) + && (y <= clip_bottom) && (clip_top < (y + fontHeight * sy ))) { +// if (!fillbg || style->size_y != 1.0 || x < clip_left || y < clip_top || y + fontHeight > clip_bottom || x + fontWidth * sx > clip_right) { + std::int32_t x1 = sx; + std::int32_t x0 = 0; me->startWrite(); std::int_fast8_t i = 0; do { - std::int_fast16_t ypos = y; std::uint8_t line = font_addr[i]; std::uint8_t flg = (line & 0x01); std::int_fast8_t j = 1; - std::int_fast8_t jp = 0; + std::int_fast16_t y0 = 0; + std::int_fast16_t y1 = 0; do { while (flg == ((line >> j) & 0x01) && ++j < fontHeight); - jp = j - jp; + y1 = j * sy; if (flg || fillbg) { me->setRawColor(colortbl[flg]); - me->writeFillRect(xpos, ypos, style->size_x, jp * style->size_y); + me->writeFillRect(x + x0, y + y0, x1 - x0, y1 - y0); } - ypos += jp * style->size_y; + y0 = y1; flg = !flg; - jp = j; } while (j < fontHeight); - xpos += style->size_x; - } while (++i < fontWidth - 1); + x0 = x1; + x1 = (++i + 1) * sx; + } while (i < fontWidth - 1); if (fillbg) { me->setRawColor(colortbl[0]); - me->writeFillRect(xpos, y, style->size_x, fontHeight * style->size_y); + me->writeFillRect(x + x0, y, x1 - x0, fontHeight * style->size_y); } me->endWrite(); +/* } else { std::uint8_t col[fontWidth]; std::int_fast8_t i = 0; @@ -1011,8 +1007,9 @@ namespace lgfx me->writeRawColor(colortbl[0], len); me->endWrite(); } +//*/ } - return fontWidth * style->size_x; + return fontWidth * sx; } static size_t drawCharBMP(LGFX_Font_Support* me, std::int32_t x, std::int32_t y, std::uint16_t uniCode, const TextStyle* style, const IFont* ifont) @@ -1054,47 +1051,52 @@ namespace lgfx std::int32_t clip_top = me->_clip_t; std::int32_t clip_bottom = me->_clip_b; - if ((x <= clip_right) && (clip_left < (x + fontWidth * style->size_x )) - && (y <= clip_bottom) && (clip_top < (y + fontHeight * style->size_y ))) { - if (!fillbg || style->size_y > 1 || x < clip_left || y < clip_top || y + fontHeight > clip_bottom || x + fontWidth * style->size_x > clip_right) { + float sx = style->size_x; + float sy = style->size_y; + + if ((x <= clip_right) && (clip_left < (x + fontWidth * sx )) + && (y <= clip_bottom) && (clip_top < (y + fontHeight * sy ))) { +// if (!fillbg || sy != 1 || x < clip_left || y < clip_top || y + fontHeight > clip_bottom || x + fontWidth * sx > clip_right) { me->startWrite(); if (fillbg) { me->setRawColor(colortbl[0]); - if (margin) - me->writeFillRect(x + (fontWidth - margin) * style->size_x, y, style->size_x, fontHeight * style->size_y); + if (margin) { + std::int32_t x0 = (fontWidth - margin) * sx; + std::int32_t x1 = (fontWidth ) * sx; + if (x0 < x1) { + me->writeFillRect(x + x0, y, x1 - x0, fontHeight * sy); + } + } } std::int_fast8_t i = 0; + std::int32_t y1 = 0; + std::int32_t y0 = - 1; do { + bool fill = y0 != y1; + y0 = y1; + y1 = ++i * sy; std::uint8_t line = font_addr[0]; bool flg = line & 0x80; - std::int_fast8_t len = 1; std::int_fast8_t j = 1; std::int_fast8_t je = fontWidth - margin; + std::int32_t x0 = 0; do { - if (j & 7) { - line <<= 1; - } else { - line = font_addr[j >> 3]; - } - if (flg != (bool)(line & 0x80)) { - if (flg || fillbg) { - me->setRawColor(colortbl[flg]); - me->writeFillRect( x + (j - len) * style->size_x, y, len * style->size_x, style->size_y); - } - len = 1; - flg = !flg; - } else { - ++len; + do { + if (0 == (j & 7)) line = font_addr[j >> 3]; + } while (flg == (bool)(line & (0x80) >> (j&7)) && ++j < je); + std::int32_t x1 = j * sx; + if (flg || (fillbg && fill)) { + me->setRawColor(colortbl[flg]); + if (flg && x1 == std::int32_t((j-1)*sx)) ++x1; + me->writeFillRect(x + x0, y + y0, x1 - x0, std::max(1, y1 - y0)); } - } while (++j < je); - if (flg || fillbg) { - me->setRawColor(colortbl[flg]); - me->writeFillRect( x + (j - len) * style->size_x, y, len * style->size_x, style->size_y); - } - y += style->size_y; + x0 = x1; + flg = !flg; + } while (j < je); font_addr += w; - } while (++i < fontHeight); + } while (i < fontHeight); me->endWrite(); +/* } else { std::int_fast8_t len = 0; std::uint8_t line = 0; @@ -1123,9 +1125,10 @@ namespace lgfx me->writeRawColor(colortbl[flg], len); me->endWrite(); } +//*/ } - return fontWidth * style->size_x; + return fontWidth * sx; } static size_t drawCharRLE(LGFX_Font_Support* me, std::int32_t x, std::int32_t y, std::uint16_t code, const TextStyle* style, const IFont* ifont) @@ -1146,12 +1149,18 @@ namespace lgfx std::int32_t clip_top = me->_clip_t; std::int32_t clip_bottom = me->_clip_b; - if ((x <= clip_right) && (clip_left < (x + fontWidth * style->size_x )) - && (y <= clip_bottom) && (clip_top < (y + fontHeight * style->size_y ))) { - if (!fillbg || style->size_y > 1 || x < clip_left || y < clip_top || y + fontHeight > clip_bottom || x + fontWidth * style->size_x > clip_right) { + float sx = style->size_x; + float sy = style->size_y; + + if ((x <= clip_right) && (clip_left < (x + fontWidth * sx )) + && (y <= clip_bottom) && (clip_top < (y + fontHeight * sy ))) { +// if (!fillbg || sy != 1.0 || x < clip_left || y < clip_top || y + fontHeight > clip_bottom || x + fontWidth * sx > clip_right) { bool flg = false; std::uint8_t line = 0, i = 0, j = 0; std::int32_t len; + std::int32_t y0 = 0; + std::int32_t y1 = sy; + std::int32_t x0 = 0; me->startWrite(); do { line = *font_addr++; @@ -1160,18 +1169,23 @@ namespace lgfx do { len = (j + line > fontWidth) ? fontWidth - j : line; line -= len; + j += len; + std::int32_t x1 = j * sx; if (fillbg || flg) { me->setRawColor(colortbl[flg]); - me->writeFillRect( x + j * style->size_x, y + (i * style->size_y), len * style->size_x, style->size_y); + me->writeFillRect( x + x0, y + y0, x1 - x0, y1 - y0); } - j += len; + x0 = x1; if (j == fontWidth) { j = 0; - i++; + x0 = 0; + y0 = y1; + y1 = (++i + 1) * sy; } } while (line); } while (i < fontHeight); me->endWrite(); +/* } else { std::uint32_t line = 0; me->startWrite(); @@ -1185,9 +1199,10 @@ namespace lgfx } while (len -= line); me->endWrite(); } +//*/ } - return fontWidth * style->size_x; + return fontWidth * sx; } static size_t drawCharGFXFF(LGFX_Font_Support* me, std::int32_t x, std::int32_t y, std::uint16_t uniCode, const TextStyle* style, const IFont* ifont) @@ -1199,9 +1214,11 @@ namespace lgfx std::int32_t w = glyph->width, h = glyph->height; - std::int32_t xAdvance = (std::int32_t)style->size_x * glyph->xAdvance; - std::int32_t xoffset = (std::int32_t)style->size_x * glyph->xOffset; - std::int32_t yoffset = (std::int32_t)style->size_y * glyph->yOffset; + float sx = style->size_x; + float sy = style->size_y; + + std::int32_t xAdvance = sx * glyph->xAdvance; + std::int32_t xoffset = sx * glyph->xOffset; me->startWrite(); std::uint32_t colortbl[2] = {me->getColorConverter()->convert(style->back_rgb888), me->getColorConverter()->convert(style->fore_rgb888)}; @@ -1210,65 +1227,75 @@ namespace lgfx std::int32_t right = 0; if (fillbg) { left = std::max(me->_filled_x, x + (xoffset < 0 ? xoffset : 0)); - right = x + std::max(w * style->size_x + xoffset, xAdvance); + right = x + std::max(w * sx + xoffset, xAdvance); + me->setRawColor(colortbl[0]); } x += xoffset; - y += yoffset; + y += int(me->_font_metrics.y_offset * sy); + std::int32_t yoffset = (- me->_font_metrics.y_offset) + glyph->yOffset; std::int32_t clip_left = me->_clip_l; std::int32_t clip_right = me->_clip_r; std::int32_t clip_top = me->_clip_t; std::int32_t clip_bottom = me->_clip_b; - if ((x <= clip_right) && (clip_left < (x + w * style->size_x )) - && (y <= clip_bottom) && (clip_top < (y + h * style->size_y ))) { + if ((x <= clip_right) && (clip_left < (x + w * sx )) + && (y <= clip_bottom) && (clip_top < (y + h * sy ))) { - if (right > left) { - me->setRawColor(colortbl[0]); - int tmp = yoffset - (me->_font_metrics.y_offset * style->size_y); - if (tmp > 0) - me->writeFillRect(left, y - yoffset + me->_font_metrics.y_offset * style->size_y, right - left, tmp); - - tmp = (me->_font_metrics.y_offset + me->_font_metrics.height - h) * style->size_y - yoffset; - if (tmp > 0) - me->writeFillRect(left, y + h * style->size_y, right - left, tmp); + if (left < right) { + if (yoffset > 0) { + me->writeFillRect(left, y, right - left, yoffset * sy); + } + std::int32_t y0 = (yoffset + h) * sy; + std::int32_t y1 = me->_font_metrics.height * sy; + if (y0 < y1) { + me->writeFillRect(left, y + y0, right - left, y1 - y0); + } } std::uint8_t *bitmap = &font->bitmap[glyph->bitmapOffset]; - std::uint8_t bits=0, bit=0; + std::uint8_t mask=0x80; me->setRawColor(colortbl[1]); - while (h--) { - if (right > left) { + std::int_fast8_t i = 0; + std::int32_t y1 = yoffset * sy; + std::int32_t y0 = y1 - 1; + do { + bool fill = y0 != y1; + y0 = y1; + y1 = (++i + yoffset) * sy; + std::int32_t fh = y1 - y0; + if (!fh) fh = 1; + if (left < right && fill) { me->setRawColor(colortbl[0]); - me->writeFillRect(left, y, right - left, style->size_y); + me->writeFillRect(left, y + y0, right - left, fh); me->setRawColor(colortbl[1]); } - std::int32_t len = 0; - std::int32_t i = 0; - for (i = 0; i < w; i++) { - if (bit == 0) { - bit = 0x80; - bits = *bitmap++; - } - if (bits & bit) len++; - else if (len) { - me->writeFillRect(x + (i-len) * style->size_x, y, style->size_x * len, style->size_y); - len=0; + std::int32_t j = 0; + std::int32_t x0 = 0; + bool flg = false; + do { + do { + if (flg != (bool)(*bitmap & mask)) break; + if (! (mask >>= 1)) { + mask = 0x80; + ++bitmap; + } + } while (++j < w); + std::int32_t x1 = j * sx; + if (flg) { + std::int32_t fw = (x0 < x1) ? x1 - x0 : 1; + me->writeFillRect(x + x0, y + y0, fw, fh); } - bit >>= 1; - } - if (len) { - me->writeFillRect(x + (i-len) * style->size_x, y, style->size_x * len, style->size_y); - } - y += style->size_y; - } + x0 = x1; + flg = !flg; + } while (j < w); + } while (i < h); } else { - if (right > left) { - me->setRawColor(colortbl[0]); - me->writeFillRect(left, y - yoffset + me->_font_metrics.y_offset * style->size_y, right - left, (me->_font_metrics.height) * style->size_y); + if (left < right) { + me->writeFillRect(left, y, right - left, (me->_font_metrics.height) * sy); } } me->_filled_x = right; @@ -1296,12 +1323,17 @@ namespace lgfx file->read((std::uint8_t*)buffer, 24); file->seek(font->gBitmap[gNum]); } + + std::int32_t h = __builtin_bswap32(buffer[0]); // Height of glyph std::int32_t w = __builtin_bswap32(buffer[1]); // Width of glyph - std::int32_t xAdvance = __builtin_bswap32(buffer[2]) * style->size_x; // xAdvance - to move x cursor - std::int32_t xoffset = (std::int32_t)((std::int8_t)__builtin_bswap32(buffer[4])) * style->size_x; // x delta from cursor + float sx = style->size_x; + std::int32_t xAdvance = __builtin_bswap32(buffer[2]) * sx; // xAdvance - to move x cursor + std::int32_t xoffset = (std::int32_t)((std::int8_t)__builtin_bswap32(buffer[4])) * sx; // x delta from cursor std::int32_t dY = (std::int16_t)__builtin_bswap32(buffer[3]); // y delta from baseline - std::int32_t yoffset = ((std::int32_t)font->maxAscent - dY) * (std::int32_t)style->size_y; + float sy = style->size_y; + std::int32_t yoffset = (font->maxAscent - dY); +// std::int32_t yoffset = (me->_font_metrics.y_offset) - dY; std::uint8_t pbuffer[w * h]; std::uint8_t* pixel = pbuffer; @@ -1318,96 +1350,138 @@ namespace lgfx std::int32_t right = 0; if (fillbg) { left = std::max(me->_filled_x, x + (xoffset < 0 ? xoffset : 0)); - right = x + std::max(w * style->size_x + xoffset, xAdvance); + right = x + std::max(w * sx + xoffset, xAdvance); } me->_filled_x = right; x += xoffset; - y += yoffset; - std::int32_t l = 0; + y += int(me->_font_metrics.y_offset * sy); + std::int32_t bx = x; - std::int32_t bw = w * style->size_x; + std::int32_t bw = w * sx; std::int32_t clip_left = me->_clip_l; - if (x < clip_left) { l = -((x - clip_left) / style->size_x); bw += (x - clip_left); bx = clip_left; } - std::int32_t clip_right = me->_clip_r + 1; - if (bw > clip_right - bx) bw = clip_right - bx; - if (bw >= 0 && (y <= me->_clip_b) && (me->_clip_t < (std::int32_t)(y + h * style->size_y))) { + if (x < clip_left) { bw += (x - clip_left); bx = clip_left; } + + std::int32_t clip_right = me->_clip_r; + if (bw > clip_right+1 - bx) bw = clip_right+1 - bx; + + if (bw >= 0) + { std::int32_t fore_r = ((style->fore_rgb888>>16)&0xFF); std::int32_t fore_g = ((style->fore_rgb888>> 8)&0xFF); std::int32_t fore_b = ((style->fore_rgb888) &0xFF); - if (fillbg) { // fill background mode - if (right > left) { + if (fillbg || !me->isReadable() || me->hasPalette()) + { // fill background mode or unreadable panel or palette sprite mode + if (left < right && fillbg) { me->setRawColor(colortbl[0]); - int tmp = yoffset - (me->_font_metrics.y_offset * style->size_y); - if (tmp > 0) - me->writeFillRect(left, y - yoffset + me->_font_metrics.y_offset * style->size_y, right - left, tmp); - - tmp = (me->_font_metrics.y_offset + me->_font_metrics.height - h) * style->size_y - yoffset; - if (tmp > 0) - me->writeFillRect(left, y + h * style->size_y, right - left, tmp); + if (yoffset > 0) { + me->writeFillRect(left, y, right - left, yoffset * sy); + } + std::int32_t y0 = (yoffset + h) * sy; + std::int32_t y1 = me->_font_metrics.height * sy; + if (y0 < y1) { + me->writeFillRect(left, y + y0, right - left, y1 - y0); + } } - std::int32_t r = (clip_right - x + style->size_x - 1) / style->size_x; - if (r > w) r = w; - if (l < r) { - std::int32_t back_r = ((style->back_rgb888>>16)&0xFF); - std::int32_t back_g = ((style->back_rgb888>> 8)&0xFF); - std::int32_t back_b = ((style->back_rgb888) &0xFF); + if (0 < w) { + uint32_t back = fillbg ? style->back_rgb888 : me->_base_rgb888; + std::int32_t back_r = ((back>>16)&0xFF); + std::int32_t back_g = ((back>> 8)&0xFF); + std::int32_t back_b = ( back &0xFF); + std::int32_t i = 0; + std::int32_t y0, y1 = yoffset * sy; do { - if (right > left) { + y0 = y1; + if (y0 > me->_clip_b) break; + y1 = (yoffset + i + 1) * sy; + if (left < right) { me->setRawColor(colortbl[0]); - me->writeFillRect(left, y, right - left, style->size_y); + me->writeFillRect(left, y + y0, right - left, y1 - y0); } - std::int32_t i = l; + std::int32_t j = 0; do { - while (pixel[i] != 0xFF) { - if (pixel[i] != 0) { - std::int32_t p = 1 + (std::uint32_t)pixel[i]; + std::int32_t x0 = j * sx; + while (pixel[j] != 0xFF) { + std::int32_t x1 =(j+1)* sx; + if (pixel[j] != 0 && x0 < x1) { + std::int32_t p = 1 + (std::uint32_t)pixel[j]; me->setColor(color888( ( fore_r * p + back_r * (257 - p)) >> 8 , ( fore_g * p + back_g * (257 - p)) >> 8 , ( fore_b * p + back_b * (257 - p)) >> 8 )); - me->writeFillRect(i * style->size_x + x, y, style->size_x, style->size_y); + me->writeFillRect(x + x0, y + y0, x1 - x0, y1 - y0); } - if (++i == r) break; + x0 = x1; + if (++j == w || clip_right < x0) break; } - if (i == r) break; - std::int32_t dl = 1; - while (i + dl != r && pixel[i + dl] == 0xFF) { ++dl; } + if (j == w || clip_right < x0) break; me->setRawColor(colortbl[1]); - me->writeFillRect(x + i * style->size_x, y, dl * style->size_x, style->size_y); - i += dl; - } while (i != r); + do { ++j; } while (j != w && pixel[j] == 0xFF); + me->writeFillRect(x + x0, y + y0, (j * sx) - x0, y1 - y0); + } while (j != w); pixel += w; - y += style->size_y; - } while (--h); + } while (++i < h); } - } else { // alpha blend mode - - std::int32_t xshift = (bx - x) % style->size_x; - bgr888_t buf[bw * style->size_y]; + } + else // alpha blend mode + { + bgr888_t buf[bw * (int)ceil(sy)]; pixelcopy_t p(buf, me->getColorConverter()->depth, rgb888_3Byte, me->hasPalette()); + std::int32_t y0, y1 = yoffset * sy; + std::int32_t i = 0; do { - std::int32_t by = y; - std::int32_t bh = style->size_y; - if (by < 0) { bh += by; by = 0; } + y0 = y1; + if (y0 > me->_clip_b) break; + y1 = (yoffset + i + 1) * sy; + std::int32_t by = y + y0; + std::int32_t bh = y1 - y0; + + auto ct = me->_clip_t; + if (by < ct) { bh += by - ct; by = ct; } if (bh > 0) { - me->readRectRGB(bx, by, bw, bh, (std::uint8_t*)buf); - for (std::int32_t sx = 0; sx < bw; sx++) { - std::int32_t p = 1 + pixel[left + (sx+xshift) / style->size_x]; - std::int32_t sy = 0; - do { - auto bgr = &buf[sx + sy * bw]; - bgr->r = ( fore_r * p + bgr->r * (257 - p)) >> 8; - bgr->g = ( fore_g * p + bgr->g * (257 - p)) >> 8; - bgr->b = ( fore_b * p + bgr->b * (257 - p)) >> 8; - } while (++sy < bh); + std::int32_t j0 = 0; + std::int32_t j1 = w; + + // search first and last pixel + while (j0 != j1 && !pixel[j0 ]) { ++j0; } + while (j0 != j1 && !pixel[j1 - 1]) { --j1; } + + if (j0 != j1) { + std::int32_t rx = j0 * sx; + std::int32_t rw = j1 * sx; + if (rx < bx -x) rx = bx -x; + if (rw > bx+bw -x) rw = bx+bw -x; + rw -= rx; + + if (0 < rw) { + me->readRectRGB(x + rx, by, rw, bh, (std::uint8_t*)buf); + + std::int32_t x0, x1 = (j0 * sx) - rx; + do { + x0 = x1; + if (x0 < 0) x0 = 0; + x1 = (int)((j0+1) * sx) - rx; + if (x1 > rw) x1 = rw; + if (pixel[j0] && x0 < x1) { + std::int32_t p = 1 + pixel[j0]; + do { + std::int32_t yy = 0; + do { + auto bgr = &buf[x0 + yy * rw]; + bgr->r = ( fore_r * p + bgr->r * (257 - p)) >> 8; + bgr->g = ( fore_g * p + bgr->g * (257 - p)) >> 8; + bgr->b = ( fore_b * p + bgr->b * (257 - p)) >> 8; + } while (++yy != bh); + } while (++x0 != x1); + } + } while (++j0 < j1); + me->push_image(x + rx, by, rw, bh, &p); + } } - me->push_image(bx, by, bw, bh, &p); } pixel += w; - if ((y += style->size_y) >= me->height()) break; - } while (--h); + } while (++i < h); } } me->endWrite(); diff --git a/src/lgfx/lgfx_img_support.hpp b/src/lgfx/lgfx_img_support.hpp index 9d7b471..14cfe69 100644 --- a/src/lgfx/lgfx_img_support.hpp +++ b/src/lgfx/lgfx_img_support.hpp @@ -21,6 +21,7 @@ Original Source: #define LGFX_IMG_SUPPORT_HPP_ #include +#include namespace lgfx { @@ -318,7 +319,7 @@ namespace lgfx } } - this->startWrite(false); + this->startWrite(!data->hasParent()); if (bmpdata.biCompression == 1) { do { data->preRead(); @@ -405,7 +406,7 @@ namespace lgfx if (maxWidth > 0 && maxHeight > 0) { this->setClipRect(x, y, maxWidth, maxHeight); - this->startWrite(); + this->startWrite(!data->hasParent()); jres = lgfx_jd_decomp(&jpegdec, jpg_push_image, scale); this->_clip_l = cl; @@ -450,11 +451,11 @@ namespace lgfx auto data = (DataWrapper*)jpeg->data; data->postRead(); jpeg->lgfx->push_image( jpeg->x + rect->left - , jpeg->y + rect->top - , rect->right - rect->left + 1 - , rect->bottom - rect->top + 1 - , jpeg->pc - , false); + , jpeg->y + rect->top + , rect->right - rect->left + 1 + , rect->bottom - rect->top + 1 + , jpeg->pc + , false); return 1; } @@ -707,7 +708,7 @@ namespace lgfx int len; bool res = true; - this->startWrite(false); + this->startWrite(!data->hasParent()); while (0 < (len = data->read(buf + remain, sizeof(buf) - remain))) { data->postRead(); diff --git a/src/lgfx/lgfx_sprite.hpp b/src/lgfx/lgfx_sprite.hpp index 45ae498..8bc5cbb 100644 --- a/src/lgfx/lgfx_sprite.hpp +++ b/src/lgfx/lgfx_sprite.hpp @@ -94,13 +94,19 @@ namespace lgfx void* createSprite(std::int32_t w, std::int32_t h) { if (w < 1 || h < 1) return nullptr; - if (_img) deleteSprite(); + if (_img != nullptr) { + _mem_free(_img); + _img = nullptr; + } _bitwidth = (w + _write_conv.x_mask) & (~(std::uint32_t)_write_conv.x_mask); size_t len = (h * _bitwidth * _write_conv.bits >> 3) + 1; _img = (std::uint8_t*)_mem_alloc(len); - if (!_img) return nullptr; + if (!_img) { + deleteSprite(); + return nullptr; + } memset(_img, 0, len); - if (0 == _write_conv.bytes) createPalette(); + if (_palette == nullptr && 0 == _write_conv.bytes) createPalette(); _sw = _width = w; _clip_r = _xe = w - 1; @@ -117,7 +123,7 @@ namespace lgfx #if defined (ARDUINO) - #if defined (FS_H) + #if defined (FS_H) || defined (__SEEED_FS__) inline void createFromBmp(fs::FS &fs, const char *path) { createFromBmpFile(fs, path); } void createFromBmpFile(fs::FS &fs, const char *path) { @@ -143,14 +149,6 @@ namespace lgfx create_from_bmp(&data); } - void createFromBmpFile(FileWrapper* file, const char *path) { - file->need_transaction = false; - if (file->open(path, "r")) { - create_from_bmp(file); - file->close(); - } - } - bool createPalette(void) { if (!create_palette()) return false; @@ -331,8 +329,15 @@ namespace lgfx return true; } + void createFromBmpFile(FileWrapper* file, const char *path) { + file->need_transaction = false; + if (file->open(path, "r")) { + create_from_bmp(file); + file->close(); + } + } + bool create_from_bmp(DataWrapper* data) { - //std::uint32_t startTime = millis(); bitmap_header_t bmpdata; if (!load_bmp_header(data, &bmpdata) diff --git a/src/lgfx/panel/panel_ILI9163.hpp b/src/lgfx/panel/panel_ILI9163.hpp index f46c3aa..28360c7 100644 --- a/src/lgfx/panel/panel_ILI9163.hpp +++ b/src/lgfx/panel/panel_ILI9163.hpp @@ -20,12 +20,6 @@ namespace lgfx protected: -// enum colmod_t -// { RGB565_2BYTE = 0x55 -// , RGB666_3BYTE = 0x66 -// }; -// std::uint8_t getColMod(std::uint8_t bpp) const override { return (bpp > 16) ? RGB666_3BYTE : RGB565_2BYTE; } - struct CMD : public CommandCommon { static constexpr std::uint8_t FRMCTR1 = 0xB1; diff --git a/src/lgfx/panel/panel_ILI9341.hpp b/src/lgfx/panel/panel_ILI9341.hpp index 637ec45..5db7c9b 100644 --- a/src/lgfx/panel/panel_ILI9341.hpp +++ b/src/lgfx/panel/panel_ILI9341.hpp @@ -19,12 +19,6 @@ namespace lgfx protected: -// enum colmod_t -// { RGB565_2BYTE = 0x55 -// , RGB666_3BYTE = 0x66 -// }; -// std::uint8_t getColMod(std::uint8_t bpp) const override { return (bpp > 16) ? RGB666_3BYTE : RGB565_2BYTE; } - struct CMD : public PanelIlitekCommon::CommandCommon { static constexpr std::uint8_t FRMCTR1 = 0xB1; @@ -170,12 +164,12 @@ namespace lgfx gpio_rst = 0x0207; // PORTC 7 (PORTC=0x0200 | 7=0x0007) gpio_bl = 0x0205; // PORTC 5 (PORTC=0x0200 | 5=0x0005) freq_fill = 100000000; - freq_write = 50000000; + freq_write = 60000000; freq_read = 20000000; rotation = 1; } - std::uint8_t currentBrightness = 255; + std::uint8_t currentBrightness = 127; std::uint8_t maxBrightness = 255; void init(void) override diff --git a/src/lgfx/panel/panel_ST7735.hpp b/src/lgfx/panel/panel_ST7735.hpp index dbca3a7..f592457 100644 --- a/src/lgfx/panel/panel_ST7735.hpp +++ b/src/lgfx/panel/panel_ST7735.hpp @@ -50,7 +50,7 @@ namespace lgfx }; const std::uint8_t* getInitCommands(std::uint8_t listno) const override { - static constexpr std::uint8_t PROGMEM Bcmd[] = { // Initialization commands for 7735B screens + static constexpr std::uint8_t Bcmd[] = { // Initialization commands for 7735B screens CMD::SWRESET, CMD_INIT_DELAY, 50, // Software reset, no args, w/delay CMD::SLPOUT , CMD_INIT_DELAY, 255, // Out of sleep mode, no args, w/delay CMD::FRMCTR1, 3+CMD_INIT_DELAY, // Frame rate control, 3 args + delay: @@ -108,7 +108,7 @@ namespace lgfx protected: const std::uint8_t* getInitCommands(std::uint8_t listno) const override { - static constexpr std::uint8_t PROGMEM Rcmd1[] = { // Init for 7735R, part 1 (red or green tab) + static constexpr std::uint8_t Rcmd1[] = { // Init for 7735R, part 1 (red or green tab) CMD::SWRESET, CMD_INIT_DELAY, // 1: Software reset, 0 args, w/delay 150, // 150 ms delay CMD::SLPOUT , CMD_INIT_DELAY, // 2: Out of sleep mode, 0 args, w/delay @@ -140,7 +140,7 @@ namespace lgfx 0x0E, 0xFF,0xFF }; - static constexpr std::uint8_t PROGMEM Rcmd2[] = { // Init for 7735R, part 2 (red or green tab) + static constexpr std::uint8_t Rcmd2[] = { // Init for 7735R, part 2 (red or green tab) CMD::GMCTRP1, 16 , // 1: 16 args, no delay: 0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, diff --git a/src/lgfx/platforms/esp32_common.cpp b/src/lgfx/platforms/esp32_common.cpp new file mode 100644 index 0000000..2e8335c --- /dev/null +++ b/src/lgfx/platforms/esp32_common.cpp @@ -0,0 +1,97 @@ +#if defined (ESP32) || (CONFIG_IDF_TARGET_ESP32) || (ESP_PLATFORM) + +#include "esp32_common.hpp" + +#include +#include + +#if defined ARDUINO + #include +#else + #include +#endif + +namespace lgfx +{ + + void lgfxPinMode(std::int_fast8_t pin, pin_mode_t mode) + { +#if defined (ARDUINO) + int m; + switch (mode) + { + case pin_mode_t::output: m = OUTPUT; break; + default: + case pin_mode_t::input: m = INPUT; break; + case pin_mode_t::input_pullup: m = INPUT_PULLUP; break; + case pin_mode_t::input_pulldown: m = INPUT_PULLDOWN; break; + } + pinMode(pin, m); +#else + if (rtc_gpio_is_valid_gpio((gpio_num_t)pin)) rtc_gpio_deinit((gpio_num_t)pin); + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = (std::uint64_t)1 << pin; + switch (mode) + { + case pin_mode_t::output: + io_conf.mode = GPIO_MODE_OUTPUT; + break; + default: + io_conf.mode = GPIO_MODE_INPUT; + break; + } + io_conf.mode = (mode == pin_mode_t::output) ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT; + io_conf.pull_down_en = (mode == pin_mode_t::input_pulldown) ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = (mode == pin_mode_t::input_pullup ) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; + gpio_config(&io_conf); +#endif + } + + void initPWM(std::int_fast8_t pin, std::uint32_t pwm_ch, std::uint8_t duty) + { +#ifdef ARDUINO + + ledcSetup(pwm_ch, 12000, 8); + ledcAttachPin(pin, pwm_ch); + ledcWrite(pwm_ch, duty); + +#else + + static ledc_channel_config_t ledc_channel; + { + ledc_channel.gpio_num = (gpio_num_t)pin; + ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; + ledc_channel.channel = (ledc_channel_t)pwm_ch; + ledc_channel.intr_type = LEDC_INTR_DISABLE; + ledc_channel.timer_sel = (ledc_timer_t)((pwm_ch >> 1) & 3); + ledc_channel.duty = duty; // duty; + ledc_channel.hpoint = 0; + }; + ledc_channel_config(&ledc_channel); + static ledc_timer_config_t ledc_timer; + { + ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; // timer mode + ledc_timer.duty_resolution = (ledc_timer_bit_t)8; // resolution of PWM duty + ledc_timer.freq_hz = 12000; // frequency of PWM signal + ledc_timer.timer_num = ledc_channel.timer_sel; // timer index + }; + ledc_timer_config(&ledc_timer); + +#endif + } + + void setPWMDuty(std::uint32_t pwm_ch, std::uint8_t duty) + { +#ifdef ARDUINO + ledcWrite(pwm_ch, duty); +#else + ledc_set_duty(LEDC_HIGH_SPEED_MODE, (ledc_channel_t)pwm_ch, duty); + ledc_update_duty(LEDC_HIGH_SPEED_MODE, (ledc_channel_t)pwm_ch); +#endif + } + + +}; + +#endif diff --git a/src/lgfx/platforms/esp32_common.hpp b/src/lgfx/platforms/esp32_common.hpp index 3f7516f..c9f8857 100644 --- a/src/lgfx/platforms/esp32_common.hpp +++ b/src/lgfx/platforms/esp32_common.hpp @@ -1,94 +1,26 @@ #ifndef LGFX_ESP32_COMMON_HPP_ #define LGFX_ESP32_COMMON_HPP_ -#include -#include -#include -#include -#include -#include -#include +#include "../lgfx_common.hpp" -#ifdef ARDUINO +#include + +#if defined ARDUINO #include - #include #include - #include - #include #else - #include - - static void delay(std::uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } + #include + #include -// static constexpr std::uint32_t MATRIX_DETACH_OUT_SIG = 0x100; -// static constexpr std::uint32_t MATRIX_DETACH_IN_LOW_PIN = 0x30; -// static constexpr std::uint32_t MATRIX_DETACH_IN_LOW_HIGH = 0x38; -// static void IRAM_ATTR pinMatrixOutAttach(std::uint8_t pin, std::uint8_t function, bool invertOut, bool invertEnable) { gpio_matrix_out(pin, function, invertOut, invertEnable); } -// static void IRAM_ATTR pinMatrixOutDetach(std::uint8_t pin , bool invertOut, bool invertEnable) { gpio_matrix_out(pin, MATRIX_DETACH_OUT_SIG, invertOut, invertEnable); } -// static void IRAM_ATTR pinMatrixInAttach( std::uint8_t pin, std::uint8_t signal , bool inverted) { gpio_matrix_in(pin, signal, inverted); } -// static void IRAM_ATTR pinMatrixInDetach( std::uint8_t signal, bool high, bool inverted) { gpio_matrix_in(high?MATRIX_DETACH_IN_LOW_HIGH:MATRIX_DETACH_IN_LOW_PIN, signal, inverted); } - - static std::uint32_t getApbFrequency() { - rtc_cpu_freq_config_t conf; - rtc_clk_cpu_freq_get_config(&conf); - if (conf.freq_mhz >= 80){ - return 80 * 1000000; - } - return (conf.source_freq_mhz * 1000000) / conf.div; - } + static inline void delay(std::uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } #endif - namespace lgfx { - static void* heap_alloc_psram(size_t length) - { - return heap_caps_malloc(length, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - } - - __attribute__((__used__)) - __attribute__((always_inline)) inline - static void* heap_alloc_dma(size_t length) - { - return heap_caps_malloc((length + 3) & ~3, MALLOC_CAP_DMA); - } - - static void* heap_alloc(size_t length) - { - return heap_caps_malloc(length, MALLOC_CAP_8BIT); - } - - __attribute__((__used__)) - __attribute__((always_inline)) inline - static void heap_free(void* dmabuffer) - { - heap_caps_free(dmabuffer); - } - - static std::uint32_t FreqToClockDiv(std::uint32_t fapb, std::uint32_t hz) - { - if (hz > ((fapb >> 2) * 3)) { - return SPI_CLK_EQU_SYSCLK; - } - std::uint32_t besterr = fapb; - std::uint32_t halfhz = hz >> 1; - std::uint32_t bestn = 0; - std::uint32_t bestpre = 0; - for (std::uint32_t n = 2; n <= 64; n++) { - std::uint32_t pre = ((fapb / n) + halfhz) / hz; - if (pre == 0) pre = 1; - else if (pre > 8192) pre = 8192; - - int errval = abs((std::int32_t)(fapb / (pre * n) - hz)); - if (errval < besterr) { - besterr = errval; - bestn = n - 1; - bestpre = pre - 1; - if (!besterr) break; - } - } - return bestpre << 18 | bestn << 12 | ((bestn-1)>>1) << 6 | bestn; - } + static inline void* heap_alloc( size_t length) { return heap_caps_malloc(length, MALLOC_CAP_8BIT); } + static inline void* heap_alloc_dma( size_t length) { return heap_caps_malloc((length + 3) & ~3, MALLOC_CAP_DMA); } + static inline void* heap_alloc_psram(size_t length) { return heap_caps_malloc(length, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); } + static inline void heap_free(void* buf) { heap_caps_free(buf); } enum pin_mode_t { output @@ -97,86 +29,17 @@ namespace lgfx , input_pulldown }; -#if defined (ARDUINO) - static void lgfxPinMode(std::int_fast8_t pin, int mode) { - switch (mode) { - case pin_mode_t::output: mode = OUTPUT; break; - case pin_mode_t::input: mode = INPUT; break; - case pin_mode_t::input_pullup: mode = INPUT_PULLUP; break; - case pin_mode_t::input_pulldown: mode = INPUT_PULLDOWN; break; - } - pinMode(pin, mode); - }; -#else - static void lgfxPinMode(std::int_fast8_t pin, pin_mode_t mode) { - if (pin == -1) return; - if (rtc_gpio_is_valid_gpio((gpio_num_t)pin)) rtc_gpio_deinit((gpio_num_t)pin); - gpio_config_t io_conf; - io_conf.intr_type = GPIO_INTR_DISABLE; - io_conf.pin_bit_mask = (std::uint64_t)1 << pin; - switch (mode) { - case pin_mode_t::output: - io_conf.mode = GPIO_MODE_OUTPUT; - break; - default: - io_conf.mode = GPIO_MODE_INPUT; - break; - } - io_conf.mode = (mode == pin_mode_t::output) ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT; - io_conf.pull_down_en = (mode == pin_mode_t::input_pulldown) ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE; - io_conf.pull_up_en = (mode == pin_mode_t::input_pullup ) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; - gpio_config(&io_conf); - } -#endif - - static volatile std::uint32_t* get_gpio_hi_reg(std::int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1ts.val : &GPIO.out_w1ts; } - static volatile std::uint32_t* get_gpio_lo_reg(std::int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1tc.val : &GPIO.out_w1tc; } - - static void gpio_hi(std::int_fast8_t pin) { *get_gpio_hi_reg(pin) = 1 << (pin & 31); } - static void gpio_lo(std::int_fast8_t pin) { *get_gpio_lo_reg(pin) = 1 << (pin & 31); } - static bool gpio_in(std::int_fast8_t pin) { return ((pin & 32) ? GPIO.in1.data : GPIO.in) & (1 << (pin & 31)); } - - static void initPWM(std::int_fast8_t pin, std::uint32_t pwm_ch, std::uint8_t duty = 128) { + void lgfxPinMode(std::int_fast8_t pin, pin_mode_t mode); -#ifdef ARDUINO - - ledcSetup(pwm_ch, 12000, 8); - ledcAttachPin(pin, pwm_ch); - ledcWrite(pwm_ch, duty); - -#else + void initPWM(std::int_fast8_t pin, std::uint32_t pwm_ch, std::uint8_t duty = 128); - static ledc_channel_config_t ledc_channel; - { - ledc_channel.gpio_num = (gpio_num_t)pin; - ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; - ledc_channel.channel = (ledc_channel_t)pwm_ch; - ledc_channel.intr_type = LEDC_INTR_DISABLE; - ledc_channel.timer_sel = (ledc_timer_t)((pwm_ch >> 1) & 3); - ledc_channel.duty = duty; // duty; - ledc_channel.hpoint = 0; - }; - ledc_channel_config(&ledc_channel); - static ledc_timer_config_t ledc_timer; - { - ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; // timer mode - ledc_timer.duty_resolution = (ledc_timer_bit_t)8; // resolution of PWM duty - ledc_timer.freq_hz = 12000; // frequency of PWM signal - ledc_timer.timer_num = ledc_channel.timer_sel; // timer index - }; - ledc_timer_config(&ledc_timer); + void setPWMDuty(std::uint32_t pwm_ch, std::uint8_t duty); -#endif - } - - static void setPWMDuty(std::uint32_t pwm_ch, std::uint8_t duty) { -#ifdef ARDUINO - ledcWrite(pwm_ch, duty); -#else - ledc_set_duty(LEDC_HIGH_SPEED_MODE, (ledc_channel_t)pwm_ch, duty); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, (ledc_channel_t)pwm_ch); -#endif - } + static inline volatile std::uint32_t* get_gpio_hi_reg(std::int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1ts.val : &GPIO.out_w1ts; } + static inline volatile std::uint32_t* get_gpio_lo_reg(std::int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1tc.val : &GPIO.out_w1tc; } + static inline void gpio_hi(std::int_fast8_t pin) { *get_gpio_hi_reg(pin) = 1 << (pin & 31); } + static inline void gpio_lo(std::int_fast8_t pin) { *get_gpio_lo_reg(pin) = 1 << (pin & 31); } + static inline bool gpio_in(std::int_fast8_t pin) { return ((pin & 32) ? GPIO.in1.data : GPIO.in) & (1 << (pin & 31)); } /* diff --git a/src/lgfx/platforms/lgfx_spi_esp32.hpp b/src/lgfx/platforms/lgfx_spi_esp32.hpp index 46b5de2..4ab04a5 100644 --- a/src/lgfx/platforms/lgfx_spi_esp32.hpp +++ b/src/lgfx/platforms/lgfx_spi_esp32.hpp @@ -20,19 +20,40 @@ Original Source: #ifndef LGFX_SPI_ESP32_HPP_ #define LGFX_SPI_ESP32_HPP_ +#include #include + +#include +#include +#include #include #include -#include +#include +#include +#include #if defined (ARDUINO) // Arduino ESP32 #include + #include + #include + #include #else #include #include #if ESP_IDF_VERSION_MAJOR > 3 #include #endif + + static std::uint32_t getApbFrequency() + { + rtc_cpu_freq_config_t conf; + rtc_clk_cpu_freq_get_config(&conf); + if (conf.freq_mhz >= 80){ + return 80 * 1000000; + } + return (conf.source_freq_mhz * 1000000) / conf.div; + } + #endif #include "esp32_common.hpp" @@ -324,9 +345,8 @@ namespace lgfx //---------------------------------------------------------------------------- protected: -// template static PanelCommon* createPanel(const T&) { return new T; } -// template static PanelCommon* createPanelFromConfig(decltype(T::panel)*) { return createPanel(T::panel); } -// template static PanelCommon* createPanelFromConfig(...) { return nullptr; } + + bool isReadable_impl(void) const override { return _panel->spi_read; } void postSetPanel(void) { @@ -336,9 +356,10 @@ namespace lgfx fpGetWindowAddr = _len_setwindow == 32 ? PanelCommon::getWindowAddr32 : PanelCommon::getWindowAddr16; std::int32_t spi_dc = _panel->spi_dc; + _mask_reg_dc = (spi_dc < 0) ? 0 : (1 << (spi_dc & 31)); + _gpio_reg_dc_h = get_gpio_hi_reg(spi_dc); _gpio_reg_dc_l = get_gpio_lo_reg(spi_dc); - _mask_reg_dc = (spi_dc < 0) ? 0 : (1 << (spi_dc & 31)); dc_h(); lgfxPinMode(spi_dc, pin_mode_t::output); @@ -754,7 +775,7 @@ namespace lgfx memcpy(buf, src, len); write_bytes(buf, len, true); } else { - write_bytes(src, len, false); + write_bytes(src, len, use_dma); } } else { auto add = param->src_width * bytes; @@ -793,7 +814,7 @@ namespace lgfx auto buf = get_dmabuffer(w * bytes); std::int32_t len = fp_copy(buf, 0, w - i, param); setWindow_impl(x + i, y, x + i + len - 1, y); - write_bytes(buf, len * bytes, use_dma); + write_bytes(buf, len * bytes, true); if (w == (i += len)) break; } param->src_x = src_x; @@ -1189,6 +1210,31 @@ namespace lgfx virtual void cs_l_impl(void) {} //*/ + static std::uint32_t FreqToClockDiv(std::uint32_t fapb, std::uint32_t hz) + { + if (hz > ((fapb >> 2) * 3)) { + return SPI_CLK_EQU_SYSCLK; + } + std::uint32_t besterr = fapb; + std::uint32_t halfhz = hz >> 1; + std::uint32_t bestn = 0; + std::uint32_t bestpre = 0; + for (std::uint32_t n = 2; n <= 64; n++) { + std::uint32_t pre = ((fapb / n) + halfhz) / hz; + if (pre == 0) pre = 1; + else if (pre > 8192) pre = 8192; + + int errval = abs((std::int32_t)(fapb / (pre * n) - hz)); + if (errval < besterr) { + besterr = errval; + bestn = n - 1; + bestpre = pre - 1; + if (!besterr) break; + } + } + return bestpre << 18 | bestn << 12 | ((bestn-1)>>1) << 6 | bestn; + } + static constexpr int _dma_channel= get_dma_channel::value; static constexpr int _spi_mosi = get_spi_mosi::value; static constexpr int _spi_miso = get_spi_miso::value; diff --git a/src/lgfx/utility/lgfx_pngle.c b/src/lgfx/utility/lgfx_pngle.c index 547c381..095a21e 100644 --- a/src/lgfx/utility/lgfx_pngle.c +++ b/src/lgfx/utility/lgfx_pngle.c @@ -242,7 +242,7 @@ static uint_fast16_t check_trans_color(pngle_t *pngle, uint_fast16_t *value, siz if (pngle->n_trans_palettes != 1) return ~0; // (none or indexed) for (size_t i = 0; i < n; ++i) { - if (value[i] != (pngle->trans_palette[i * 2 + 0] << 8 | pngle->trans_palette[i * 2 + 1])) return ~0; // not transcolor + if (value[i] != (uint_fast16_t)(pngle->trans_palette[i * 2 + 0] << 8 | pngle->trans_palette[i * 2 + 1])) return ~0; // not transcolor } return 0; // transcolor } diff --git a/src/utility/TinyBMPEncoder.cpp b/src/utility/TinyBMPEncoder.cpp index 82a7e87..f0f9efe 100644 --- a/src/utility/TinyBMPEncoder.cpp +++ b/src/utility/TinyBMPEncoder.cpp @@ -35,7 +35,6 @@ void BMP_Encoder::init( M5Display *tft, fs::FS &fileSystem ) { } bool BMP_Encoder::encodeToFile( const char* filename, const int imageW, const int imageH ) { - byte colorByteH, colorByteL; rgbBuffer = (RGBColor*)calloc( imageW+1, sizeof( RGBColor ) ); fs::File outFile = _fileSystem->open( filename, "w" ); // <-----fs:: added for compatibility with SdFat ------ diff --git a/src/utility/TouchButton.cpp b/src/utility/TouchButton.cpp index 1f2c9d9..a60381c 100644 --- a/src/utility/TouchButton.cpp +++ b/src/utility/TouchButton.cpp @@ -60,7 +60,7 @@ void TouchButton::drawButton(String label, boolean inverted, uint16_t margin) { _gfx->setTextColor(text); _gfx->setTextSize(_textsize); - uint8_t tempdatum = _gfx->getTextDatum(); + textdatum_t tempdatum = _gfx->getTextDatum(); _gfx->setTextDatum(ML_DATUM); if (label == "") _gfx->drawString(_label, _x1 + margin, _y1 + (_h/2)); @@ -89,7 +89,7 @@ void TouchButton::drawButton(boolean inverted) { _gfx->setTextColor(text); _gfx->setTextSize(_textsize); - uint8_t tempdatum = _gfx->getTextDatum(); + textdatum_t tempdatum = _gfx->getTextDatum(); _gfx->setTextDatum(MC_DATUM); _gfx->drawString(_label, _x1 + (_w/2), _y1 + (_h/2)); _gfx->setTextDatum(tempdatum);