|
|
@ -1,3 +1,5 @@ |
|
|
|
;; FontAtlas.cake: Cache FreeType-rendered fonts into a font atlas and kerning table |
|
|
|
;; TODO: Support UTF-8 by using non char-sized keys |
|
|
|
(import |
|
|
|
;; GameLib |
|
|
|
"FreeType.cake" "Dictionary.cake") |
|
|
@ -13,10 +15,17 @@ |
|
|
|
height uint16_t |
|
|
|
to-origin-left int16_t |
|
|
|
to-origin-top int16_t |
|
|
|
advance-x uint16_t) |
|
|
|
advance-x int16_t) |
|
|
|
|
|
|
|
(defstruct kerning-entry |
|
|
|
key uint16_t ;; first character << 8, second character |
|
|
|
x int16_t |
|
|
|
;; Unused |
|
|
|
y int16_t) |
|
|
|
|
|
|
|
(defstruct font-atlas |
|
|
|
glyph-lookup-table (* glyph-entry) ;; dictionary |
|
|
|
kerning-lookup-table (* kerning-entry) ;; dictionary |
|
|
|
pixel-buffer (* (unsigned char)) ;; malloc'd |
|
|
|
width uint16_t |
|
|
|
height uint16_t |
|
|
@ -28,6 +37,11 @@ |
|
|
|
(dict-free (path font-atlas-to-free > glyph-lookup-table)) |
|
|
|
(free (path font-atlas-to-free > pixel-buffer))) |
|
|
|
|
|
|
|
(defun font-atlas-make-character-pair (character-a char |
|
|
|
character-b char |
|
|
|
&return uint16_t) |
|
|
|
(return (bit-or (bit-<< character-a 8) character-b))) |
|
|
|
|
|
|
|
;; Returns 0 for success or anything else for failure |
|
|
|
(defun build-font-atlas (font-face (* (const (unsigned char))) |
|
|
|
font-face-size (unsigned int) |
|
|
@ -161,4 +175,38 @@ |
|
|
|
;; Wrapping happens after we know what the next glyph's dimensions are |
|
|
|
(set atlas-write-x (+ atlas-write-x num-columns)))) |
|
|
|
|
|
|
|
;; Build kerning lookup table |
|
|
|
(each-in-array ranges-to-render range-index-a |
|
|
|
(var range-a (* ascii-glyph-range) (addr (at range-index-a ranges-to-render))) |
|
|
|
(each-in-range (- (+ 1 (path range-a > end-character-inclusive)) (path range-a > start-character)) |
|
|
|
character-offset-from-start |
|
|
|
(var character-a char (+ character-offset-from-start (path range-a > start-character))) |
|
|
|
(var glyph-index-a int (FT_Get_Char_Index typeface character-a)) |
|
|
|
(unless glyph-index-a |
|
|
|
(continue)) |
|
|
|
|
|
|
|
(each-in-array ranges-to-render range-index-b |
|
|
|
(var range-b (* ascii-glyph-range) (addr (at range-index-b ranges-to-render))) |
|
|
|
(each-in-range (- (+ 1 (path range-b > end-character-inclusive)) (path range-b > start-character)) |
|
|
|
character-offset-from-start |
|
|
|
(var character-b char (+ character-offset-from-start (path range-b > start-character))) |
|
|
|
;; If this is slow, it might make sense to cache it in the outer loop |
|
|
|
(var glyph-index-b int (FT_Get_Char_Index typeface character-b)) |
|
|
|
(unless glyph-index-b |
|
|
|
(continue)) |
|
|
|
|
|
|
|
(var kerning FT_Vector) |
|
|
|
(set result (FT_Get_Kerning typeface glyph-index-a glyph-index-b |
|
|
|
FT_KERNING_DEFAULT (addr kerning))) |
|
|
|
(freetype-check-result-or-return result "Getting kerning value") |
|
|
|
(when (or (field kerning x) (field kerning y)) |
|
|
|
(var new-kerning-entry kerning-entry (array 0)) |
|
|
|
(var character-pair uint16_t (font-atlas-make-character-pair |
|
|
|
character-a character-b)) |
|
|
|
(set (field new-kerning-entry key) character-pair) |
|
|
|
(set (field new-kerning-entry x) (bit->> (field kerning x) 6)) |
|
|
|
(set (field new-kerning-entry y) (bit->> (field kerning y) 6)) |
|
|
|
(dict-set-struct (path font-atlas-out > kerning-lookup-table) |
|
|
|
new-kerning-entry)))))) |
|
|
|
|
|
|
|
(return 0)) |
|
|
|