|
|
@ -5,7 +5,13 @@ |
|
|
|
|
|
|
|
(import |
|
|
|
;; GameLib |
|
|
|
"SDL.cake" "DynamicArray.cake") |
|
|
|
"SDL.cake" "FreeType.cake" "DynamicArray.cake" "Dictionary.cake" "DataBundle.cake") |
|
|
|
|
|
|
|
(c-import "<stdio.h>" |
|
|
|
&with-decls "<stdint.h>") |
|
|
|
|
|
|
|
(bundle-file s-start-ubuntu-regular-font s-end-ubuntu-regular-font |
|
|
|
(unsigned char) "data/Fonts/Ubuntu-R.ttf") |
|
|
|
|
|
|
|
(define-keybind s-quit-keybind (array SDL_SCANCODE_Q keybind-modifier-flags-ctrl)) |
|
|
|
|
|
|
@ -21,7 +27,137 @@ |
|
|
|
(fprintf stderr (token-splice format))))) |
|
|
|
(return true)) |
|
|
|
|
|
|
|
(defstruct glyph-entry |
|
|
|
key char |
|
|
|
x uint16_t |
|
|
|
y uint16_t |
|
|
|
width uint16_t |
|
|
|
height uint16_t) |
|
|
|
|
|
|
|
(defstruct font-atlas |
|
|
|
glyph-lookup-table (* glyph-entry) ;; dictionary |
|
|
|
pixel-buffer (* (unsigned char)) ;; malloc'd |
|
|
|
width uint16_t |
|
|
|
height uint16_t) |
|
|
|
|
|
|
|
(defun-local free-font-atlas (font-atlas-to-free (* font-atlas)) |
|
|
|
(dict-free (path font-atlas-to-free > glyph-lookup-table)) |
|
|
|
(free (path font-atlas-to-free > pixel-buffer))) |
|
|
|
|
|
|
|
;; Returns 0 for success or anything else for failure |
|
|
|
(defun-local build-font-atlas (font-atlas-out (* font-atlas) &return int) |
|
|
|
(var freetype-library FT_Library) |
|
|
|
(var result int |
|
|
|
(FT_Init_FreeType (addr freetype-library))) |
|
|
|
(freetype-check-result-or-return result "initializing FreeType") |
|
|
|
(defer (FT_Done_FreeType freetype-library)) |
|
|
|
|
|
|
|
(var typeface FT_Face) |
|
|
|
(var face-index int 0) |
|
|
|
(set result (FT_New_Memory_Face freetype-library s-start-ubuntu-regular-font |
|
|
|
(- s-end-ubuntu-regular-font s-start-ubuntu-regular-font) |
|
|
|
face-index (addr typeface))) |
|
|
|
(unless (= result FT_Err_Ok) |
|
|
|
(fprintf stderr "error: encountered error %d while loading font\n" result) |
|
|
|
(return 1)) |
|
|
|
(defer (FT_Done_Face typeface)) |
|
|
|
|
|
|
|
(set result (FT_Set_Char_Size |
|
|
|
typeface ;; handle to face object |
|
|
|
0 ;; char_width in 1/64th of points |
|
|
|
(* 16 64) ;; char_height in 1/64th of points |
|
|
|
300 ;; horizontal device resolution |
|
|
|
300)) ;; vertical device resolution |
|
|
|
|
|
|
|
(freetype-check-result-or-return result "setting character size") |
|
|
|
|
|
|
|
(defstruct ascii-glyph-range |
|
|
|
start-character char |
|
|
|
end-character-inclusive char) |
|
|
|
;; This is a bit silly |
|
|
|
(var ranges-to-render ([] ascii-glyph-range) |
|
|
|
(array (array 'a' 'z') (array 'A' 'Z') (array '0' '9') (array '!' '/') (array ':' '@') |
|
|
|
(array '[' '`') (array '{' '~'))) |
|
|
|
|
|
|
|
(var atlas-width uint16_t 512) |
|
|
|
(var atlas-height uint16_t 512) |
|
|
|
(var num-components-per-pixel char 4) |
|
|
|
(set (path font-atlas-out > pixel-buffer) |
|
|
|
(type-cast (malloc (* atlas-width atlas-height num-components-per-pixel)) |
|
|
|
(* (unsigned char)))) |
|
|
|
(set (path font-atlas-out > width) atlas-width) |
|
|
|
(set (path font-atlas-out > height) atlas-height) |
|
|
|
(var atlas-write-x uint16_t 0) |
|
|
|
(var atlas-write-y uint16_t 0) |
|
|
|
(var atlas-tallest-character-this-row uint16_t 0) |
|
|
|
|
|
|
|
(each-in-array ranges-to-render range-index |
|
|
|
(var range (* ascii-glyph-range) (addr (at range-index ranges-to-render))) |
|
|
|
(each-in-range (- (+ 1 (path range > end-character-inclusive)) (path range > start-character)) |
|
|
|
character-offset-from-start |
|
|
|
(var character char (+ character-offset-from-start (path range > start-character))) |
|
|
|
(var glyph-index int (FT_Get_Char_Index typeface character)) |
|
|
|
(unless glyph-index |
|
|
|
(fprintf stderr "error: could not find glyph '%c' in font\n" character) |
|
|
|
(return 1)) |
|
|
|
|
|
|
|
(set result (FT_Load_Glyph typeface glyph-index FT_LOAD_DEFAULT)) |
|
|
|
(freetype-check-result-or-return result "loading glyph") |
|
|
|
|
|
|
|
;; One slot for the whole face |
|
|
|
(set result (FT_Render_Glyph (path typeface > glyph) FT_RENDER_MODE_NORMAL)) |
|
|
|
(freetype-check-result-or-return result "rendering glyph") |
|
|
|
|
|
|
|
(var num-rows int (path typeface > glyph > bitmap . rows)) |
|
|
|
(var num-columns int (path typeface > glyph > bitmap . width)) |
|
|
|
|
|
|
|
(when (> num-rows atlas-tallest-character-this-row) |
|
|
|
(set atlas-tallest-character-this-row num-rows)) |
|
|
|
|
|
|
|
(when (> (+ num-columns atlas-write-x) atlas-width) |
|
|
|
(set atlas-write-x 0) |
|
|
|
(set atlas-write-y (+ atlas-write-y atlas-tallest-character-this-row)) |
|
|
|
(set atlas-tallest-character-this-row num-rows) |
|
|
|
(when (> (+ atlas-write-y atlas-tallest-character-this-row) atlas-height) |
|
|
|
(fprintf stderr "error: ran out of space in atlas size %dx%d\n" atlas-width atlas-height) |
|
|
|
(return 1))) |
|
|
|
|
|
|
|
(var new-glyph-entry glyph-entry (array 0)) |
|
|
|
(set (field new-glyph-entry key) 'g') |
|
|
|
(set (field new-glyph-entry x) atlas-write-x) |
|
|
|
(set (field new-glyph-entry y) atlas-write-y) |
|
|
|
(set (field new-glyph-entry width) num-columns) |
|
|
|
(set (field new-glyph-entry height) num-rows) |
|
|
|
(dict-set-struct (path font-atlas-out > glyph-lookup-table) new-glyph-entry) |
|
|
|
|
|
|
|
;; TODO: This can become a memcpy if we can get FreeType to render to our same format |
|
|
|
(each-in-range num-rows row |
|
|
|
(each-in-range num-columns column |
|
|
|
(var current-pixel (* (unsigned char)) |
|
|
|
(addr |
|
|
|
(at (+ column (* row num-columns)) |
|
|
|
(path typeface > glyph > bitmap . buffer)))) |
|
|
|
(var current-pixel-out (* (unsigned char)) |
|
|
|
(addr |
|
|
|
(at (* num-components-per-pixel |
|
|
|
(+ (+ column atlas-write-x) (* (+ atlas-write-y row) atlas-width))) |
|
|
|
(path font-atlas-out > pixel-buffer)))) |
|
|
|
(if (> (deref current-pixel) 128) |
|
|
|
(scope |
|
|
|
(each-in-range 3 component |
|
|
|
(set (at component current-pixel-out) 255)) |
|
|
|
(set (at 3 current-pixel-out) 0)) |
|
|
|
;; Full alpha for empty pixels |
|
|
|
(set (at 3 current-pixel-out) 255)))) |
|
|
|
|
|
|
|
;; Wrapping happens after we know what the next glyph's dimensions are |
|
|
|
(set atlas-write-x (+ atlas-write-x num-columns)))) |
|
|
|
|
|
|
|
(return 0)) |
|
|
|
|
|
|
|
(defun main (&return int) |
|
|
|
(data-bundle-load-all-resources) |
|
|
|
|
|
|
|
(SDL_GL_SetAttribute SDL_GL_CONTEXT_MAJOR_VERSION 4) |
|
|
|
(SDL_GL_SetAttribute SDL_GL_CONTEXT_MINOR_VERSION 6) |
|
|
|
(SDL_SetHint SDL_HINT_RENDER_VSYNC "1") |
|
|
@ -38,6 +174,26 @@ |
|
|
|
(return 1)) |
|
|
|
(defer (SDL_DestroyRenderer renderer)) |
|
|
|
|
|
|
|
(var ubuntu-regular-font-atlas font-atlas (array 0)) |
|
|
|
(unless (= 0 (build-font-atlas (addr ubuntu-regular-font-atlas))) |
|
|
|
(return 1)) |
|
|
|
(defer (free-font-atlas (addr ubuntu-regular-font-atlas))) |
|
|
|
(var ubuntu-regular-texture (* SDL_Texture) null) |
|
|
|
(defer (when ubuntu-regular-texture (SDL_DestroyTexture ubuntu-regular-texture))) |
|
|
|
(scope |
|
|
|
(var font-surface (* SDL_Surface) |
|
|
|
(SDL_CreateRGBSurfaceFrom (field ubuntu-regular-font-atlas pixel-buffer) |
|
|
|
(field ubuntu-regular-font-atlas width) |
|
|
|
(field ubuntu-regular-font-atlas height) |
|
|
|
32 ;; bit depth of each pixel (RGBA) |
|
|
|
(* (field ubuntu-regular-font-atlas width) 4) ;; pitch (width of a row in bytes) |
|
|
|
0xff000000 0x00ff0000 0x0000ff00 0x000000ff)) |
|
|
|
(defer (SDL_FreeSurface font-surface)) ;; We don't need this after making the texture |
|
|
|
(set ubuntu-regular-texture (SDL_CreateTextureFromSurface renderer font-surface)) |
|
|
|
(unless ubuntu-regular-texture |
|
|
|
(sdl-print-error) |
|
|
|
(return 1))) |
|
|
|
|
|
|
|
;; current-key-states is owned by SDL, but we own last-frame-states |
|
|
|
(defer (dynarray-free (field s-key-states last-frame-states))) |
|
|
|
|
|
|
@ -53,6 +209,24 @@ |
|
|
|
(when (keybind-tapped (addr s-quit-keybind) (addr s-key-states)) |
|
|
|
(set exit-reason "Quit keybind pressed")) |
|
|
|
|
|
|
|
(SDL_SetRenderDrawColor renderer 85 85 85 255) |
|
|
|
(SDL_RenderClear renderer) |
|
|
|
|
|
|
|
(scope |
|
|
|
(var source-rectangle SDL_Rect |
|
|
|
(array 0 0 |
|
|
|
(field ubuntu-regular-font-atlas width) |
|
|
|
(field ubuntu-regular-font-atlas height))) |
|
|
|
(var destination-rectangle SDL_Rect |
|
|
|
(array 0 0 |
|
|
|
(field ubuntu-regular-font-atlas width) |
|
|
|
(field ubuntu-regular-font-atlas height))) |
|
|
|
(unless (= 0 (SDL_RenderCopy renderer ubuntu-regular-texture |
|
|
|
(addr source-rectangle) (addr destination-rectangle))) |
|
|
|
(sdl-print-error) |
|
|
|
(set exit-reason "SDL failed to render font atlas"))) |
|
|
|
|
|
|
|
(SDL_RenderPresent renderer) |
|
|
|
(SDL_UpdateWindowSurface window) |
|
|
|
|
|
|
|
(dynarray-set-length (field s-key-states last-frame-states) num-keys) |
|
|
|