mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Added PBF font file loading
This commit is contained in:
parent
5fe2e6ae95
commit
566344f4e8
1
Makefile
1
Makefile
@ -411,6 +411,7 @@ SOURCES += \
|
||||
libs/graphics/bitmap_font_4x6.c \
|
||||
libs/graphics/bitmap_font_6x8.c \
|
||||
libs/graphics/vector_font.c \
|
||||
libs/graphics/pbf_font.c \
|
||||
libs/graphics/graphics.c \
|
||||
libs/graphics/lcd_arraybuffer.c \
|
||||
libs/graphics/lcd_js.c
|
||||
|
||||
@ -88,6 +88,7 @@ typedef enum {
|
||||
JSGRAPHICS_FONTSIZE_CUSTOM_1BPP = 4 << 13,// a custom bitmap font made from fields in the graphics object (See below)
|
||||
JSGRAPHICS_FONTSIZE_CUSTOM_2BPP = 5 << 13,// a custom bitmap font made from fields in the graphics object (See below)
|
||||
JSGRAPHICS_FONTSIZE_CUSTOM_4BPP = 6 << 13,// a custom bitmap font made from fields in the graphics object (See below)
|
||||
JSGRAPHICS_FONTSIZE_CUSTOM_PBF = 7 << 13,// a custom bitmap font using PBF format (in JSGRAPHICS_CUSTOMFONT_BMP)
|
||||
JSGRAPHICS_FONTSIZE_CUSTOM_BIT = 4 << 13 // all custom fonts have this bit set
|
||||
#endif
|
||||
} JsGraphicsFontSize;
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
#include "bitmap_font_4x6.h"
|
||||
#include "bitmap_font_6x8.h"
|
||||
#include "vector_font.h"
|
||||
#include "pbf_font.h"
|
||||
|
||||
#ifdef GRAPHICS_PALETTED_IMAGES
|
||||
#if defined(ESPR_GRAPHICS_12BIT)
|
||||
@ -797,7 +798,7 @@ JsVar *jswrap_graphics_createImage(JsVar *data) {
|
||||
}
|
||||
}
|
||||
if (x) height++;
|
||||
if (height && ch=="\n") height--; // if the last char was a newline, ignore it
|
||||
if (height && ch=='\n') height--; // if the last char was a newline, ignore it
|
||||
jsvStringIteratorFree(&it);
|
||||
// Sorted - now create the object, set it up and create the buffer
|
||||
JsVar *img = jsvNewObject();
|
||||
@ -1716,6 +1717,36 @@ JsVar *jswrap_graphics_setFontCustom(JsVar *parent, JsVar *bitmap, int firstChar
|
||||
return jsvLockAgain(parent);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*JSON{
|
||||
"type" : "method",
|
||||
"class" : "Graphics",
|
||||
"name" : "setFontPBF",
|
||||
"ifndef" : "SAVE_ON_FLASH",
|
||||
"generate" : "jswrap_graphics_setFontPBF",
|
||||
"params" : [
|
||||
["file","JsVar","The font as a PBF file"]
|
||||
],
|
||||
"return" : ["JsVar","The instance of Graphics this was called on, to allow call chaining"],
|
||||
"return_object" : "Graphics"
|
||||
}
|
||||
*/
|
||||
#ifndef SAVE_ON_FLASH
|
||||
JsVar *jswrap_graphics_setFontPBF(JsVar *parent, JsVar *file) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
|
||||
|
||||
if (!jsvIsString(file)) {
|
||||
jsExceptionHere(JSET_ERROR, "Font must be a String");
|
||||
return 0;
|
||||
}
|
||||
int scale = 1;
|
||||
jsvObjectSetChild(parent, JSGRAPHICS_CUSTOMFONT_BMP, file);
|
||||
gfx.data.fontSize = (unsigned short)(scale | JSGRAPHICS_FONTSIZE_CUSTOM_PBF);
|
||||
graphicsSetVar(&gfx);
|
||||
return jsvLockAgain(parent);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*JSON{
|
||||
"type" : "method",
|
||||
"class" : "Graphics",
|
||||
@ -1990,6 +2021,9 @@ typedef struct {
|
||||
unsigned short scale;
|
||||
unsigned short scalex, scaley;
|
||||
unsigned char customFirstChar;
|
||||
JsVar *widths; // Array of widths (for old-style fonts) or just an int for fixed width
|
||||
JsVar *bitmap; // Bitmap/font data
|
||||
PbfFontLoaderInfo pbfInfo;
|
||||
} JsGraphicsFontInfo;
|
||||
|
||||
static void _jswrap_graphics_getFontInfo(JsGraphics *gfx, JsGraphicsFontInfo *info) {
|
||||
@ -2004,34 +2038,53 @@ static void _jswrap_graphics_getFontInfo(JsGraphics *gfx, JsGraphicsFontInfo *in
|
||||
#ifndef SAVE_ON_FLASH
|
||||
if (info->font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
|
||||
info->customFirstChar = (int)jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(gfx->graphicsVar, JSGRAPHICS_CUSTOMFONT_FIRSTCHAR));
|
||||
info->widths = jsvObjectGetChildIfExists(gfx->graphicsVar, JSGRAPHICS_CUSTOMFONT_WIDTH);
|
||||
info->bitmap = jsvObjectGetChildIfExists(gfx->graphicsVar, JSGRAPHICS_CUSTOMFONT_BMP);
|
||||
if ((info->font & JSGRAPHICS_FONTSIZE_FONT_MASK) == JSGRAPHICS_FONTSIZE_CUSTOM_PBF)
|
||||
jspbfFontNew(&info->pbfInfo, info->bitmap);
|
||||
} else
|
||||
#endif
|
||||
info->customFirstChar = 0;
|
||||
|
||||
}
|
||||
|
||||
static int _jswrap_graphics_getCharWidth(JsGraphics *gfx, JsGraphicsFontInfo *info, char ch) {
|
||||
if (info->font == JSGRAPHICS_FONTSIZE_VECTOR) {
|
||||
static void _jswrap_graphics_freeFontInfo(JsGraphicsFontInfo *info) {
|
||||
if (info->font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
|
||||
jsvUnLock(info->widths);
|
||||
jsvUnLock(info->bitmap);
|
||||
if ((info->font & JSGRAPHICS_FONTSIZE_FONT_MASK) == JSGRAPHICS_FONTSIZE_CUSTOM_PBF)
|
||||
jspbfFontFree(&info->pbfInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static int _jswrap_graphics_getCharWidth(JsGraphics *gfx, JsGraphicsFontInfo *info, int ch) {
|
||||
if ((info->font == JSGRAPHICS_FONTSIZE_VECTOR) && (ch<256)) {
|
||||
#ifndef NO_VECTOR_FONT
|
||||
return (int)graphicsVectorCharWidth(info->scalex, ch);
|
||||
#endif
|
||||
} else if (info->font == JSGRAPHICS_FONTSIZE_4X6) {
|
||||
} else if ((info->font == JSGRAPHICS_FONTSIZE_4X6) && (ch<256)) {
|
||||
return 4*info->scalex;
|
||||
#ifdef USE_FONT_6X8
|
||||
} else if (info->font == JSGRAPHICS_FONTSIZE_6X8) {
|
||||
} else if ((info->font == JSGRAPHICS_FONTSIZE_6X8) && (ch<256)) {
|
||||
return 6*info->scalex;
|
||||
#endif
|
||||
#ifndef SAVE_ON_FLASH
|
||||
} else if (info->font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
|
||||
if ((info->font & JSGRAPHICS_FONTSIZE_FONT_MASK)==JSGRAPHICS_FONTSIZE_CUSTOM_PBF) {
|
||||
PbfFontLoaderGlyph result;
|
||||
if (jspbfFontFindGlyph(&info->pbfInfo, ch, &result))
|
||||
return result.advance;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
int w = 0;
|
||||
// FIXME: is getCharWidth is called a lot (eg for metrics), we do getChild for each
|
||||
// character - maybe we should store this in JsGraphicsFontInfo (but then we have to unlock it)
|
||||
JsVar *customWidth = jsvObjectGetChildIfExists(gfx->graphicsVar, JSGRAPHICS_CUSTOMFONT_WIDTH);
|
||||
if (jsvIsString(customWidth)) {
|
||||
if (ch>=info->customFirstChar)
|
||||
w = info->scalex*(unsigned char)jsvGetCharInString(customWidth, (size_t)(ch-info->customFirstChar));
|
||||
} else
|
||||
w = info->scalex*(int)jsvGetInteger(customWidth);
|
||||
jsvUnLock(customWidth);
|
||||
if (ch<256) {
|
||||
if (jsvIsString(info->widths)) {
|
||||
if (ch>=info->customFirstChar)
|
||||
w = info->scalex*(unsigned char)jsvGetCharInString(info->widths, (size_t)(ch-info->customFirstChar));
|
||||
} else
|
||||
w = info->scalex*(int)jsvGetInteger(info->widths);
|
||||
}
|
||||
return w;
|
||||
#endif
|
||||
}
|
||||
@ -2059,6 +2112,8 @@ static int _jswrap_graphics_getFontHeightInternal(JsGraphics *gfx, JsGraphicsFon
|
||||
#endif
|
||||
#ifndef SAVE_ON_FLASH
|
||||
} else if (info->font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
|
||||
if ((info->font & JSGRAPHICS_FONTSIZE_FONT_MASK)==JSGRAPHICS_FONTSIZE_CUSTOM_PBF)
|
||||
return info->pbfInfo.lineHeight;
|
||||
return info->scaley*(int)jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(gfx->graphicsVar, JSGRAPHICS_CUSTOMFONT_HEIGHT));
|
||||
#endif
|
||||
}
|
||||
@ -2069,7 +2124,9 @@ int jswrap_graphics_getFontHeight(JsVar *parent) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return 0;
|
||||
JsGraphicsFontInfo info;
|
||||
_jswrap_graphics_getFontInfo(&gfx, &info);
|
||||
return _jswrap_graphics_getFontHeightInternal(&gfx, &info);
|
||||
int h = _jswrap_graphics_getFontHeightInternal(&gfx, &info);
|
||||
_jswrap_graphics_freeFontInfo(&info);
|
||||
return h;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
@ -2117,6 +2174,7 @@ void _jswrap_graphics_stringMetrics(JsGraphics *gfx, JsVar *var, int lineStartIn
|
||||
jsvUnLock(str);
|
||||
if (stringWidth) *stringWidth = width>maxWidth ? width : maxWidth;
|
||||
if (stringHeight) *stringHeight = height;
|
||||
_jswrap_graphics_freeFontInfo(&info);
|
||||
}
|
||||
JsVarInt _jswrap_graphics_stringWidth(JsGraphics *gfx, JsVar *var, int lineStartIndex) {
|
||||
int w,h;
|
||||
@ -2271,6 +2329,7 @@ JsVar *jswrap_graphics_wrapString(JsVar *parent, JsVar *str, int maxWidth) {
|
||||
if (jsvGetStringLength(currentLine))
|
||||
jsvArrayPush(lines, currentLine);
|
||||
jsvUnLock2(str,currentLine);
|
||||
_jswrap_graphics_freeFontInfo(&info);
|
||||
return lines;
|
||||
}
|
||||
|
||||
@ -2317,14 +2376,11 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
|
||||
int fontHeight = _jswrap_graphics_getFontHeightInternal(&gfx, &info);
|
||||
|
||||
#ifndef SAVE_ON_FLASH
|
||||
JsVar *customBitmap = 0, *customWidth = 0;
|
||||
int customBPP = 1;
|
||||
|
||||
if (info.font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
|
||||
if (info.font==JSGRAPHICS_FONTSIZE_CUSTOM_2BPP) customBPP = 2;
|
||||
if (info.font==JSGRAPHICS_FONTSIZE_CUSTOM_4BPP) customBPP = 4;
|
||||
customBitmap = jsvObjectGetChildIfExists(parent, JSGRAPHICS_CUSTOMFONT_BMP);
|
||||
customWidth = jsvObjectGetChildIfExists(parent, JSGRAPHICS_CUSTOMFONT_WIDTH);
|
||||
if ((info.font&JSGRAPHICS_FONTSIZE_FONT_MASK)==JSGRAPHICS_FONTSIZE_CUSTOM_2BPP) customBPP = 2;
|
||||
if ((info.font&JSGRAPHICS_FONTSIZE_FONT_MASK)==JSGRAPHICS_FONTSIZE_CUSTOM_4BPP) customBPP = 4;
|
||||
}
|
||||
#endif
|
||||
#ifndef SAVE_ON_FLASH
|
||||
@ -2402,36 +2458,44 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (info.font == JSGRAPHICS_FONTSIZE_VECTOR) {
|
||||
if ((info.font == JSGRAPHICS_FONTSIZE_VECTOR) && (ch<256)) {
|
||||
#ifndef NO_VECTOR_FONT
|
||||
int w = (int)graphicsVectorCharWidth(info.scalex, ch);
|
||||
// TODO: potentially we could do this in x16 accuracy so vector chars rendered together better
|
||||
if (x>minX-w && x<maxX && y>minY-fontHeight && y<=maxY) {
|
||||
if (solidBackground)
|
||||
graphicsFillRect(&gfx,x,y,x+w-1,y+fontHeight-1, gfx.data.bgColor);
|
||||
graphicsGetVectorChar((graphicsPolyCallback)graphicsFillPoly, &gfx, x, y, info.scalex, info.scaley, ch);
|
||||
graphicsGetVectorChar((graphicsPolyCallback)graphicsFillPoly, &gfx, x, y, info.scalex, info.scaley, (char)ch);
|
||||
}
|
||||
x+=w;
|
||||
#endif
|
||||
} else if (info.font == JSGRAPHICS_FONTSIZE_4X6) {
|
||||
} else if ((info.font == JSGRAPHICS_FONTSIZE_4X6) && (ch<256)) {
|
||||
if (x>minX-4*info.scalex && x<maxX && y>minY-fontHeight && y<=maxY)
|
||||
graphicsDrawChar4x6(&gfx, x, y, ch, info.scalex, info.scaley, solidBackground);
|
||||
graphicsDrawChar4x6(&gfx, x, y, (char)ch, info.scalex, info.scaley, solidBackground);
|
||||
x+=4*info.scalex;
|
||||
#ifdef USE_FONT_6X8
|
||||
} else if (info.font == JSGRAPHICS_FONTSIZE_6X8) {
|
||||
if (x>minX-6*info.scalex && x<maxX && y>minY-fontHeight && y<=maxY)
|
||||
graphicsDrawChar6x8(&gfx, x, y, ch, info.scalex, info.scaley, solidBackground);
|
||||
graphicsDrawChar6x8(&gfx, x, y, (char)ch, info.scalex, info.scaley, solidBackground);
|
||||
x+=6*info.scalex;
|
||||
#endif
|
||||
#ifndef SAVE_ON_FLASH
|
||||
} else if (info.font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) {
|
||||
} else if ((info.font & JSGRAPHICS_FONTSIZE_FONT_MASK)==JSGRAPHICS_FONTSIZE_CUSTOM_PBF) {
|
||||
PbfFontLoaderGlyph glyph;
|
||||
if (jspbfFontFindGlyph(&info.pbfInfo, ch, &glyph)) {
|
||||
jspbfFontRenderGlyph(&info.pbfInfo, &glyph, &gfx,
|
||||
x+glyph.x*info.scalex, y+glyph.y*info.scaley,
|
||||
solidBackground, info.scalex, info.scaley);
|
||||
x+=glyph.advance*info.scalex;
|
||||
}
|
||||
} else if ((info.font & JSGRAPHICS_FONTSIZE_CUSTOM_BIT) && (ch<256)) {
|
||||
int customBPPRange = (1<<customBPP)-1;
|
||||
// get char width and offset in string
|
||||
int width = 0, bmpOffset = 0;
|
||||
if (jsvIsString(customWidth)) {
|
||||
if (jsvIsString(info.widths)) {
|
||||
if (ch>=info.customFirstChar) {
|
||||
JsvStringIterator wit;
|
||||
jsvStringIteratorNew(&wit, customWidth, 0);
|
||||
jsvStringIteratorNew(&wit, info.widths, 0);
|
||||
while (jsvStringIteratorHasChar(&wit) && (int)jsvStringIteratorGetIndex(&wit)<(ch-info.customFirstChar)) {
|
||||
bmpOffset += (unsigned char)jsvStringIteratorGetCharAndNext(&wit);
|
||||
}
|
||||
@ -2439,7 +2503,7 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
|
||||
jsvStringIteratorFree(&wit);
|
||||
}
|
||||
} else {
|
||||
width = (int)jsvGetInteger(customWidth);
|
||||
width = (int)jsvGetInteger(info.widths);
|
||||
bmpOffset = width*(ch-info.customFirstChar);
|
||||
}
|
||||
if (ch>=info.customFirstChar && (x>minX-width*info.scalex) && (x<maxX) && (y>minY-fontHeight) && y<=maxY) {
|
||||
@ -2447,7 +2511,7 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
|
||||
bmpOffset *= ch * customBPP;
|
||||
// now render character
|
||||
JsvStringIterator cit;
|
||||
jsvStringIteratorNew(&cit, customBitmap, (size_t)(bmpOffset>>3));
|
||||
jsvStringIteratorNew(&cit, info.bitmap, (size_t)(bmpOffset>>3));
|
||||
bmpOffset &= 7;
|
||||
int cx,cy;
|
||||
int citdata = jsvStringIteratorGetChar(&cit);
|
||||
@ -2480,13 +2544,11 @@ JsVar *jswrap_graphics_drawString(JsVar *parent, JsVar *var, int x, int y, bool
|
||||
}
|
||||
jsvStringIteratorFree(&it);
|
||||
jsvUnLock(str);
|
||||
#ifndef SAVE_ON_FLASH
|
||||
jsvUnLock2(customBitmap, customWidth);
|
||||
#endif
|
||||
#ifndef SAVE_ON_FLASH
|
||||
gfx.data.flags = oldFlags; // restore flags because of text rotation
|
||||
graphicsSetVar(&gfx); // gfx data changed because modified area
|
||||
#endif
|
||||
_jswrap_graphics_freeFontInfo(&info);
|
||||
return jsvLockAgain(parent);
|
||||
}
|
||||
|
||||
|
||||
@ -56,6 +56,7 @@ JsVarInt jswrap_graphics_getColorX(JsVar *parent, bool isForeground);
|
||||
JsVar *jswrap_graphics_setClipRect(JsVar *parent, int x1, int y1, int x2, int y2);
|
||||
JsVar *jswrap_graphics_setFontSizeX(JsVar *parent, int size, bool isVectorFont);
|
||||
JsVar *jswrap_graphics_setFontCustom(JsVar *parent, JsVar *bitmap, int firstChar, JsVar *width, int height);
|
||||
JsVar *jswrap_graphics_setFontPBF(JsVar *parent, JsVar *file);
|
||||
JsVar *jswrap_graphics_setFontAlign(JsVar *parent, int x, int y, int r);
|
||||
JsVar *jswrap_graphics_setFont(JsVar *parent, JsVar *name, int size);
|
||||
JsVar *jswrap_graphics_getFont(JsVar *parent);
|
||||
|
||||
135
libs/graphics/pbf_font.c
Normal file
135
libs/graphics/pbf_font.c
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
||||
*
|
||||
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Pebble font format parser
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "pbf_font.h"
|
||||
|
||||
// https://github.com/pebble-dev/wiki/wiki/Firmware-Font-Format
|
||||
|
||||
/* Notes for improvements in a new format:
|
||||
|
||||
* remove value in hashtable (un-needed)
|
||||
* Smaller hashtable, might as well use ~64 or something
|
||||
* per-codepoint codepoint size?
|
||||
* Allow mix of 1bpp/2bpp/etc glyphs
|
||||
* Store all glyphs in one chunk - allow bit-level packing
|
||||
*/
|
||||
|
||||
static uint8_t jspbfGetU8(JsvStringIterator *it) {
|
||||
return (uint8_t)jsvStringIteratorGetCharAndNext(it);
|
||||
}
|
||||
static uint16_t jspbfGetU16(JsvStringIterator *it) {
|
||||
return (uint16_t)((uint16_t)(uint8_t)jsvStringIteratorGetCharAndNext(it) |
|
||||
(((uint16_t)(uint8_t)jsvStringIteratorGetCharAndNext(it))<<8));
|
||||
}
|
||||
static uint32_t jspbfGetU32(JsvStringIterator *it) {
|
||||
return (uint32_t)((uint32_t)(uint8_t)jsvStringIteratorGetCharAndNext(it) |
|
||||
(((uint32_t)(uint8_t)jsvStringIteratorGetCharAndNext(it))<<8) |
|
||||
(((uint32_t)(uint8_t)jsvStringIteratorGetCharAndNext(it))<<16) |
|
||||
(((uint32_t)(uint8_t)jsvStringIteratorGetCharAndNext(it))<<24));
|
||||
}
|
||||
|
||||
/// Load a .pbf file
|
||||
void jspbfFontNew(PbfFontLoaderInfo *info, JsVar *font) {
|
||||
info->var = jsvLockAgain(font);
|
||||
jsvStringIteratorNew(&info->it, font, 0);
|
||||
info->version = jspbfGetU8(&info->it); // 0
|
||||
info->lineHeight = jspbfGetU8(&info->it); // 1
|
||||
info->glyphCount = jspbfGetU16(&info->it); // 2
|
||||
jspbfGetU16(&info->it); // wildcard codepoint
|
||||
info->hashTableOffset = 6;
|
||||
info->hashTableSize = 255;
|
||||
info->codepointSize = 2;
|
||||
if (info->version>=2) {
|
||||
info->hashTableOffset = 8;
|
||||
info->hashTableSize = jspbfGetU8(&info->it);
|
||||
info->codepointSize = jspbfGetU8(&info->it);
|
||||
}
|
||||
if (info->version==3) {
|
||||
info->hashTableOffset = 10;
|
||||
assert(0); // v3 not loaded yet
|
||||
}
|
||||
info->offsetTableOffset = (uint16_t)(info->hashTableOffset + info->hashTableSize*4);
|
||||
info->glyphTableOffset = (uint16_t)(info->offsetTableOffset + info->glyphCount*6); // cp=2,address=4
|
||||
}
|
||||
|
||||
void jspbfFontFree(PbfFontLoaderInfo *info) {
|
||||
jsvStringIteratorFree(&info->it);
|
||||
jsvUnLock(info->var);
|
||||
info->var = NULL;
|
||||
}
|
||||
|
||||
// Find the font glyph, fill PbfFontLoaderGlyph with info. Iterator is left pointing to glyph
|
||||
bool jspbfFontFindGlyph(PbfFontLoaderInfo *info, int codepoint, PbfFontLoaderGlyph *result) {
|
||||
int hash = codepoint % info->hashTableSize;
|
||||
/*
|
||||
HashTable
|
||||
0x00 u8 : Value. In all examples I encountered, this simply counts 0..255
|
||||
0x01 u8 : Offset Table Size.
|
||||
0x02 u16 : Offset Table Offset. Measured in bytes from the beginning of the offset table.
|
||||
*/
|
||||
jsvStringIteratorGoto(&info->it, info->var, info->hashTableOffset + 4*hash + 1); // +1 because we don't care about value
|
||||
uint8_t offsetTableSize = jspbfGetU8(&info->it);
|
||||
uint16_t o = jspbfGetU16(&info->it);
|
||||
uint16_t offsetTableOffset = o + info->offsetTableOffset;
|
||||
jsvStringIteratorGoto(&info->it, info->var, offsetTableOffset);
|
||||
int cp;
|
||||
while (offsetTableSize--) {
|
||||
/* Offset Table
|
||||
0x00 u16/u32 : Unicode codepoint (for example, 0x0622 for ∆).
|
||||
0x02 or 0x04 u16/u32 : Data offset.
|
||||
*/
|
||||
cp = jspbfGetU16(&info->it); assert(info->codepointSize==2); // only cp=2 suppported
|
||||
uint32_t dataOffset = jspbfGetU32(&info->it); // only address=4 byte supported
|
||||
if (cp==codepoint) {
|
||||
jsvStringIteratorGoto(&info->it, info->var, info->glyphTableOffset+dataOffset);
|
||||
result->w = jspbfGetU8(&info->it);
|
||||
result->h = jspbfGetU8(&info->it);
|
||||
result->x = (int8_t)jspbfGetU8(&info->it);
|
||||
result->y = (int8_t)jspbfGetU8(&info->it);
|
||||
result->advance = (int8_t)jspbfGetU8(&info->it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void jspbfFontRenderGlyph(PbfFontLoaderInfo *info, PbfFontLoaderGlyph *glyph, JsGraphics *gfx, int x, int y, bool solidBackground, int scalex, int scaley) {
|
||||
//bmpOffset *= ch * customBPP;
|
||||
// now render character
|
||||
int bmpOffset = 0;
|
||||
int bpp = 1;
|
||||
int bppRange = (1<<bpp)-1;
|
||||
bmpOffset &= 7;
|
||||
int cx,cy;
|
||||
int citdata = jsvStringIteratorGetCharAndNext(&info->it);
|
||||
citdata <<= bpp*bmpOffset;
|
||||
for (cy=0;cy<glyph->h;cy++) {
|
||||
for (cx=0;cx<glyph->w;cx++) {
|
||||
int col = citdata&bppRange;
|
||||
if (solidBackground || col)
|
||||
graphicsFillRect(gfx,
|
||||
(x + cx*scalex),
|
||||
(y + cy*scaley),
|
||||
(x + cx*scalex + scalex-1),
|
||||
(y + cy*scaley + scaley-1),
|
||||
graphicsBlendGfxColor(gfx, (256*col)/bppRange));
|
||||
bmpOffset += bpp;
|
||||
citdata >>= bpp;
|
||||
if (bmpOffset>=8) {
|
||||
bmpOffset=0;
|
||||
citdata = jsvStringIteratorGetCharAndNext(&info->it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
libs/graphics/pbf_font.h
Normal file
47
libs/graphics/pbf_font.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
||||
*
|
||||
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Pebble font format parser
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "jsvar.h"
|
||||
#include "jsvariterator.h"
|
||||
#include "graphics.h"
|
||||
|
||||
typedef struct {
|
||||
JsVar *var;
|
||||
JsvStringIterator it;
|
||||
uint8_t version;
|
||||
uint8_t lineHeight;
|
||||
uint16_t glyphCount;
|
||||
uint8_t hashTableSize;
|
||||
uint8_t codepointSize;
|
||||
uint16_t hashTableOffset;
|
||||
uint16_t offsetTableOffset;
|
||||
uint16_t glyphTableOffset;
|
||||
} PbfFontLoaderInfo;
|
||||
|
||||
typedef struct {
|
||||
uint8_t w;
|
||||
uint8_t h;
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
int8_t advance; // how wide is the character itself?
|
||||
} PbfFontLoaderGlyph;
|
||||
|
||||
/// Load a .pbf file
|
||||
void jspbfFontNew(PbfFontLoaderInfo *info, JsVar *font);
|
||||
void jspbfFontFree(PbfFontLoaderInfo *info);
|
||||
|
||||
// Find the font glyph, fill PbfFontLoaderGlyph with info. Iterator is left pointing to glyph
|
||||
bool jspbfFontFindGlyph(PbfFontLoaderInfo *info, int codepoint, PbfFontLoaderGlyph *result);
|
||||
|
||||
void jspbfFontRenderGlyph(PbfFontLoaderInfo *info, PbfFontLoaderGlyph *glyph, JsGraphics *gfx, int x, int y, bool solidBackground, int scalex, int scaley);
|
||||
Loading…
x
Reference in New Issue
Block a user