Move Smooth Font to new class
This commit is contained in:
parent
870207dcfa
commit
09c2d137a3
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** 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();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
23
TFT_eSPI.cpp
23
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
|
||||
|
|
|
|||
|
|
@ -144,6 +144,11 @@
|
|||
#include <User_Setups/User_Custom_Fonts.h>
|
||||
#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};
|
||||
|
|
|
|||
Loading…
Reference in New Issue