Font partition supported. No time and ram is used for load smooth font.
This commit is contained in:
parent
7d85157c3c
commit
44d8aa1073
|
|
@ -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
|
||||
|
||||
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
|
||||
|
||||
fontLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
static TFT_eSPI::CharMetrics _cm;
|
||||
|
||||
TFT_eSPI::CharMetrics * TFT_eSPI::getCharMetrics(uint16_t gNum)
|
||||
{
|
||||
CharMetrics * cm = &_cm;
|
||||
|
||||
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();
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
#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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
@ -31,17 +33,29 @@
|
|||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
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,7 +386,7 @@ 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)
|
||||
{
|
||||
|
|
@ -382,6 +396,7 @@ void TFT_eSprite::deleteSprite(void)
|
|||
|
||||
if (_created)
|
||||
{
|
||||
if (!keep)
|
||||
free(_img8_1);
|
||||
_img8 = nullptr;
|
||||
_created = false;
|
||||
|
|
@ -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]);
|
||||
}
|
||||
#endif
|
||||
for (int32_t x = 0; x < gWidth[gNum]; x++)
|
||||
{
|
||||
#ifdef FONT_FS_AVAILABLE
|
||||
if (fs_font) {
|
||||
pixel = pbuffer[x];
|
||||
fontFile.read(pbuffer, cm->gWidth);
|
||||
}
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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('<lllllll', code, height, width, xAdvance, dY, dX, disp)
|
||||
glyph_metrics += s
|
||||
disp += height * width
|
||||
if ((code > 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('<llllll', gCount, ver, yAdvance, max_descent, ascent, descent)
|
||||
|
||||
out_data = font_metrics + glyph_metrics + bitmap
|
||||
|
||||
with open(outf, 'wb') as f2:
|
||||
f2.write(out_data)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x300000,
|
||||
app1, app, ota_1, 0x310000,0x300000,
|
||||
font1, data, fat, 0x610000,0x300000,
|
||||
spiffs, data, spiffs, 0x910000,0x4F0000,
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
tools\esptool.exe --port COM49 --baud 2000000 write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0x610000 data/x324.prt
|
||||
Loading…
Reference in New Issue