diff --git a/Extensions/SmoothFont.cpp b/Extensions/SmoothFont.cpp new file mode 100644 index 0000000..fe17953 --- /dev/null +++ b/Extensions/SmoothFont.cpp @@ -0,0 +1,344 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// New anti-aliased (smoothed) font functions added below +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: loadFont +** Description: loads parameters from a font vlw array in memory +*************************************************************************************x*/ +void TFT_eSPI_SmoothFont::loadFont(const uint8_t array[]) +{ + if (array == nullptr) return; + fontPtr = (uint8_t*) array; + loadFont("", false); +} + +#ifdef FONT_FS_AVAILABLE +/*************************************************************************************** +** Function name: loadFont +** Description: loads parameters from a font vlw file +*************************************************************************************x*/ +void TFT_eSPI_SmoothFont::loadFont(String fontName, fs::FS &ffs) +{ + fontFS = ffs; + loadFont(fontName, false); +} +#endif + +/*************************************************************************************** +** Function name: loadFont +** Description: loads parameters from a font vlw file +*************************************************************************************x*/ +void TFT_eSPI_SmoothFont::loadFont(String fontName, bool flash) +{ + /* + The vlw font format does not appear to be documented anywhere, so some reverse + engineering has been applied! + + Header of vlw file comprises 6 uint32_t parameters (24 bytes total): + 1. The gCount (number of character glyphs) + 2. A version number (0xB = 11 for the one I am using) + 3. The font size (in points, not pixels) + 4. Deprecated mboxY parameter (typically set to 0) + 5. Ascent in pixels from baseline to top of "d" + 6. Descent in pixels from baseline to bottom of "p" + + Next are gCount sets of values for each glyph, each set comprises 7 int32t parameters (28 bytes): + 1. Glyph Unicode stored as a 32 bit value + 2. Height of bitmap bounding box + 3. Width of bitmap bounding box + 4. gxAdvance for cursor (setWidth in Processing) + 5. dY = distance from cursor baseline to top of glyph bitmap (signed value +ve = up) + 6. dX = distance from cursor to left side of glyph bitmap (signed value -ve = left) + 7. padding value, typically 0 + + The bitmaps start next at 24 + (28 * gCount) bytes from the start of the file. + Each pixel is 1 byte, an 8 bit Alpha value which represents the transparency from + 0xFF foreground colour, 0x00 background. The sketch uses a linear interpolation + between the foreground and background RGB component colours. e.g. + pixelRed = ((fgRed * alpha) + (bgRed * (255 - alpha))/255 + To gain a performance advantage fixed point arithmetic is used with rounding and + division by 256 (shift right 8 bits is faster). + + After the bitmaps is: + 1 byte for font name string length (excludes null) + a zero terminated character string giving the font name + 1 byte for Postscript name string length + a zero/one terminated character string giving the font name + last byte is 0 for non-anti-aliased and 1 for anti-aliased (smoothed) + + + Glyph bitmap example is: + // Cursor coordinate positions for this and next character are marked by 'C' + // C<------- gxAdvance ------->C gxAdvance is how far to move cursor for next glyph cursor position + // | | + // | | ascent is top of "d", descent is bottom of "p" + // +-- gdX --+ ascent + // | +-- gWidth--+ | gdX is offset to left edge of glyph bitmap + // | + x@.........@x + | gdX may be negative e.g. italic "y" tail extending to left of + // | | @@.........@@ | | cursor position, plot top left corner of bitmap at (cursorX + gdX) + // | | @@.........@@ gdY | gWidth and gHeight are glyph bitmap dimensions + // | | .@@@.....@@@@ | | + // | gHeight ....@@@@@..@@ + + <-- baseline + // | | ...........@@ | + // | | ...........@@ | gdY is the offset to the top edge of the bitmap + // | | .@@.......@@. descent plot top edge of bitmap at (cursorY + yAdvance - gdY) + // | + x..@@@@@@@..x | x marks the corner pixels of the bitmap + // | | + // +---------------------------+ yAdvance is y delta for the next line, font size or (ascent + descent) + // some fonts can overlay in y direction so may need a user adjust value + + */ + + if (fontLoaded) return; + +#ifdef FONT_FS_AVAILABLE + if (fontName == "") fs_font = false; + else { fontPtr = nullptr; fs_font = true; } + + if (fs_font) { + spiffs = flash; // true if font is in SPIFFS + + if(spiffs) fontFS = SPIFFS; + + // Avoid a crash on the ESP32 if the file does not exist + if (fontFS.exists("/" + fontName + ".vlw") == false) { + Serial.println("Font file " + fontName + " not found!"); + return; + } + + fontFile = fontFS.open( "/" + fontName + ".vlw", "r"); + + if(!fontFile) return; + + fontFile.seek(0, fs::SeekSet); + } +#endif + + gFont.gArray = (const uint8_t*)fontPtr; + + gFont.gCount = (uint16_t)readInt32(); // glyph count in file + readInt32(); // vlw encoder version - discard + gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels + readInt32(); // discard + gFont.ascent = (uint16_t)readInt32(); // top of "d" + gFont.descent = (uint16_t)readInt32(); // bottom of "p" + + // These next gFont values might be updated when the Metrics are fetched + gFont.maxAscent = gFont.ascent; // Determined from metrics + gFont.maxDescent = gFont.descent; // Determined from metrics + gFont.yAdvance = gFont.ascent + gFont.descent; + gFont.spaceWidth = gFont.yAdvance / 4; // Guess at space width + + fontLoaded = true; + + // Fetch the metrics for each glyph + loadMetrics(); +} + + +/*************************************************************************************** +** Function name: loadMetrics +** Description: Get the metrics for each glyph and store in RAM +*************************************************************************************x*/ +//#define SHOW_ASCENT_DESCENT +void TFT_eSPI_SmoothFont::loadMetrics(void) +{ + uint32_t headerPtr = 24; + uint32_t bitmapPtr = headerPtr + gFont.gCount * 28; + +#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT) + if ( psramFound() ) + { + gUnicode = (uint16_t*)ps_malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF) + gHeight = (uint8_t*)ps_malloc( gFont.gCount ); // Height of glyph + gWidth = (uint8_t*)ps_malloc( gFont.gCount ); // Width of glyph + gxAdvance = (uint8_t*)ps_malloc( gFont.gCount ); // xAdvance - to move x cursor + gdY = (int16_t*)ps_malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character + gdX = (int8_t*)ps_malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X + gBitmap = (uint32_t*)ps_malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file + } + else +#endif + { + gUnicode = (uint16_t*)malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF) + gHeight = (uint8_t*)malloc( gFont.gCount ); // Height of glyph + gWidth = (uint8_t*)malloc( gFont.gCount ); // Width of glyph + gxAdvance = (uint8_t*)malloc( gFont.gCount ); // xAdvance - to move x cursor + gdY = (int16_t*)malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character + gdX = (int8_t*)malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X + gBitmap = (uint32_t*)malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file + } + +#ifdef SHOW_ASCENT_DESCENT + Serial.print("ascent = "); Serial.println(gFont.ascent); + Serial.print("descent = "); Serial.println(gFont.descent); +#endif + +#ifdef FONT_FS_AVAILABLE + if (fs_font) fontFile.seek(headerPtr, fs::SeekSet); +#endif + + uint16_t gNum = 0; + + while (gNum < gFont.gCount) + { + gUnicode[gNum] = (uint16_t)readInt32(); // Unicode code point value + gHeight[gNum] = (uint8_t)readInt32(); // Height of glyph + gWidth[gNum] = (uint8_t)readInt32(); // Width of glyph + gxAdvance[gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor + gdY[gNum] = (int16_t)readInt32(); // y delta from baseline + gdX[gNum] = (int8_t)readInt32(); // x delta from cursor + readInt32(); // ignored + + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gHeight = "); Serial.println(gHeight[gNum]); + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gWidth = "); Serial.println(gWidth[gNum]); + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gxAdvance = "); Serial.println(gxAdvance[gNum]); + //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gdY = "); Serial.println(gdY[gNum]); + + // Different glyph sets have different ascent values not always based on "d", so we could get + // the maximum glyph ascent by checking all characters. BUT this method can generate bad values + // for non-existant glyphs, so we will reply on processing for the value and disable this code for now... + + if (gdY[gNum] > gFont.maxAscent) + { + // Try to avoid UTF coding values and characters that tend to give duff values + if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0x7F)) || (gUnicode[gNum] > 0xA0)) + { + gFont.maxAscent = gdY[gNum]; +#ifdef SHOW_ASCENT_DESCENT + Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxAscent = "); Serial.println(gFont.maxAscent); +#endif + } + } + + +// // Different glyph sets have different descent values not always based on "p", so get maximum glyph descent +// if (((int16_t)gHeight[gNum] - (int16_t)gdY[gNum]) > gFont.maxDescent) +// { +// // Avoid UTF coding values and characters that tend to give duff values +// if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0xA0) && (gUnicode[gNum] != 0x7F)) || (gUnicode[gNum] > 0xFF)) +// { +// gFont.maxDescent = gHeight[gNum] - gdY[gNum]; +// #ifdef SHOW_ASCENT_DESCENT +// Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxDescent = "); Serial.println(gHeight[gNum] - gdY[gNum]); +// #endif +// } +// } + + gBitmap[gNum] = bitmapPtr; + + bitmapPtr += gWidth[gNum] * gHeight[gNum]; + + gNum++; + yield(); + } + + gFont.yAdvance = gFont.maxAscent + gFont.maxDescent; + + gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width +} + + +/*************************************************************************************** +** Function name: deleteMetrics +** Description: Delete the old glyph metrics and free up the memory +*************************************************************************************x*/ +void TFT_eSPI_SmoothFont::unloadFont( void ) +{ + if (gUnicode) + { + free(gUnicode); + gUnicode = NULL; + } + + if (gHeight) + { + free(gHeight); + gHeight = NULL; + } + + if (gWidth) + { + free(gWidth); + gWidth = NULL; + } + + if (gxAdvance) + { + free(gxAdvance); + gxAdvance = NULL; + } + + if (gdY) + { + free(gdY); + gdY = NULL; + } + + if (gdX) + { + free(gdX); + gdX = NULL; + } + + if (gBitmap) + { + free(gBitmap); + gBitmap = NULL; + } + + gFont.gArray = nullptr; + +#ifdef FONT_FS_AVAILABLE + if (fs_font && fontFile) fontFile.close(); +#endif + + fontLoaded = false; +} + + +/*************************************************************************************** +** Function name: readInt32 +** Description: Get a 32 bit integer from the font file +*************************************************************************************x*/ +uint32_t TFT_eSPI_SmoothFont::readInt32(void) +{ + uint32_t val = 0; + +#ifdef FONT_FS_AVAILABLE + if (fs_font) { + val |= fontFile.read() << 24; + val |= fontFile.read() << 16; + val |= fontFile.read() << 8; + val |= fontFile.read(); + } + else +#endif + { + val |= pgm_read_byte(fontPtr++) << 24; + val |= pgm_read_byte(fontPtr++) << 16; + val |= pgm_read_byte(fontPtr++) << 8; + val |= pgm_read_byte(fontPtr++); + } + + return val; +} + + +/*************************************************************************************** +** Function name: getUnicodeIndex +** Description: Get the font file index of a Unicode character +*************************************************************************************x*/ +bool TFT_eSPI_SmoothFont::getUnicodeIndex(uint16_t unicode, uint16_t *index) +{ + for (uint16_t i = 0; i < gFont.gCount; i++) + { + if (gUnicode[i] == unicode) + { + *index = i; + return true; + } + } + return false; +} diff --git a/Extensions/SmoothFont.h b/Extensions/SmoothFont.h new file mode 100644 index 0000000..18c963c --- /dev/null +++ b/Extensions/SmoothFont.h @@ -0,0 +1,61 @@ + // Coded by Bodmer 10/2/18, see license in root directory. + // This is part of the TFT_eSPI class and is associated with anti-aliased font functions + +class TFT_eSPI_SmoothFont { + + private: + String filename; + public: + + // These are for the new antialiased fonts + void loadFont(const uint8_t array[]); +#ifdef FONT_FS_AVAILABLE + void loadFont(String fontName, fs::FS &ffs); +#endif + void loadFont(String fontName, bool flash = true); + void unloadFont( void ); + bool getUnicodeIndex(uint16_t unicode, uint16_t *index); + + // This is for the whole font + typedef struct + { + const uint8_t* gArray; //array start pointer + uint16_t gCount; // Total number of characters + uint16_t yAdvance; // Line advance + uint16_t spaceWidth; // Width of a space character + int16_t ascent; // Height of top of 'd' above baseline, other characters may be taller + int16_t descent; // Offset to bottom of 'p', other characters may have a larger descent + uint16_t maxAscent; // Maximum ascent found in font + uint16_t maxDescent; // Maximum descent found in font + } fontMetrics; + +fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; + + // These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time) + uint16_t* gUnicode = NULL; //UTF-16 code, the codes are searched so do not need to be sequential + uint8_t* gHeight = NULL; //cheight + uint8_t* gWidth = NULL; //cwidth + uint8_t* gxAdvance = NULL; //setWidth + int16_t* gdY = NULL; //topExtent + int8_t* gdX = NULL; //leftExtent + uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap + + +#ifdef FONT_FS_AVAILABLE + fs::File fontFile; + fs::FS &fontFS = SPIFFS; + bool spiffs = true; + bool fs_font = false; // For ESP32/8266 use smooth font file or FLASH (PROGMEM) array + +#else + bool fontFile = true; +#endif + + private: + bool fontLoaded = false; + void loadMetrics(void); + uint32_t readInt32(void); + + uint8_t* fontPtr = nullptr; + +}; diff --git a/Extensions/Smooth_font.cpp b/Extensions/Smooth_font.cpp index 2d5c787..b290ada 100644 --- a/Extensions/Smooth_font.cpp +++ b/Extensions/Smooth_font.cpp @@ -12,8 +12,6 @@ *************************************************************************************x*/ void TFT_eSPI::loadFont(const uint8_t array[]) { - if (array == nullptr) return; - fontPtr = (uint8_t*) array; loadFont("", false); } @@ -24,7 +22,6 @@ void TFT_eSPI::loadFont(const uint8_t array[]) *************************************************************************************x*/ void TFT_eSPI::loadFont(String fontName, fs::FS &ffs) { - fontFS = ffs; loadFont(fontName, false); } #endif @@ -35,212 +32,8 @@ void TFT_eSPI::loadFont(String fontName, fs::FS &ffs) *************************************************************************************x*/ void TFT_eSPI::loadFont(String fontName, bool flash) { - /* - The vlw font format does not appear to be documented anywhere, so some reverse - engineering has been applied! - - Header of vlw file comprises 6 uint32_t parameters (24 bytes total): - 1. The gCount (number of character glyphs) - 2. A version number (0xB = 11 for the one I am using) - 3. The font size (in points, not pixels) - 4. Deprecated mboxY parameter (typically set to 0) - 5. Ascent in pixels from baseline to top of "d" - 6. Descent in pixels from baseline to bottom of "p" - - Next are gCount sets of values for each glyph, each set comprises 7 int32t parameters (28 bytes): - 1. Glyph Unicode stored as a 32 bit value - 2. Height of bitmap bounding box - 3. Width of bitmap bounding box - 4. gxAdvance for cursor (setWidth in Processing) - 5. dY = distance from cursor baseline to top of glyph bitmap (signed value +ve = up) - 6. dX = distance from cursor to left side of glyph bitmap (signed value -ve = left) - 7. padding value, typically 0 - - The bitmaps start next at 24 + (28 * gCount) bytes from the start of the file. - Each pixel is 1 byte, an 8 bit Alpha value which represents the transparency from - 0xFF foreground colour, 0x00 background. The sketch uses a linear interpolation - between the foreground and background RGB component colours. e.g. - pixelRed = ((fgRed * alpha) + (bgRed * (255 - alpha))/255 - To gain a performance advantage fixed point arithmetic is used with rounding and - division by 256 (shift right 8 bits is faster). - - After the bitmaps is: - 1 byte for font name string length (excludes null) - a zero terminated character string giving the font name - 1 byte for Postscript name string length - a zero/one terminated character string giving the font name - last byte is 0 for non-anti-aliased and 1 for anti-aliased (smoothed) - - - Glyph bitmap example is: - // Cursor coordinate positions for this and next character are marked by 'C' - // C<------- gxAdvance ------->C gxAdvance is how far to move cursor for next glyph cursor position - // | | - // | | ascent is top of "d", descent is bottom of "p" - // +-- gdX --+ ascent - // | +-- gWidth--+ | gdX is offset to left edge of glyph bitmap - // | + x@.........@x + | gdX may be negative e.g. italic "y" tail extending to left of - // | | @@.........@@ | | cursor position, plot top left corner of bitmap at (cursorX + gdX) - // | | @@.........@@ gdY | gWidth and gHeight are glyph bitmap dimensions - // | | .@@@.....@@@@ | | - // | gHeight ....@@@@@..@@ + + <-- baseline - // | | ...........@@ | - // | | ...........@@ | gdY is the offset to the top edge of the bitmap - // | | .@@.......@@. descent plot top edge of bitmap at (cursorY + yAdvance - gdY) - // | + x..@@@@@@@..x | x marks the corner pixels of the bitmap - // | | - // +---------------------------+ yAdvance is y delta for the next line, font size or (ascent + descent) - // some fonts can overlay in y direction so may need a user adjust value - - */ - - if (fontLoaded) unloadFont(); - -#ifdef FONT_FS_AVAILABLE - if (fontName == "") fs_font = false; - else { fontPtr = nullptr; fs_font = true; } - - if (fs_font) { - spiffs = flash; // true if font is in SPIFFS - - if(spiffs) fontFS = SPIFFS; - - // Avoid a crash on the ESP32 if the file does not exist - if (fontFS.exists("/" + fontName + ".vlw") == false) { - Serial.println("Font file " + fontName + " not found!"); - return; - } - - fontFile = fontFS.open( "/" + fontName + ".vlw", "r"); - - if(!fontFile) return; - - fontFile.seek(0, fs::SeekSet); - } -#endif - - gFont.gArray = (const uint8_t*)fontPtr; - - gFont.gCount = (uint16_t)readInt32(); // glyph count in file - readInt32(); // vlw encoder version - discard - gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels - readInt32(); // discard - gFont.ascent = (uint16_t)readInt32(); // top of "d" - gFont.descent = (uint16_t)readInt32(); // bottom of "p" - - // These next gFont values might be updated when the Metrics are fetched - gFont.maxAscent = gFont.ascent; // Determined from metrics - gFont.maxDescent = gFont.descent; // Determined from metrics - gFont.yAdvance = gFont.ascent + gFont.descent; - gFont.spaceWidth = gFont.yAdvance / 4; // Guess at space width - + sf->loadFont(fontName, flash); fontLoaded = true; - - // Fetch the metrics for each glyph - loadMetrics(); -} - - -/*************************************************************************************** -** Function name: loadMetrics -** Description: Get the metrics for each glyph and store in RAM -*************************************************************************************x*/ -//#define SHOW_ASCENT_DESCENT -void TFT_eSPI::loadMetrics(void) -{ - uint32_t headerPtr = 24; - uint32_t bitmapPtr = headerPtr + gFont.gCount * 28; - -#if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT) - if ( psramFound() ) - { - gUnicode = (uint16_t*)ps_malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF) - gHeight = (uint8_t*)ps_malloc( gFont.gCount ); // Height of glyph - gWidth = (uint8_t*)ps_malloc( gFont.gCount ); // Width of glyph - gxAdvance = (uint8_t*)ps_malloc( gFont.gCount ); // xAdvance - to move x cursor - gdY = (int16_t*)ps_malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character - gdX = (int8_t*)ps_malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X - gBitmap = (uint32_t*)ps_malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file - } - else -#endif - { - gUnicode = (uint16_t*)malloc( gFont.gCount * 2); // Unicode 16 bit Basic Multilingual Plane (0-FFFF) - gHeight = (uint8_t*)malloc( gFont.gCount ); // Height of glyph - gWidth = (uint8_t*)malloc( gFont.gCount ); // Width of glyph - gxAdvance = (uint8_t*)malloc( gFont.gCount ); // xAdvance - to move x cursor - gdY = (int16_t*)malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character - gdX = (int8_t*)malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X - gBitmap = (uint32_t*)malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file - } - -#ifdef SHOW_ASCENT_DESCENT - Serial.print("ascent = "); Serial.println(gFont.ascent); - Serial.print("descent = "); Serial.println(gFont.descent); -#endif - -#ifdef FONT_FS_AVAILABLE - if (fs_font) fontFile.seek(headerPtr, fs::SeekSet); -#endif - - uint16_t gNum = 0; - - while (gNum < gFont.gCount) - { - gUnicode[gNum] = (uint16_t)readInt32(); // Unicode code point value - gHeight[gNum] = (uint8_t)readInt32(); // Height of glyph - gWidth[gNum] = (uint8_t)readInt32(); // Width of glyph - gxAdvance[gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor - gdY[gNum] = (int16_t)readInt32(); // y delta from baseline - gdX[gNum] = (int8_t)readInt32(); // x delta from cursor - readInt32(); // ignored - - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gHeight = "); Serial.println(gHeight[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gWidth = "); Serial.println(gWidth[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gxAdvance = "); Serial.println(gxAdvance[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gdY = "); Serial.println(gdY[gNum]); - - // Different glyph sets have different ascent values not always based on "d", so we could get - // the maximum glyph ascent by checking all characters. BUT this method can generate bad values - // for non-existant glyphs, so we will reply on processing for the value and disable this code for now... - /* - if (gdY[gNum] > gFont.maxAscent) - { - // Try to avoid UTF coding values and characters that tend to give duff values - if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0x7F)) || (gUnicode[gNum] > 0xA0)) - { - gFont.maxAscent = gdY[gNum]; -#ifdef SHOW_ASCENT_DESCENT - Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxAscent = "); Serial.println(gFont.maxAscent); -#endif - } - } - */ - - // Different glyph sets have different descent values not always based on "p", so get maximum glyph descent - if (((int16_t)gHeight[gNum] - (int16_t)gdY[gNum]) > gFont.maxDescent) - { - // Avoid UTF coding values and characters that tend to give duff values - if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0xA0) && (gUnicode[gNum] != 0x7F)) || (gUnicode[gNum] > 0xFF)) - { - gFont.maxDescent = gHeight[gNum] - gdY[gNum]; -#ifdef SHOW_ASCENT_DESCENT - Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", maxDescent = "); Serial.println(gHeight[gNum] - gdY[gNum]); -#endif - } - } - - gBitmap[gNum] = bitmapPtr; - - bitmapPtr += gWidth[gNum] * gHeight[gNum]; - - gNum++; - yield(); - } - - gFont.yAdvance = gFont.maxAscent + gFont.maxDescent; - - gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width } @@ -250,104 +43,9 @@ void TFT_eSPI::loadMetrics(void) *************************************************************************************x*/ void TFT_eSPI::unloadFont( void ) { - if (gUnicode) - { - free(gUnicode); - gUnicode = NULL; - } - - if (gHeight) - { - free(gHeight); - gHeight = NULL; - } - - if (gWidth) - { - free(gWidth); - gWidth = NULL; - } - - if (gxAdvance) - { - free(gxAdvance); - gxAdvance = NULL; - } - - if (gdY) - { - free(gdY); - gdY = NULL; - } - - if (gdX) - { - free(gdX); - gdX = NULL; - } - - if (gBitmap) - { - free(gBitmap); - gBitmap = NULL; - } - - gFont.gArray = nullptr; - -#ifdef FONT_FS_AVAILABLE - if (fs_font && fontFile) fontFile.close(); -#endif - - fontLoaded = false; + fontLoaded = false; } - -/*************************************************************************************** -** Function name: readInt32 -** Description: Get a 32 bit integer from the font file -*************************************************************************************x*/ -uint32_t TFT_eSPI::readInt32(void) -{ - uint32_t val = 0; - -#ifdef FONT_FS_AVAILABLE - if (fs_font) { - val |= fontFile.read() << 24; - val |= fontFile.read() << 16; - val |= fontFile.read() << 8; - val |= fontFile.read(); - } - else -#endif - { - val |= pgm_read_byte(fontPtr++) << 24; - val |= pgm_read_byte(fontPtr++) << 16; - val |= pgm_read_byte(fontPtr++) << 8; - val |= pgm_read_byte(fontPtr++); - } - - return val; -} - - -/*************************************************************************************** -** Function name: getUnicodeIndex -** Description: Get the font file index of a Unicode character -*************************************************************************************x*/ -bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) -{ - for (uint16_t i = 0; i < gFont.gCount; i++) - { - if (gUnicode[i] == unicode) - { - *index = i; - return true; - } - } - return false; -} - - /*************************************************************************************** ** Function name: drawGlyph ** Description: Write a character to the TFT cursor position @@ -358,20 +56,20 @@ void TFT_eSPI::drawGlyph(uint16_t code) if (code < 0x21) { if (code == 0x20) { - cursor_x += gFont.spaceWidth; + cursor_x += sf->gFont.spaceWidth; return; } if (code == '\n') { cursor_x = 0; - cursor_y += gFont.yAdvance; + cursor_y += sf->gFont.yAdvance; if (cursor_y >= _height) cursor_y = 0; return; } } uint16_t gNum = 0; - bool found = getUnicodeIndex(code, &gNum); + bool found = sf->getUnicodeIndex(code, &gNum); uint16_t fg = textcolor; uint16_t bg = textbgcolor; @@ -379,22 +77,22 @@ void TFT_eSPI::drawGlyph(uint16_t code) if (found) { - if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > _width)) + if (textwrapX && (cursor_x + sf->gWidth[gNum] + sf->gdX[gNum] > _width)) { - cursor_y += gFont.yAdvance; + cursor_y += sf->gFont.yAdvance; cursor_x = 0; } - if (textwrapY && ((cursor_y + gFont.yAdvance) >= _height)) cursor_y = 0; - if (cursor_x == 0) cursor_x -= gdX[gNum]; + if (textwrapY && ((cursor_y + sf->gFont.yAdvance) >= _height)) cursor_y = 0; + if (cursor_x == 0) cursor_x -= sf->gdX[gNum]; uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) gFont.gArray; + const uint8_t* gPtr = (const uint8_t*) sf->gFont.gArray; #ifdef FONT_FS_AVAILABLE - if (fs_font) + if (sf->fs_font) { - fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is taking >30ms for a significant position shift - pbuffer = (uint8_t*)malloc(gWidth[gNum]); + sf->fontFile.seek(sf->gBitmap[gNum], fs::SeekSet); // This is taking >30ms for a significant position shift + pbuffer = (uint8_t*)malloc(sf->gWidth[gNum]); } #endif @@ -402,36 +100,36 @@ void TFT_eSPI::drawGlyph(uint16_t code) uint32_t dl = 0; uint8_t pixel; - int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; - int16_t cx = cursor_x + gdX[gNum]; + int16_t cy = cursor_y + sf->gFont.maxAscent - sf->gdY[gNum]; + int16_t cx = cursor_x + sf->gdX[gNum]; startWrite(); // Avoid slow ESP32 transaction overhead for every pixel - for (int y = 0; y < gHeight[gNum]; y++) + for (int y = 0; y < sf->gHeight[gNum]; y++) { #ifdef FONT_FS_AVAILABLE - if (fs_font) { - if (spiffs) + if (sf->fs_font) { + if (sf->spiffs) { - fontFile.read(pbuffer, gWidth[gNum]); + sf->fontFile.read(pbuffer, sf->gWidth[gNum]); //Serial.println("SPIFFS"); } else { endWrite(); // Release SPI for SD card transaction - fontFile.read(pbuffer, gWidth[gNum]); + sf->fontFile.read(pbuffer,sf-> gWidth[gNum]); startWrite(); // Re-start SPI for TFT transaction //Serial.println("Not SPIFFS"); } } #endif - for (int x = 0; x < gWidth[gNum]; x++) + for (int x = 0; x < sf->gWidth[gNum]; x++) { #ifdef FONT_FS_AVAILABLE - if (fs_font) pixel = pbuffer[x]; + if (sf->fs_font) pixel = pbuffer[x]; else #endif - pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); + pixel = pgm_read_byte(gPtr + sf->gBitmap[gNum] + x + sf->gWidth[gNum] * y); if (pixel) { @@ -460,14 +158,14 @@ void TFT_eSPI::drawGlyph(uint16_t code) } if (pbuffer) free(pbuffer); - cursor_x += gxAdvance[gNum]; + cursor_x += sf->gxAdvance[gNum]; endWrite(); } else { // Not a Unicode in font so draw a rectangle and move on cursor - drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg); - cursor_x += gFont.spaceWidth + 1; + drawRect(cursor_x, cursor_y + sf->gFont.maxAscent - sf->gFont.ascent, sf->gFont.spaceWidth, sf->gFont.ascent, fg); + cursor_x += sf->gFont.spaceWidth + 1; } } @@ -477,7 +175,7 @@ void TFT_eSPI::drawGlyph(uint16_t code) *************************************************************************************x*/ void TFT_eSPI::showFont(uint32_t td) { - if(!fontLoaded) return; + if( !fontLoaded || sf == nullptr) return; int16_t cursorX = width(); // Force start of new page to initialise cursor int16_t cursorY = height();// for the first character @@ -485,15 +183,15 @@ void TFT_eSPI::showFont(uint32_t td) fillScreen(textbgcolor); - for (uint16_t i = 0; i < gFont.gCount; i++) + for (uint16_t i = 0; i < sf->gFont.gCount; i++) { // Check if this will need a new screen - if (cursorX + gdX[i] + gWidth[i] >= width()) { - cursorX = -gdX[i]; + if (cursorX + sf->gdX[i] + sf->gWidth[i] >= width()) { + cursorX = -sf->gdX[i]; - cursorY += gFont.yAdvance; - if (cursorY + gFont.maxAscent + gFont.descent >= height()) { - cursorX = -gdX[i]; + cursorY += sf->gFont.yAdvance; + if (cursorY + sf->gFont.maxAscent + sf->gFont.descent >= height()) { + cursorX = -sf->gdX[i]; cursorY = 0; delay(timeDelay); timeDelay = td; @@ -502,8 +200,8 @@ void TFT_eSPI::showFont(uint32_t td) } setCursor(cursorX, cursorY); - drawGlyph(gUnicode[i]); - cursorX += gxAdvance[i]; + drawGlyph(sf->gUnicode[i]); + cursorX += sf->gxAdvance[i]; //cursorX += printToSprite( cursorX, cursorY, i ); yield(); } @@ -511,5 +209,4 @@ void TFT_eSPI::showFont(uint32_t td) delay(timeDelay); fillScreen(textbgcolor); //fontFile.close(); - } diff --git a/Extensions/Smooth_font.h b/Extensions/Smooth_font.h index ee2a77b..edba15b 100644 --- a/Extensions/Smooth_font.h +++ b/Extensions/Smooth_font.h @@ -1,61 +1,24 @@ // Coded by Bodmer 10/2/18, see license in root directory. - // This is part of the TFT_eSPI class and is associated with anti-aliased font functions + // This is part of the TFT_eSPI class and is associated with anti-aliased font function +protected: + TFT_eSPI_SmoothFont * sf = nullptr; + bool fontLoaded = false; // Flags when a anti-aliased font is loaded public: - // These are for the new antialiased fonts void loadFont(const uint8_t array[]); #ifdef FONT_FS_AVAILABLE void loadFont(String fontName, fs::FS &ffs); #endif void loadFont(String fontName, bool flash = true); + + void setFont( TFT_eSPI_SmoothFont * font) { sf = font; fontLoaded = true;}; void unloadFont( void ); - bool getUnicodeIndex(uint16_t unicode, uint16_t *index); virtual void drawGlyph(uint16_t code); void showFont(uint32_t td); - // This is for the whole font - typedef struct - { - const uint8_t* gArray; //array start pointer - uint16_t gCount; // Total number of characters - uint16_t yAdvance; // Line advance - uint16_t spaceWidth; // Width of a space character - int16_t ascent; // Height of top of 'd' above baseline, other characters may be taller - int16_t descent; // Offset to bottom of 'p', other characters may have a larger descent - uint16_t maxAscent; // Maximum ascent found in font - uint16_t maxDescent; // Maximum descent found in font - } fontMetrics; -fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; - // These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time) - uint16_t* gUnicode = NULL; //UTF-16 code, the codes are searched so do not need to be sequential - uint8_t* gHeight = NULL; //cheight - uint8_t* gWidth = NULL; //cwidth - uint8_t* gxAdvance = NULL; //setWidth - int16_t* gdY = NULL; //topExtent - int8_t* gdX = NULL; //leftExtent - uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap - - bool fontLoaded = false; // Flags when a anti-aliased font is loaded - -#ifdef FONT_FS_AVAILABLE - fs::File fontFile; - fs::FS &fontFS = SPIFFS; - bool spiffs = true; - bool fs_font = false; // For ESP32/8266 use smooth font file or FLASH (PROGMEM) array - -#else - bool fontFile = true; -#endif - - private: - - void loadMetrics(void); - uint32_t readInt32(void); - - uint8_t* fontPtr = nullptr; diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 6b276e3..483c967 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -14,7 +14,7 @@ ** Function name: TFT_eSprite ** Description: Class constructor *************************************************************************************x*/ -TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) +TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) : TFT_eSPI() { _tft = tft; // Pointer to tft class so we can call member functions @@ -104,7 +104,6 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) *************************************************************************************x*/ TFT_eSprite::~TFT_eSprite(void) { - unloadFont(); deleteSprite(); } @@ -2198,8 +2197,8 @@ void TFT_eSprite::drawGlyph(uint16_t code) if (code < 0x21) { if (code == 0x20) { - if (_created) this->cursor_x += this->gFont.spaceWidth; - else this->cursor_x += this->gFont.spaceWidth; + if (_created) this->cursor_x += sf->gFont.spaceWidth; + else this->cursor_x += sf->gFont.spaceWidth; return; } @@ -2207,14 +2206,14 @@ void TFT_eSprite::drawGlyph(uint16_t code) if (_created) { this->cursor_x = 0; - this->cursor_y += this->gFont.yAdvance; + this->cursor_y += sf->gFont.yAdvance; if (this->cursor_y >= _height) this->cursor_y = 0; return; } else { cursor_x = 0; - cursor_y += gFont.yAdvance; + cursor_y += sf->gFont.yAdvance; if (cursor_y >= _height) cursor_y = 0; return; } @@ -2222,7 +2221,7 @@ void TFT_eSprite::drawGlyph(uint16_t code) } uint16_t gNum = 0; - bool found = this->getUnicodeIndex(code, &gNum); + bool found = sf->getUnicodeIndex(code, &gNum); uint16_t fg = this->textcolor; uint16_t bg = this->textbgcolor; @@ -2234,31 +2233,31 @@ void TFT_eSprite::drawGlyph(uint16_t code) if (newSprite) { - createSprite(this->gWidth[gNum], this->gFont.yAdvance); + createSprite(sf->gWidth[gNum], sf->gFont.yAdvance); if(bg) fillSprite(bg); - this->cursor_x = -this->gdX[gNum]; + this->cursor_x = -sf->gdX[gNum]; this->cursor_y = 0; } else { - if( this->textwrapX && ((this->cursor_x + this->gWidth[gNum] + this->gdX[gNum]) > _iwidth)) { - this->cursor_y += this->gFont.yAdvance; + if( this->textwrapX && ((this->cursor_x + sf->gWidth[gNum] + sf->gdX[gNum]) > _iwidth)) { + this->cursor_y += sf->gFont.yAdvance; this->cursor_x = 0; } - if( this->textwrapY && ((this->cursor_y + this->gFont.yAdvance) > _iheight)) this->cursor_y = 0; + if( this->textwrapY && ((this->cursor_y + sf->gFont.yAdvance) > _iheight)) this->cursor_y = 0; - if ( this->cursor_x == 0) this->cursor_x -= this->gdX[gNum]; + if ( this->cursor_x == 0) this->cursor_x -= sf->gdX[gNum]; } uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) this->gFont.gArray; + const uint8_t* gPtr = (const uint8_t*) sf->gFont.gArray; #ifdef FONT_FS_AVAILABLE - if (this->fs_font) { - this->fontFile.seek(this->gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift! - pbuffer = (uint8_t*)malloc(this->gWidth[gNum]); + if (sf->fs_font) { + sf->fontFile.seek(sf->gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift! + pbuffer = (uint8_t*)malloc(sf->gWidth[gNum]); } #endif @@ -2266,60 +2265,60 @@ void TFT_eSprite::drawGlyph(uint16_t code) uint16_t dl = 0; uint8_t pixel = 0; - for (int32_t y = 0; y < this->gHeight[gNum]; y++) + for (int32_t y = 0; y < sf->gHeight[gNum]; y++) { #ifdef FONT_FS_AVAILABLE - if (this->fs_font) { - this->fontFile.read(pbuffer, this->gWidth[gNum]); + if (sf->fs_font) { + sf->fontFile.read(pbuffer, sf->gWidth[gNum]); } #endif - for (int32_t x = 0; x < this->gWidth[gNum]; x++) + for (int32_t x = 0; x < sf->gWidth[gNum]; x++) { #ifdef FONT_FS_AVAILABLE - if (this->fs_font) { + if (sf->fs_font) { pixel = pbuffer[x]; } else #endif - pixel = pgm_read_byte(gPtr + this->gBitmap[gNum] + x + this->gWidth[gNum] * y); + pixel = pgm_read_byte(gPtr + sf->gBitmap[gNum] + x + sf->gWidth[gNum] * y); if (pixel) { if (pixel != 0xFF) { - if (dl) { drawFastHLine( xs, y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], dl, fg); dl = 0; } - if (_bpp != 1) drawPixel(x + this->cursor_x + this->gdX[gNum], y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], alphaBlend(pixel, fg, bg)); - else if (pixel>127) drawPixel(x + this->cursor_x + this->gdX[gNum], y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], fg); + if (dl) { drawFastHLine( xs, y + this->cursor_y + sf->gFont.maxAscent - sf->gdY[gNum], dl, fg); dl = 0; } + if (_bpp != 1) drawPixel(x + this->cursor_x + sf->gdX[gNum], y + this->cursor_y + sf->gFont.maxAscent - sf->gdY[gNum], alphaBlend(pixel, fg, bg)); + else if (pixel>127) drawPixel(x + this->cursor_x + sf->gdX[gNum], y + this->cursor_y + sf->gFont.maxAscent - sf->gdY[gNum], fg); } else { - if (dl==0) xs = x + this->cursor_x + this->gdX[gNum]; + if (dl==0) xs = x + this->cursor_x + sf->gdX[gNum]; dl++; } } else { - if (dl) { drawFastHLine( xs, y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], dl, fg); dl = 0; } + if (dl) { drawFastHLine( xs, y + this->cursor_y + sf->gFont.maxAscent - sf->gdY[gNum], dl, fg); dl = 0; } } } - if (dl) { drawFastHLine( xs, y + this->cursor_y + this->gFont.maxAscent - this->gdY[gNum], dl, fg); dl = 0; } + if (dl) { drawFastHLine( xs, y + this->cursor_y + sf->gFont.maxAscent - sf->gdY[gNum], dl, fg); dl = 0; } } if (pbuffer) free(pbuffer); if (newSprite) { - pushSprite(this->cursor_x + this->gdX[gNum], this->cursor_y, bg); + pushSprite(this->cursor_x + sf->gdX[gNum], this->cursor_y, bg); deleteSprite(); - this->cursor_x += this->gxAdvance[gNum]; + this->cursor_x += sf->gxAdvance[gNum]; } - else this->cursor_x += this->gxAdvance[gNum]; + else this->cursor_x += sf->gxAdvance[gNum]; } else { // Not a Unicode in font so draw a rectangle and move on cursor - drawRect(this->cursor_x, this->cursor_y + this->gFont.maxAscent - this->gFont.ascent, this->gFont.spaceWidth, this->gFont.ascent, fg); - this->cursor_x += this->gFont.spaceWidth + 1; + drawRect(this->cursor_x, this->cursor_y + sf->gFont.maxAscent - sf->gFont.ascent, sf->gFont.spaceWidth, sf->gFont.ascent, fg); + this->cursor_x += sf->gFont.spaceWidth + 1; } } @@ -2358,16 +2357,16 @@ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) while (n < len) { uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n); - if (this->getUnicodeIndex(unicode, &index)) + if (sf->getUnicodeIndex(unicode, &index)) { - if (n == 0) sWidth -= this->gdX[index]; - if (n == len-1) sWidth += ( this->gWidth[index] + this->gdX[index]); - else sWidth += this->gxAdvance[index]; + if (n == 0) sWidth -= sf->gdX[index]; + if (n == len-1) sWidth += ( sf->gWidth[index] + sf->gdX[index]); + else sWidth += sf->gxAdvance[index]; } - else sWidth += this->gFont.spaceWidth + 1; + else sWidth += sf->gFont.spaceWidth + 1; } - createSprite(sWidth, this->gFont.yAdvance); + createSprite(sWidth, sf->gFont.yAdvance); if (this->textbgcolor != TFT_BLACK) fillSprite(this->textbgcolor); } @@ -2397,22 +2396,22 @@ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index) { bool newSprite = !_created; - int16_t sWidth = this->gWidth[index]; + int16_t sWidth = sf->gWidth[index]; if (newSprite) { - createSprite(sWidth, this->gFont.yAdvance); + createSprite(sWidth, sf->gFont.yAdvance); if (this->textbgcolor != TFT_BLACK) fillSprite(this->textbgcolor); - drawGlyph(this->gUnicode[index]); + drawGlyph(sf->gUnicode[index]); - pushSprite(x + this->gdX[index], y, this->textbgcolor); + pushSprite(x + sf->gdX[index], y, this->textbgcolor); deleteSprite(); } - else drawGlyph(this->gUnicode[index]); + else drawGlyph(sf->gUnicode[index]); - return this->gxAdvance[index]; + return sf->gxAdvance[index]; } #endif diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 74ba6b2..14df43b 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -9,7 +9,7 @@ class TFT_eSprite : public TFT_eSPI { public: - TFT_eSprite(TFT_eSPI *tft); + TFT_eSprite(TFT_eSPI *tft) ; // Create a sprite of width x height pixels, return a pointer to the RAM area // Sketch can cast returned value to (uint16_t*) for 16 bit depth if needed diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 27a7e1b..b291a64 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -26,7 +26,9 @@ #include "Processors/TFT_eSPI_Generic.c" #endif - +#ifdef SMOOTH_FONT + #include "Extensions/SmoothFont.cpp" +#endif /*************************************************************************************** ** Function name: begin_tft_write (was called spi_begin) ** Description: Start SPI transaction for writes and select TFT @@ -198,9 +200,6 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) _cp437 = true; _utf8 = true; -#ifdef FONT_FS_AVAILABLE - fs_font = true; // Smooth font filing system or array (fs_font = false) flag -#endif #if defined (ESP32) && defined (CONFIG_SPIRAM_SUPPORT) if (psramFound()) _psram_enable = true; // Enable the use of PSRAM (if available) @@ -2358,16 +2357,16 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) while (*string) { uniCode = decodeUTF8(*string++); if (uniCode) { - if (uniCode == 0x20) str_width += gFont.spaceWidth; + if (uniCode == 0x20) str_width += sf->gFont.spaceWidth; else { uint16_t gNum = 0; - bool found = getUnicodeIndex(uniCode, &gNum); + bool found = sf->getUnicodeIndex(uniCode, &gNum); if (found) { - if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum]; - if (*string || isDigits) str_width += gxAdvance[gNum]; - else str_width += (gdX[gNum] + gWidth[gNum]); + if(str_width == 0 && sf->gdX[gNum] < 0) str_width -= sf->gdX[gNum]; + if (*string || isDigits) str_width += sf->gxAdvance[gNum]; + else str_width += (sf->gdX[gNum] + sf->gWidth[gNum]); } - else str_width += gFont.spaceWidth + 1; + else str_width += sf->gFont.spaceWidth + 1; } } } @@ -2435,7 +2434,7 @@ uint16_t TFT_eSPI::fontsLoaded(void) int16_t TFT_eSPI::fontHeight(int16_t font) { #ifdef SMOOTH_FONT - if(fontLoaded) return gFont.yAdvance; + if(fontLoaded) return sf->gFont.yAdvance; #endif #ifdef LOAD_GFXFF @@ -3668,7 +3667,7 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 // If it is not font 1 (GLCD or free font) get the baseline and pixel height of the font #ifdef SMOOTH_FONT if(fontLoaded) { - baseline = gFont.maxAscent; + baseline = sf->gFont.maxAscent; cheight = fontHeight(); } else diff --git a/TFT_eSPI.h b/TFT_eSPI.h index ced9448..7d69ed6 100644 --- a/TFT_eSPI.h +++ b/TFT_eSPI.h @@ -144,6 +144,11 @@ #include #endif // #ifdef LOAD_GFXFF +// Load the Anti-aliased font extension +#ifdef SMOOTH_FONT + #include "Extensions/SmoothFont.h" // Loaded if SMOOTH_FONT is defined by user +#endif + // Create a null default font in case some fonts not used (to prevent crash) const uint8_t widtbl_null[1] = {0}; PROGMEM const uint8_t chr_null[1] = {0};