From 44d8aa10738091d6d5ed9ddc3fac4eeef759d65c Mon Sep 17 00:00:00 2001 From: "en.ot" Date: Sun, 8 Aug 2021 21:44:12 +0300 Subject: [PATCH] Font partition supported. No time and ram is used for load smooth font. --- Extensions/Smooth_font.cpp | 323 ++++++++---------- Extensions/Smooth_font.h | 31 +- Extensions/Sprite.cpp | 90 +++-- Extensions/Sprite.h | 4 +- TFT_eSPI.cpp | 7 +- .../Font partition/conv_vlw_to_prt.py | 42 +++ .../Font partition/custom_16MB.csv | 7 + .../Font partition/upload_prt.bat | 1 + 8 files changed, 276 insertions(+), 229 deletions(-) create mode 100644 Tools/Create_Smooth_Font/Font partition/conv_vlw_to_prt.py create mode 100644 Tools/Create_Smooth_Font/Font partition/custom_16MB.csv create mode 100644 Tools/Create_Smooth_Font/Font partition/upload_prt.bat diff --git a/Extensions/Smooth_font.cpp b/Extensions/Smooth_font.cpp index ed66033..bb4833a 100644 --- a/Extensions/Smooth_font.cpp +++ b/Extensions/Smooth_font.cpp @@ -6,6 +6,11 @@ // New anti-aliased (smoothed) font functions added below //////////////////////////////////////////////////////////////////////////////////////// +//syntax highlight enable +#ifndef TFT_ESPI_VERSION +#include "TFT_eSPI.h" +#endif + /*************************************************************************************** ** Function name: loadFont ** Description: loads parameters from a font vlw array in memory @@ -17,6 +22,30 @@ void TFT_eSPI::loadFont(const uint8_t array[]) loadFont("", false); } + +void TFT_eSPI::loadFont(const char * partitionName, esp_partition_subtype_t subtype) +{ + const esp_partition_t* fontpart = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, subtype, partitionName); + if (!fontpart) + { + Serial.print("Font partition not found: "); + Serial.println(partitionName); + return; + } + + esp_err_t err = spi_flash_mmap(fontpart->address, fontpart->size, SPI_FLASH_MMAP_INST, (const void **)&fontPtr, &font_handle); +// esp_err_t err = spi_flash_mmap(fontpart->address, 4*1024*1024, SPI_FLASH_MMAP_INST, (const void **)&fontPtr, &font_handle); + if (err) + { + Serial.print("Partition mapping error "); + Serial.println(err); + return; + } + + loadFont("", false); +} + + #ifdef FONT_FS_AVAILABLE /*************************************************************************************** ** Function name: loadFont @@ -29,6 +58,7 @@ void TFT_eSPI::loadFont(String fontName, fs::FS &ffs) } #endif + /*************************************************************************************** ** Function name: loadFont ** Description: loads parameters from a font vlw file @@ -128,123 +158,39 @@ void TFT_eSPI::loadFont(String fontName, bool flash) 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.maxDescent = (int32_t)readInt32(); 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 + + yield(); + + gFont.yAdvance = gFont.maxAscent + gFont.maxDescent; + gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // 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::loadMetrics(void) +static TFT_eSPI::CharMetrics _cm; + +TFT_eSPI::CharMetrics * TFT_eSPI::getCharMetrics(uint16_t gNum) { - uint32_t headerPtr = 24; - uint32_t bitmapPtr = headerPtr + gFont.gCount * 28; + CharMetrics * cm = &_cm; -#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 - } + fontPtr = (uint8_t *)&gFont.gArray[24 + gNum * 28]; + cm->gUnicode = (uint16_t)readInt32(); // Unicode code point value + cm->gHeight = (uint8_t)readInt32(); // Height of glyph + cm->gWidth = (uint8_t)readInt32(); // Width of glyph + cm->gxAdvance = (uint8_t)readInt32(); // xAdvance - to move x cursor + cm->gdY = (int16_t)readInt32(); // y delta from baseline + cm->gdX = (int8_t)readInt32(); // x delta from cursor + cm->gBitmap = 24 + gFont.gCount*28 + readInt32(); -#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 + return cm; } @@ -254,54 +200,18 @@ 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 + if (font_handle) + { + spi_flash_munmap(font_handle); + font_handle = 0; + } + fontLoaded = false; } @@ -312,24 +222,24 @@ void TFT_eSPI::unloadFont( void ) *************************************************************************************x*/ uint32_t TFT_eSPI::readInt32(void) { - uint32_t val = 0; + uint32_t val; #ifdef FONT_FS_AVAILABLE - if (fs_font) { - val |= fontFile.read() << 24; - val |= fontFile.read() << 16; - val |= fontFile.read() << 8; + if (fs_font) + { + fontFile.seek((uint32_t)fontPtr, fs::SeekSet); val |= fontFile.read(); + val |= fontFile.read() << 8; + val |= fontFile.read() << 16; + val |= fontFile.read() << 24; } 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++); + val = pgm_read_dword(fontPtr) & 0xFFFFFFFFul; } + fontPtr += 4; return val; } @@ -347,7 +257,8 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) int i = above / 2; do { - uint16_t code = gUnicode[i]; + fontPtr = (uint8_t *)&gFont.gArray[24 + i * 28]; + uint32_t code = readInt32(); // Unicode code point value. 32bit to prevent compiler optimisation leading to unaligned access (16 bit) if (code == unicode) { *index = i; @@ -384,6 +295,56 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) #endif +//-------------------------------------------------------------------------------------- +void * memcpy_I(void * dst, const void * src, int len) +{ +// return memcpy(dst, src, len); + + if (!len) return dst; + + uint32_t d; + uint32_t dst1 = (uint32_t)dst; + uint32_t src1 = (uint32_t)src; + + if (src1 & 3) + { + d = *(uint32_t*)(src1 & ~3); + d >>= 8 * (src1 & 3); + while (src1 & 3) + { + *(uint8_t *)dst1 = d & 0xFF; + d >>= 8; + src1++; + dst1++; + len--; + if (!len) return dst; + } + } + + while (len > 3) + { + d = *(uint32_t *)src1; + *(uint32_t *)dst1 = d; + src1 += 4; + dst1 += 4; + len -= 4; + } + + if (!len) return dst; + + d = *(uint32_t *)src1; + while (len) + { + *(uint8_t *)dst1 = d & 0xFF; + d >>= 8; + src1++; + dst1++; + len--; + } + + return dst; +} + /*************************************************************************************** ** Function name: drawGlyph @@ -416,28 +377,27 @@ void TFT_eSPI::drawGlyph(uint16_t code) if (found) { - - if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width())) + CharMetrics * cm = getCharMetrics(gNum); + if (textwrapX && (cursor_x + cm->gWidth + cm->gdX > width())) { cursor_y += gFont.yAdvance; cursor_x = 0; } if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0; - if (cursor_x == 0) cursor_x -= gdX[gNum]; + if (cursor_x == 0) cursor_x -= cm->gdX; - uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) gFont.gArray; + uint8_t* pbuffer = glyph_line_buffer;//(uint8_t*)malloc(cm->gWidth); + const uint8_t* gPtr = (const uint8_t*) gFont.gArray + cm->gBitmap; #ifdef FONT_FS_AVAILABLE if (fs_font) { - fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is taking >30ms for a significant position shift - pbuffer = (uint8_t*)malloc(gWidth[gNum]); + fontFile.seek(cm->gBitmap, fs::SeekSet); // This is taking >30ms for a significant position shift } #endif - int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; - int16_t cx = cursor_x + gdX[gNum]; + int16_t cy = cursor_y + gFont.maxAscent - cm->gdY; + int16_t cx = cursor_x + cm->gdX; int16_t xs = cx; uint32_t dl = 0; @@ -447,31 +407,33 @@ void TFT_eSPI::drawGlyph(uint16_t code) //if (fg!=bg) fillRect(cursor_x, cursor_y, gxAdvance[gNum], gFont.yAdvance, bg); - for (int y = 0; y < gHeight[gNum]; y++) + for (int y = 0; y < cm->gHeight; y++) { #ifdef FONT_FS_AVAILABLE if (fs_font) { if (spiffs) { - fontFile.read(pbuffer, gWidth[gNum]); + fontFile.read(pbuffer, cm->gWidth); //Serial.println("SPIFFS"); } else { endWrite(); // Release SPI for SD card transaction - fontFile.read(pbuffer, gWidth[gNum]); + fontFile.read(pbuffer, cm->gWidth); startWrite(); // Re-start SPI for TFT transaction //Serial.println("Not SPIFFS"); } } + else #endif - for (int x = 0; x < gWidth[gNum]; x++) { -#ifdef FONT_FS_AVAILABLE - if (fs_font) pixel = pbuffer[x]; - else -#endif - pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); + memcpy_I(pbuffer, gPtr, cm->gWidth); + gPtr += cm->gWidth; + } + + for (int x = 0; x < cm->gWidth; x++) + { + pixel = pbuffer[x]; if (pixel) { @@ -499,8 +461,8 @@ void TFT_eSPI::drawGlyph(uint16_t code) if (dl) { drawFastHLine( xs, y + cy, dl, fg); dl = 0; } } - if (pbuffer) free(pbuffer); - cursor_x += gxAdvance[gNum]; + //if (pbuffer) free(pbuffer); + cursor_x += cm->gxAdvance; endWrite(); } else @@ -528,12 +490,13 @@ void TFT_eSPI::showFont(uint32_t td) for (uint16_t i = 0; i < gFont.gCount; i++) { // Check if this will need a new screen - if (cursorX + gdX[i] + gWidth[i] >= width()) { - cursorX = -gdX[i]; + CharMetrics * cm = getCharMetrics(i); + if (cursorX + cm->gdX + cm->gWidth >= width()) { + cursorX = -cm->gdX; cursorY += gFont.yAdvance; if (cursorY + gFont.maxAscent + gFont.descent >= height()) { - cursorX = -gdX[i]; + cursorX = -cm->gdX; cursorY = 0; delay(timeDelay); timeDelay = td; @@ -542,8 +505,8 @@ void TFT_eSPI::showFont(uint32_t td) } setCursor(cursorX, cursorY); - drawGlyph(gUnicode[i]); - cursorX += gxAdvance[i]; + drawGlyph(cm->gUnicode); + cursorX += cm->gxAdvance; //cursorX += printToSprite( cursorX, cursorY, i ); yield(); } diff --git a/Extensions/Smooth_font.h b/Extensions/Smooth_font.h index ee2a77b..2f306cf 100644 --- a/Extensions/Smooth_font.h +++ b/Extensions/Smooth_font.h @@ -9,6 +9,8 @@ void loadFont(String fontName, fs::FS &ffs); #endif void loadFont(String fontName, bool flash = true); + void loadFont(const char * partitionName, esp_partition_subtype_t subtype); + void unloadFont( void ); bool getUnicodeIndex(uint16_t unicode, uint16_t *index); @@ -29,19 +31,31 @@ uint16_t maxDescent; // Maximum descent found in font } fontMetrics; -fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; + fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; + +#define MAX_GLYPH_WIDTH 30 + uint8_t glyph_line_buffer[MAX_GLYPH_WIDTH]; // 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 + typedef struct + { + uint16_t gUnicode; //UTF-16 code, the codes are searched so do not need to be sequential + uint8_t gHeight; //cheight + uint8_t gWidth; //cwidth + uint8_t gxAdvance; //setWidth + int16_t gdY; //topExtent + int8_t gdX; //leftExtent + uint32_t gBitmap; //bitmap offset + } CharMetrics; + + TFT_eSPI::CharMetrics * getCharMetrics(uint16_t gNum); + +// uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap bool fontLoaded = false; // Flags when a anti-aliased font is loaded + spi_flash_mmap_handle_t font_handle; + #ifdef FONT_FS_AVAILABLE fs::File fontFile; fs::FS &fontFS = SPIFFS; @@ -54,7 +68,6 @@ fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; private: - void loadMetrics(void); uint32_t readInt32(void); uint8_t* fontPtr = nullptr; diff --git a/Extensions/Sprite.cpp b/Extensions/Sprite.cpp index 0a05675..92c1645 100644 --- a/Extensions/Sprite.cpp +++ b/Extensions/Sprite.cpp @@ -10,6 +10,11 @@ // there is a nett performance gain by using swapped bytes. ***************************************************************************************/ +//syntax highlight enable +#ifndef TFT_ESPI_VERSION +#include "TFT_eSPI.h" +#endif + /*************************************************************************************** ** Function name: TFT_eSprite ** Description: Class constructor @@ -45,7 +50,7 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) ** Description: Create a sprite (bitmap) of defined width and height ***************************************************************************************/ // cast returned value to (uint8_t*) for 8 bit or (uint16_t*) for 16 bit colours -void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) +void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames, uint8_t * mem) { if ( _created ) return _img8_1; @@ -65,7 +70,16 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) _sh = h; _scolor = TFT_BLACK; - _img8 = (uint8_t*) callocSprite(w, h, frames); + if (!mem) + { + _img8 = (uint8_t*) callocSprite(w, h, frames); +Serial.println("error: alloc!!!!"); + } + else + { + //memset(mem, 0, w*h*sizeof(uint8_t)/_bpp*8); + _img8 = mem; + } _img8_1 = _img8; _img8_2 = _img8; _img = (uint16_t*) _img8; @@ -372,17 +386,18 @@ uint16_t TFT_eSprite::getPaletteColor(uint8_t index) ** Function name: deleteSprite ** Description: Delete the sprite to free up memory (RAM) ***************************************************************************************/ -void TFT_eSprite::deleteSprite(void) +void TFT_eSprite::deleteSprite(bool keep) { if (_colorMap != nullptr) { free(_colorMap); - _colorMap = nullptr; + _colorMap = nullptr; } if (_created) { - free(_img8_1); + if (!keep) + free(_img8_1); _img8 = nullptr; _created = false; _vpOoB = true; // TFT_eSPI class write() uses this to check for valid sprite @@ -2380,6 +2395,8 @@ int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t fo #ifdef SMOOTH_FONT +void * memcpy_I(void * dst, const void * src, int len); + /*************************************************************************************** ** Function name: drawGlyph ** Description: Write a character to the sprite cursor position @@ -2410,60 +2427,60 @@ void TFT_eSprite::drawGlyph(uint16_t code) if (found) { + CharMetrics * cm = getCharMetrics(gNum); bool newSprite = !_created; if (newSprite) { - createSprite(gWidth[gNum], gFont.yAdvance); + createSprite(cm->gWidth, gFont.yAdvance); if(fg != bg) fillSprite(bg); - cursor_x = -gdX[gNum]; + cursor_x = -cm->gdX; cursor_y = 0; } else { - if( textwrapX && ((cursor_x + gWidth[gNum] + gdX[gNum]) > width())) { + if( textwrapX && ((cursor_x + cm->gWidth + cm->gdX) > width())) { cursor_y += gFont.yAdvance; cursor_x = 0; } if( textwrapY && ((cursor_y + gFont.yAdvance) > height())) cursor_y = 0; - if ( cursor_x == 0) cursor_x -= gdX[gNum]; + if ( cursor_x == 0) cursor_x -= cm->gdX; } - uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) gFont.gArray; + uint8_t* pbuffer = glyph_line_buffer;//(uint8_t*)malloc(cm->gWidth); + const uint8_t* gPtr = (const uint8_t*) gFont.gArray + cm->gBitmap; #ifdef FONT_FS_AVAILABLE if (fs_font) { - fontFile.seek(gBitmap[gNum], fs::SeekSet); // This is slow for a significant position shift! - pbuffer = (uint8_t*)malloc(gWidth[gNum]); + fontFile.seek(cm->gBitmap, fs::SeekSet); // This is slow for a significant position shift! } #endif int16_t xs = 0; uint16_t dl = 0; uint8_t pixel = 0; - int32_t cgy = cursor_y + gFont.maxAscent - gdY[gNum]; - int32_t cgx = cursor_x + gdX[gNum]; + int32_t cgy = cursor_y + gFont.maxAscent - cm->gdY; + int32_t cgx = cursor_x + cm->gdX; - for (int32_t y = 0; y < gHeight[gNum]; y++) + for (int32_t y = 0; y < cm->gHeight; y++) { #ifdef FONT_FS_AVAILABLE if (fs_font) { - fontFile.read(pbuffer, gWidth[gNum]); + fontFile.read(pbuffer, cm->gWidth); } + else #endif - for (int32_t x = 0; x < gWidth[gNum]; x++) { -#ifdef FONT_FS_AVAILABLE - if (fs_font) { - pixel = pbuffer[x]; - } - else -#endif - pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); + memcpy_I(pbuffer, gPtr, cm->gWidth); + gPtr += cm->gWidth; + } + + for (int32_t x = 0; x < cm->gWidth; x++) + { + pixel = pbuffer[x]; if (pixel) { @@ -2490,14 +2507,14 @@ void TFT_eSprite::drawGlyph(uint16_t code) if (dl) { drawFastHLine( xs, y + cgy, dl, fg); dl = 0; } } - if (pbuffer) free(pbuffer); + //if (pbuffer) free(pbuffer); if (newSprite) { pushSprite(cgx, cursor_y); deleteSprite(); } - cursor_x += gxAdvance[gNum]; + cursor_x += cm->gxAdvance; } else { @@ -2540,9 +2557,10 @@ void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n); if (getUnicodeIndex(unicode, &index)) { - if (n == 0) sWidth -= gdX[index]; - if (n == len-1) sWidth += ( gWidth[index] + gdX[index]); - else sWidth += gxAdvance[index]; + CharMetrics * cm = getCharMetrics(index); + if (n == 0) sWidth -= cm->gdX; + if (n == len-1) sWidth += ( cm->gWidth + cm->gdX); + else sWidth += cm->gxAdvance; } else sWidth += gFont.spaceWidth + 1; } @@ -2577,7 +2595,8 @@ 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 = gWidth[index]; + CharMetrics * cm = getCharMetrics(index); + int16_t sWidth = cm->gWidth; if (newSprite) { @@ -2585,14 +2604,15 @@ int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index) if (textcolor != textbgcolor) fillSprite(textbgcolor); - drawGlyph(gUnicode[index]); + //todo:drawGlyphIndex + drawGlyph(cm->gUnicode); - pushSprite(x + gdX[index], y, textbgcolor); + pushSprite(x + cm->gdX, y, textbgcolor); deleteSprite(); } - else drawGlyph(gUnicode[index]); + else drawGlyph(cm->gUnicode); - return gxAdvance[index]; + return cm->gxAdvance; } #endif diff --git a/Extensions/Sprite.h b/Extensions/Sprite.h index 951099b..2694ede 100644 --- a/Extensions/Sprite.h +++ b/Extensions/Sprite.h @@ -19,7 +19,7 @@ class TFT_eSprite : public TFT_eSPI { // - 1 nibble per pixel for 4 bit colour // - 1 byte per pixel for 8 bit colour // - 2 bytes per pixel for 16 bit color depth - void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); + void* createSprite(int16_t width, int16_t height, uint8_t frames = 1, uint8_t * mem = nullptr); // Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type void* getPointer(void); @@ -28,7 +28,7 @@ class TFT_eSprite : public TFT_eSPI { bool created(void); // Delete the sprite to free up the RAM - void deleteSprite(void); + void deleteSprite(bool keep = false); // Select the frame buffer for graphics write (for 2 colour ePaper and DMA toggle buffer) // Returns a pointer to the Sprite frame buffer diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index 493d01f..49af605 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -2777,9 +2777,10 @@ int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) uint16_t gNum = 0; bool found = 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]); + CharMetrics * cm = getCharMetrics(gNum); + if(str_width == 0 && cm->gdX < 0) str_width -= cm->gdX; + if (*string || isDigits) str_width += cm->gxAdvance; + else str_width += (cm->gdX + cm->gWidth); } else str_width += gFont.spaceWidth + 1; } diff --git a/Tools/Create_Smooth_Font/Font partition/conv_vlw_to_prt.py b/Tools/Create_Smooth_Font/Font partition/conv_vlw_to_prt.py new file mode 100644 index 0000000..491ffd8 --- /dev/null +++ b/Tools/Create_Smooth_Font/Font partition/conv_vlw_to_prt.py @@ -0,0 +1,42 @@ +import struct + +inf = 'x324.vlw' +outf = 'x324.prt' + +with open(inf, 'rb') as f1: + x = f1.read() + +print(len(x)) + +gCount, ver, yAdvance, dummy, ascent, descent = struct.unpack('>llllll', x[:24]) +print(gCount, ver, yAdvance, dummy, ascent, descent) + +m = x[24:24+gCount*28] +bitmap = x[24+gCount*28:] + +print(len(m), len(bitmap)) +print(len(m)/28) + +in_metrics = list(struct.iter_unpack('>lllllll', m)) +print(len(in_metrics)) + +max_descent = 0 +disp = 0 +glyph_metrics = b'' +for m in in_metrics: + code, height, width, xAdvance, dY, dX, dummy = m +# print(code, height, width, xAdvance, dY, dX) + s = struct.pack(' 0x20 and code < 0xA0 and code != 0x7F) or code > 0xFF): + descent1 = height - dY + if descent1 > max_descent: max_descent = descent1 + +yAdvance = ascent + max_descent +font_metrics = struct.pack('