4 changed files with 339 additions and 1 deletions
@ -0,0 +1,101 @@ |
|||
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src") |
|||
(add-cakelisp-search-directory "Dependencies/cakelisp/runtime") |
|||
|
|||
;; SDLFontAtlas.cake: Render font atlases generated by FreeType.cake. This is kept separate from |
|||
;; both libraries in order to not force a dependency on either. |
|||
(import "SDL.cake" "FreeType.cake" "Dictionary.cake" |
|||
"CHelpers.cake") |
|||
|
|||
(forward-declare (struct SDL_Renderer) |
|||
(struct SDL_Texture) |
|||
(struct font-atlas)) |
|||
|
|||
(var s-enable-kerning bool true) |
|||
|
|||
;; TODO: Support UTF-8 |
|||
(defun render-string (renderer (addr SDL_Renderer) font (addr font-atlas) font-texture (addr SDL_Texture) |
|||
x int y int str (addr (const char))) |
|||
(var write-x int x) |
|||
(var write-y int y) |
|||
(var tab-width int 100) |
|||
(scope ;; Get tab width based on space advance |
|||
(var space-key char ' ') |
|||
(var glyph (addr glyph-entry) (dict-ptr-at (path font > glyph-lookup-table) space-key)) |
|||
(when glyph |
|||
(set tab-width (* 4 (path glyph > advance-x))))) |
|||
|
|||
(var line-height int (path font > font-height)) |
|||
|
|||
(each-char-in-string-const str current-char |
|||
(cond |
|||
((= (deref current-char) '\r') |
|||
(continue)) |
|||
((= (deref current-char) '\n') |
|||
(set write-y (+ line-height write-y)) |
|||
(set write-x x) |
|||
(continue)) |
|||
((= (deref current-char) '\t') |
|||
(set write-x (+ write-x tab-width)) |
|||
(continue))) |
|||
|
|||
(var search-key char (deref current-char)) |
|||
(var glyph (addr glyph-entry) (dict-ptr-at (path font > glyph-lookup-table) search-key)) |
|||
(unless glyph ;; fallback |
|||
(set search-key '?') |
|||
(set glyph (dict-ptr-at (path font > glyph-lookup-table) search-key))) |
|||
(unless glyph ;; even the fallback is missing! |
|||
(continue)) |
|||
(var source-rectangle SDL_Rect |
|||
(array (path glyph > x) |
|||
(path glyph > y) |
|||
(path glyph > width) |
|||
(path glyph > height))) |
|||
(var destination-rectangle SDL_Rect |
|||
(array |
|||
(+ write-x (path glyph > to-origin-left)) |
|||
(- write-y (path glyph > to-origin-top)) |
|||
(path glyph > width) |
|||
(path glyph > height))) |
|||
(SDL_RenderCopy renderer font-texture |
|||
(addr source-rectangle) (addr destination-rectangle)) |
|||
(set write-x (+ write-x (path glyph > advance-x))) |
|||
|
|||
(when (and s-enable-kerning (+ 1 current-char)) |
|||
(var character-pair uint16_t (font-atlas-make-character-pair |
|||
(deref current-char) (at 1 current-char))) |
|||
(var kerning (addr kerning-entry) |
|||
(dict-ptr-at (path font > kerning-lookup-table) character-pair)) |
|||
(when kerning |
|||
(set write-x (+ write-x (path kerning > x))))))) |
|||
|
|||
(defun make-font-atlas-and-texture (renderer (addr SDL_Renderer) |
|||
font-atlas-out (addr font-atlas) font-texture-out (addr (addr SDL_Texture)) |
|||
font-data (addr (const (unsigned char))) font-data-size (unsigned int) |
|||
device-dpi (unsigned int) |
|||
font-size-points (unsigned char) |
|||
&return bool) |
|||
(var enable-subpixel-antialiasing bool true) |
|||
(unless (= 0 (build-font-atlas font-data font-data-size |
|||
font-size-points |
|||
device-dpi |
|||
enable-subpixel-antialiasing |
|||
font-atlas-out)) |
|||
(return false)) |
|||
|
|||
(scope |
|||
(var font-surface (addr SDL_Surface) |
|||
(SDL_CreateRGBSurfaceWithFormatFrom |
|||
(path font-atlas-out > pixel-buffer) |
|||
(path font-atlas-out > width) |
|||
(path font-atlas-out > height) |
|||
32 ;; bit depth of each pixel (RGBA) |
|||
(* (path font-atlas-out > width) 4) ;; pitch (width of a row in bytes) |
|||
;; Because of how SDL reads pixels in, this does seem to be endian-dependent |
|||
;; I don't fully understand why |
|||
SDL_PIXELFORMAT_RGBA32)) |
|||
(defer (SDL_FreeSurface font-surface)) ;; We don't need this after making the texture |
|||
(set (deref font-texture-out) (SDL_CreateTextureFromSurface renderer font-surface)) |
|||
(unless (deref font-texture-out) |
|||
(sdl-print-error) |
|||
(return false))) |
|||
(return true)) |
Loading…
Reference in new issue