summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Thompson <dthompson2@worcester.edu>2017-01-24 20:16:08 -0500
committerDavid Thompson <dthompson2@worcester.edu>2017-01-24 21:25:20 -0500
commit233d13ca4af2fb7627926f160b9c42638ad7b333 (patch)
treeea4934154ad03d37a2ec297d3c99d2fc6a7c3b20
parentc36193e84bb4ab93e1cacf37e010d4e484e6ce63 (diff)
render: Add bitmap font support.
* chickadee/render/font.scm: New file. * Makefile.am (SOURCES): Add it. * examples/text.scm: New file. * examples/fonts/AUTHORS: New file. * examples/fonts/good_neighbors_starling.png: New file. * examples/fonts/good_neighbors_starling.xml: New file.
-rw-r--r--Makefile.am1
-rw-r--r--chickadee/render/font.scm191
-rw-r--r--examples/fonts/AUTHORS5
-rw-r--r--examples/fonts/good_neighbors_starling.pngbin0 -> 6659 bytes
-rw-r--r--examples/fonts/good_neighbors_starling.xml244
-rw-r--r--examples/text.scm26
6 files changed, 467 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 6dadc1b..8e65d44 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,6 +57,7 @@ SOURCES = \
chickadee/render/framebuffer.scm \
chickadee/render/shapes.scm \
chickadee/render/sprite.scm \
+ chickadee/render/font.scm \
chickadee/render.scm \
chickadee/window.scm \
chickadee.scm
diff --git a/chickadee/render/font.scm b/chickadee/render/font.scm
new file mode 100644
index 0000000..8f89b95
--- /dev/null
+++ b/chickadee/render/font.scm
@@ -0,0 +1,191 @@
+;;; Chickadee Game Toolkit
+;;; Copyright © 2017 David Thompson <davet@gnu.org>
+;;;
+;;; Chickadee is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published
+;;; by the Free Software Foundation, either version 3 of the License,
+;;; or (at your option) any later version.
+;;;
+;;; Chickadee is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Bitmap font rendering.
+;;
+;;; Code:
+
+(define-module (chickadee render font)
+ #:use-module (ice-9 format)
+ #:use-module (srfi srfi-9)
+ #:use-module (srfi srfi-9 gnu)
+ #:use-module (srfi srfi-11)
+ #:use-module (sxml xpath)
+ #:use-module (sxml simple)
+ #:use-module (chickadee math matrix)
+ #:use-module (chickadee math rect)
+ #:use-module (chickadee math vector)
+ #:use-module (chickadee render)
+ #:use-module (chickadee render shader)
+ #:use-module (chickadee render sprite)
+ #:use-module (chickadee render texture)
+ #:export (load-font
+ font?
+ font-face
+ font-line-height
+ font-bold?
+ font-italic?
+ draw-text))
+
+(define-record-type <font-char>
+ (make-font-char id texture region offset dimensions advance)
+ font-char?
+ (id font-char-id)
+ (texture font-char-texture)
+ (region font-char-region)
+ (offset font-char-offset)
+ (dimensions font-char-dimensions)
+ (advance font-char-advance))
+
+(define-record-type <font>
+ (make-font face bold? italic? line-height chars kerning)
+ font?
+ (face font-face)
+ (bold? font-bold?)
+ (italic? font-italic?)
+ (line-height font-line-height)
+ (chars font-chars)
+ (kerning font-kerning))
+
+(define (display-font font port)
+ (format port "#<font face: ~a line-height: ~d bold?: ~a italic?: ~a>"
+ (font-face font)
+ (font-line-height font)
+ (font-bold? font)
+ (font-italic? font)))
+
+(set-record-type-printer! <font> display-font)
+
+(define (load-font file)
+ "Load the Angel Code XML formatted font within FILE."
+ (define directory (dirname file))
+ (define* (attr tree name #:optional (parse identity))
+ (let ((result ((sxpath `(@ ,name *text*)) tree)))
+ (if (null? result)
+ #f
+ (parse (car result)))))
+ (define (parse-pages nodes)
+ (let ((table (make-hash-table)))
+ (for-each (lambda (node)
+ (let* ((id (attr node 'id string->number))
+ (file (attr node 'file))
+ (texture (load-image
+ (string-append directory "/" file))))
+ (hash-set! table id texture)))
+ nodes)
+ table))
+ (define (string->character s)
+ (integer->char (string->number s)))
+ (define (parse-chars nodes pages image-width image-height line-height)
+ (define (x->s x)
+ (exact->inexact (/ x image-width)))
+ (define (y->t y)
+ (exact->inexact (/ y image-height)))
+ (let ((table (make-hash-table)))
+ (for-each (lambda (node)
+ (let* ((id (attr node 'id string->character))
+ (width (attr node 'width string->number))
+ (height (attr node 'height string->number))
+ (x (attr node 'x string->number))
+ ;; Invert the y axis. Our origin is the
+ ;; bottom-left corner, not top-left.
+ (y (- image-height height
+ (attr node 'y string->number)))
+ (x-offset (attr node 'xoffset string->number))
+ (y-offset (- line-height height
+ (attr node 'yoffset string->number)))
+ (x-advance (attr node 'xadvance string->number))
+ (page (or (attr node 'page string->number) 0))
+ (region (make-rect (x->s x)
+ (y->t y)
+ (x->s width)
+ (y->t height)))
+ (char (make-font-char id
+ (hash-ref pages page)
+ region
+ (vec2 x-offset y-offset)
+ (vec2 width height)
+ (vec2 x-advance 0.0))))
+ (hash-set! table id char)))
+ nodes)
+ table))
+ (define (parse-kernings nodes)
+ (let ((table (make-hash-table)))
+ (for-each (lambda (node)
+ (let* ((first (attr node 'first string->character))
+ (second (attr node 'second string->character))
+ (x-offset (attr node 'amount string->number))
+ (inner-table (hash-ref table first)))
+ (if inner-table
+ (hash-set! inner-table second (vec2 x-offset 0.0))
+ (let ((inner-table (make-hash-table)))
+ (hash-set! inner-table second (vec2 x-offset 0.0))
+ (hash-set! table first inner-table)))))
+ nodes)
+ table))
+ (let* ((tree (call-with-input-file file xml->sxml))
+ (info ((sxpath '(font info)) tree))
+ (common ((sxpath '(font common)) tree))
+ (face (attr info 'face))
+ (bold? (attr info 'bold (const #t)))
+ (italic? (attr info 'italic (const #t)))
+ (line-height (attr common 'lineHeight string->number))
+ (image-width (attr common 'scaleW string->number))
+ (image-height (attr common 'scaleH string->number))
+ (pages (parse-pages ((sxpath '(font pages page)) tree)))
+ (chars (parse-chars ((sxpath '(font chars char)) tree)
+ pages
+ image-width
+ image-height
+ line-height))
+ (kernings (parse-kernings ((sxpath '(font kernings kerning)) tree))))
+ (make-font face bold? italic? line-height chars kernings)))
+
+(define (font-ref font char)
+ (hashv-ref (font-chars font) char))
+
+(define draw-text
+ (let ((p (vec2 0.0 0.0))
+ (rect (make-rect 0.0 0.0 0.0 0.0)))
+ (lambda* (font text position #:key scale rotation (blend-mode 'alpha))
+ "Draw the string TEXT with the first character starting at
+POSITION using FONT."
+ ;; TODO: Respect kerning.
+ (define (render-char c)
+ (let* ((char (font-ref font c))
+ (dimensions (font-char-dimensions char))
+ (offset (font-char-offset char)))
+ (set-rect-x! rect (+ (vec2-x p) (vec2-x offset)))
+ (set-rect-y! rect (+ (vec2-y p) (vec2-y offset)))
+ (set-rect-width! rect (vec2-x dimensions))
+ (set-rect-height! rect (vec2-y dimensions))
+ (draw-sprite (font-char-texture char)
+ rect
+ #:texture-region (font-char-region char)
+ #:scale scale
+ #:rotation rotation
+ #:blend-mode blend-mode)
+ ;; Move forward to where the next character needs to be drawn.
+ (set-vec2-x! p
+ (+ (vec2-x p)
+ (vec2-x
+ (font-char-advance char))))))
+ (vec2-copy! position p) ; initialize position
+ (with-batched-sprites
+ (string-for-each render-char text)))))
diff --git a/examples/fonts/AUTHORS b/examples/fonts/AUTHORS
new file mode 100644
index 0000000..13a3415
--- /dev/null
+++ b/examples/fonts/AUTHORS
@@ -0,0 +1,5 @@
+-*- org -*-
+
+* good_neighbors_starling.png, good_neighbors_starling.xml
+ By PROWNE and Clint Bellanger, CC0
+ http://opengameart.org/content/good-neighbors-pixel-font-starlingunity-version-updated
diff --git a/examples/fonts/good_neighbors_starling.png b/examples/fonts/good_neighbors_starling.png
new file mode 100644
index 0000000..74197a6
--- /dev/null
+++ b/examples/fonts/good_neighbors_starling.png
Binary files differ
diff --git a/examples/fonts/good_neighbors_starling.xml b/examples/fonts/good_neighbors_starling.xml
new file mode 100644
index 0000000..0a7afde
--- /dev/null
+++ b/examples/fonts/good_neighbors_starling.xml
@@ -0,0 +1,244 @@
+<font>
+ <info face="GoodNeighbors" size="16" />
+ <common lineHeight="16" scaleW="167" scaleH="168" pages="1" />
+ <pages>
+ <page id="0" file="good_neighbors_starling.png" />
+ </pages>
+ <chars count="233">
+ <char id="33" x="153" y="26" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- ! -->
+ <char id="34" x="82" y="32" width="7" height="7" xoffset="0" yoffset="4" xadvance="6" /><!-- " -->
+ <char id="35" x="24" y="77" width="10" height="10" xoffset="0" yoffset="5" xadvance="9" /><!-- # -->
+ <char id="36" x="24" y="88" width="10" height="14" xoffset="0" yoffset="3" xadvance="9" /><!-- $ -->
+ <char id="37" x="12" y="124" width="11" height="12" xoffset="0" yoffset="4" xadvance="10" /><!-- % -->
+ <char id="38" x="0" y="146" width="11" height="12" xoffset="0" yoffset="4" xadvance="10" /><!-- & -->
+ <char id="39" x="45" y="136" width="4" height="7" xoffset="0" yoffset="4" xadvance="3" /><!-- ' -->
+ <char id="40" x="160" y="26" width="6" height="14" xoffset="0" yoffset="3" xadvance="5" /><!-- ( -->
+ <char id="41" x="160" y="41" width="6" height="14" xoffset="0" yoffset="3" xadvance="5" /><!-- ) -->
+ <char id="42" x="24" y="126" width="10" height="11" xoffset="0" yoffset="3" xadvance="9" /><!-- * -->
+ <char id="43" x="126" y="156" width="8" height="9" xoffset="0" yoffset="6" xadvance="7" /><!-- + -->
+ <char id="44" x="135" y="160" width="4" height="7" xoffset="0" yoffset="11" xadvance="3" /><!-- , -->
+ <char id="45" x="0" y="160" width="9" height="5" xoffset="0" yoffset="8" xadvance="8" /><!-- - -->
+ <char id="46" x="43" y="161" width="4" height="5" xoffset="0" yoffset="11" xadvance="3" /><!-- . -->
+ <char id="47" x="144" y="13" width="8" height="14" xoffset="0" yoffset="3" xadvance="7" /><!-- / -->
+ <char id="48" x="136" y="0" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 0 -->
+ <char id="49" x="160" y="13" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- 1 -->
+ <char id="50" x="144" y="54" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 2 -->
+ <char id="51" x="144" y="80" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 3 -->
+ <char id="52" x="45" y="26" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- 4 -->
+ <char id="53" x="135" y="78" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 5 -->
+ <char id="54" x="144" y="28" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 6 -->
+ <char id="55" x="144" y="41" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 7 -->
+ <char id="56" x="144" y="93" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 8 -->
+ <char id="57" x="144" y="132" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- 9 -->
+ <char id="58" x="160" y="158" width="4" height="8" xoffset="0" yoffset="7" xadvance="3" /><!-- : -->
+ <char id="59" x="161" y="0" width="4" height="10" xoffset="0" yoffset="8" xadvance="3" /><!-- ; -->
+ <char id="60" x="44" y="145" width="9" height="14" xoffset="0" yoffset="3" xadvance="8" /><!-- < -->
+ <char id="61" x="117" y="159" width="7" height="8" xoffset="0" yoffset="7" xadvance="6" /><!-- = -->
+ <char id="62" x="35" y="81" width="9" height="14" xoffset="0" yoffset="3" xadvance="8" /><!-- > -->
+ <char id="63" x="126" y="89" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ? -->
+ <char id="64" x="13" y="86" width="10" height="12" xoffset="0" yoffset="4" xadvance="9" /><!-- @ -->
+ <char id="65" x="144" y="119" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- A -->
+ <char id="66" x="144" y="106" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- B -->
+ <char id="67" x="144" y="67" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- C -->
+ <char id="68" x="36" y="0" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- D -->
+ <char id="69" x="135" y="13" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- E -->
+ <char id="70" x="127" y="0" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- F -->
+ <char id="71" x="126" y="117" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- G -->
+ <char id="72" x="135" y="130" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- H -->
+ <char id="73" x="153" y="67" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- I -->
+ <char id="74" x="35" y="13" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- J -->
+ <char id="75" x="135" y="91" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- K -->
+ <char id="76" x="135" y="143" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- L -->
+ <char id="77" x="13" y="46" width="10" height="12" xoffset="0" yoffset="4" xadvance="9" /><!-- M -->
+ <char id="78" x="35" y="119" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- N -->
+ <char id="79" x="135" y="117" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- O -->
+ <char id="80" x="135" y="104" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- P -->
+ <char id="81" x="45" y="52" width="9" height="13" xoffset="0" yoffset="4" xadvance="8" /><!-- Q -->
+ <char id="82" x="34" y="148" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- R -->
+ <char id="83" x="135" y="65" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- S -->
+ <char id="84" x="135" y="52" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- T -->
+ <char id="85" x="135" y="39" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- U -->
+ <char id="86" x="135" y="26" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- V -->
+ <char id="87" x="24" y="113" width="10" height="12" xoffset="0" yoffset="4" xadvance="9" /><!-- W -->
+ <char id="88" x="26" y="0" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- X -->
+ <char id="89" x="126" y="143" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Y -->
+ <char id="90" x="126" y="130" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Z -->
+ <char id="91" x="153" y="109" width="6" height="14" xoffset="0" yoffset="3" xadvance="5" /><!-- [ -->
+ <char id="92" x="126" y="102" width="8" height="14" xoffset="0" yoffset="3" xadvance="7" /><!-- \ -->
+ <char id="93" x="153" y="39" width="6" height="14" xoffset="0" yoffset="3" xadvance="5" /><!-- ] -->
+ <char id="94" x="0" y="124" width="11" height="8" xoffset="0" yoffset="3" xadvance="10" /><!-- ^ -->
+ <char id="95" x="34" y="161" width="8" height="5" xoffset="0" yoffset="12" xadvance="7" /><!-- _ -->
+ <char id="96" x="127" y="13" width="6" height="6" xoffset="0" yoffset="4" xadvance="5" /><!-- ` -->
+ <char id="97" x="126" y="56" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- a -->
+ <char id="98" x="126" y="43" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- b -->
+ <char id="99" x="126" y="33" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- c -->
+ <char id="100" x="126" y="20" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- d -->
+ <char id="101" x="118" y="10" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- e -->
+ <char id="102" x="145" y="0" width="7" height="12" xoffset="0" yoffset="4" xadvance="6" /><!-- f -->
+ <char id="103" x="117" y="146" width="8" height="12" xoffset="0" yoffset="7" xadvance="7" /><!-- g -->
+ <char id="104" x="117" y="133" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- h -->
+ <char id="105" x="153" y="96" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- i -->
+ <char id="106" x="153" y="80" width="6" height="15" xoffset="0" yoffset="4" xadvance="5" /><!-- j -->
+ <char id="107" x="117" y="94" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- k -->
+ <char id="108" x="160" y="130" width="5" height="12" xoffset="0" yoffset="4" xadvance="4" /><!-- l -->
+ <char id="109" x="24" y="67" width="10" height="9" xoffset="0" yoffset="7" xadvance="9" /><!-- m -->
+ <char id="110" x="117" y="61" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- n -->
+ <char id="111" x="117" y="51" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- o -->
+ <char id="112" x="117" y="38" width="8" height="12" xoffset="0" yoffset="7" xadvance="7" /><!-- p -->
+ <char id="113" x="35" y="26" width="9" height="12" xoffset="0" yoffset="7" xadvance="8" /><!-- q -->
+ <char id="114" x="109" y="12" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- r -->
+ <char id="115" x="108" y="157" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- s -->
+ <char id="116" x="109" y="0" width="8" height="11" xoffset="0" yoffset="5" xadvance="7" /><!-- t -->
+ <char id="117" x="108" y="147" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- u -->
+ <char id="118" x="108" y="137" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- v -->
+ <char id="119" x="24" y="103" width="10" height="9" xoffset="0" yoffset="7" xadvance="9" /><!-- w -->
+ <char id="120" x="108" y="117" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- x -->
+ <char id="121" x="108" y="104" width="8" height="12" xoffset="0" yoffset="7" xadvance="7" /><!-- y -->
+ <char id="122" x="108" y="94" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- z -->
+ <char id="123" x="144" y="145" width="7" height="14" xoffset="0" yoffset="3" xadvance="6" /><!-- { -->
+ <char id="124" x="160" y="143" width="4" height="14" xoffset="0" yoffset="3" xadvance="3" /><!-- | -->
+ <char id="125" x="152" y="145" width="7" height="14" xoffset="0" yoffset="3" xadvance="6" /><!-- } -->
+ <char id="126" x="10" y="160" width="9" height="6" xoffset="0" yoffset="4" xadvance="8" /><!-- ~ -->
+ <char id="1040" x="108" y="39" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- А -->
+ <char id="1041" x="108" y="26" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Б -->
+ <char id="1042" x="100" y="13" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- В -->
+ <char id="1043" x="100" y="0" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Г -->
+ <char id="1044" x="13" y="59" width="10" height="13" xoffset="0" yoffset="4" xadvance="9" /><!-- Д -->
+ <char id="1045" x="99" y="136" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Е -->
+ <char id="1025" x="99" y="120" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ё -->
+ <char id="1046" x="0" y="27" width="12" height="12" xoffset="0" yoffset="4" xadvance="11" /><!-- Ж -->
+ <char id="1047" x="99" y="94" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- З -->
+ <char id="1048" x="35" y="39" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- И -->
+ <char id="1049" x="35" y="52" width="9" height="15" xoffset="0" yoffset="1" xadvance="8" /><!-- Й -->
+ <char id="1050" x="99" y="65" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- К -->
+ <char id="1051" x="35" y="68" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- Л -->
+ <char id="1052" x="13" y="73" width="10" height="12" xoffset="0" yoffset="4" xadvance="9" /><!-- М -->
+ <char id="1053" x="99" y="26" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Н -->
+ <char id="1054" x="91" y="13" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- О -->
+ <char id="1055" x="91" y="0" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- П -->
+ <char id="1056" x="90" y="145" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Р -->
+ <char id="1057" x="90" y="132" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- С -->
+ <char id="1058" x="90" y="119" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Т -->
+ <char id="1059" x="126" y="76" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- У -->
+ <char id="1060" x="0" y="14" width="12" height="12" xoffset="0" yoffset="4" xadvance="11" /><!-- Ф -->
+ <char id="1061" x="35" y="132" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- Х -->
+ <char id="1062" x="13" y="99" width="10" height="13" xoffset="0" yoffset="4" xadvance="9" /><!-- Ц -->
+ <char id="1063" x="90" y="48" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Ч -->
+ <char id="1064" x="0" y="40" width="12" height="12" xoffset="0" yoffset="4" xadvance="11" /><!-- Ш -->
+ <char id="1065" x="0" y="0" width="14" height="13" xoffset="0" yoffset="4" xadvance="13" /><!-- Щ -->
+ <char id="1066" x="15" y="0" width="10" height="12" xoffset="0" yoffset="4" xadvance="9" /><!-- Ъ -->
+ <char id="1067" x="0" y="133" width="11" height="12" xoffset="0" yoffset="4" xadvance="10" /><!-- Ы -->
+ <char id="1068" x="81" y="128" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Ь -->
+ <char id="1069" x="81" y="115" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Э -->
+ <char id="1070" x="12" y="137" width="11" height="12" xoffset="0" yoffset="4" xadvance="10" /><!-- Ю -->
+ <char id="1071" x="45" y="13" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- Я -->
+ <char id="1072" x="81" y="76" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- а -->
+ <char id="1073" x="81" y="62" width="8" height="13" xoffset="0" yoffset="3" xadvance="7" /><!-- б -->
+ <char id="1074" x="81" y="52" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- в -->
+ <char id="1075" x="81" y="42" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- г -->
+ <char id="1076" x="13" y="113" width="10" height="9" xoffset="0" yoffset="7" xadvance="9" /><!-- д -->
+ <char id="1077" x="72" y="157" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- е -->
+ <char id="1105" x="73" y="16" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ё -->
+ <char id="1078" x="24" y="24" width="10" height="9" xoffset="0" yoffset="7" xadvance="9" /><!-- ж -->
+ <char id="1079" x="72" y="147" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- з -->
+ <char id="1080" x="25" y="13" width="9" height="9" xoffset="0" yoffset="7" xadvance="8" /><!-- и -->
+ <char id="1081" x="35" y="96" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- й -->
+ <char id="1082" x="108" y="127" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- к -->
+ <char id="1083" x="35" y="109" width="9" height="9" xoffset="0" yoffset="7" xadvance="8" /><!-- л -->
+ <char id="1084" x="24" y="34" width="10" height="9" xoffset="0" yoffset="7" xadvance="9" /><!-- м -->
+ <char id="1085" x="90" y="158" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- н -->
+ <char id="1086" x="117" y="123" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- о -->
+ <char id="1087" x="117" y="84" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- п -->
+ <char id="1088" x="117" y="71" width="8" height="12" xoffset="0" yoffset="7" xadvance="7" /><!-- р -->
+ <char id="1089" x="81" y="157" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- с -->
+ <char id="1090" x="126" y="66" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- т -->
+ <char id="1091" x="63" y="142" width="8" height="12" xoffset="0" yoffset="7" xadvance="7" /><!-- у -->
+ <char id="1092" x="24" y="54" width="10" height="12" xoffset="0" yoffset="7" xadvance="9" /><!-- ф -->
+ <char id="1093" x="118" y="0" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- х -->
+ <char id="1094" x="13" y="35" width="10" height="10" xoffset="0" yoffset="7" xadvance="9" /><!-- ц -->
+ <char id="1095" x="63" y="88" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- ч -->
+ <char id="1096" x="24" y="138" width="10" height="9" xoffset="0" yoffset="7" xadvance="9" /><!-- ш -->
+ <char id="1097" x="0" y="90" width="12" height="10" xoffset="0" yoffset="7" xadvance="11" /><!-- щ -->
+ <char id="1098" x="24" y="44" width="10" height="9" xoffset="0" yoffset="7" xadvance="9" /><!-- ъ -->
+ <char id="1099" x="12" y="150" width="11" height="9" xoffset="0" yoffset="7" xadvance="10" /><!-- ы -->
+ <char id="1100" x="55" y="23" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- ь -->
+ <char id="1101" x="55" y="13" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- э -->
+ <char id="1102" x="13" y="14" width="11" height="9" xoffset="0" yoffset="7" xadvance="10" /><!-- ю -->
+ <char id="1103" x="54" y="156" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- я -->
+ <char id="1028" x="72" y="134" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- Є -->
+ <char id="1030" x="153" y="13" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- І -->
+ <char id="1031" x="54" y="111" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ї -->
+ <char id="1038" x="63" y="98" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ў -->
+ <char id="1168" x="63" y="114" width="8" height="14" xoffset="0" yoffset="2" xadvance="7" /><!-- Ґ -->
+ <char id="1108" x="55" y="33" width="8" height="9" xoffset="0" yoffset="7" xadvance="7" /><!-- є -->
+ <char id="1110" x="153" y="54" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- і -->
+ <char id="1111" x="153" y="0" width="7" height="12" xoffset="0" yoffset="4" xadvance="6" /><!-- ї -->
+ <char id="1118" x="54" y="127" width="8" height="15" xoffset="0" yoffset="4" xadvance="7" /><!-- ў -->
+ <char id="1169" x="45" y="95" width="8" height="11" xoffset="0" yoffset="5" xadvance="7" /><!-- ґ -->
+ <char id="196" x="54" y="82" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ä -->
+ <char id="228" x="46" y="0" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ä -->
+ <char id="192" x="45" y="66" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- À -->
+ <char id="224" x="45" y="107" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- à -->
+ <char id="194" x="45" y="120" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Â -->
+ <char id="226" x="45" y="82" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- â -->
+ <char id="193" x="54" y="66" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Á -->
+ <char id="225" x="54" y="98" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- á -->
+ <char id="195" x="63" y="72" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ã -->
+ <char id="227" x="54" y="143" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ã -->
+ <char id="197" x="64" y="32" width="8" height="16" xoffset="0" yoffset="0" xadvance="7" /><!-- Å -->
+ <char id="229" x="72" y="49" width="8" height="13" xoffset="0" yoffset="3" xadvance="7" /><!-- å -->
+ <char id="198" x="0" y="77" width="12" height="12" xoffset="0" yoffset="4" xadvance="11" /><!-- Æ -->
+ <char id="230" x="0" y="114" width="12" height="9" xoffset="0" yoffset="7" xadvance="11" /><!-- æ -->
+ <char id="200" x="72" y="118" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- È -->
+ <char id="232" x="63" y="155" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- è -->
+ <char id="202" x="64" y="0" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ê -->
+ <char id="234" x="99" y="52" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ê -->
+ <char id="201" x="99" y="78" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- É -->
+ <char id="233" x="72" y="63" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- é -->
+ <char id="199" x="108" y="52" width="8" height="15" xoffset="0" yoffset="4" xadvance="7" /><!-- Ç -->
+ <char id="231" x="72" y="105" width="8" height="12" xoffset="0" yoffset="7" xadvance="7" /><!-- ç -->
+ <char id="286" x="55" y="43" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ğ -->
+ <char id="287" x="82" y="16" width="8" height="15" xoffset="0" yoffset="4" xadvance="7" /><!-- ğ -->
+ <char id="206" x="160" y="56" width="6" height="15" xoffset="0" yoffset="1" xadvance="5" /><!-- Î -->
+ <char id="238" x="160" y="104" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- î -->
+ <char id="205" x="160" y="88" width="6" height="15" xoffset="0" yoffset="1" xadvance="5" /><!-- Í -->
+ <char id="237" x="160" y="117" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- í -->
+ <char id="304" x="160" y="72" width="6" height="15" xoffset="0" yoffset="1" xadvance="5" /><!-- İ -->
+ <char id="305" x="64" y="49" width="6" height="9" xoffset="0" yoffset="7" xadvance="5" /><!-- ı -->
+ <char id="209" x="24" y="148" width="9" height="16" xoffset="0" yoffset="0" xadvance="8" /><!-- Ñ -->
+ <char id="241" x="63" y="129" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ñ -->
+ <char id="214" x="64" y="16" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ö -->
+ <char id="246" x="108" y="81" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ö -->
+ <char id="210" x="73" y="0" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ò -->
+ <char id="242" x="73" y="29" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ò -->
+ <char id="212" x="82" y="0" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ô -->
+ <char id="244" x="90" y="61" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ô -->
+ <char id="211" x="90" y="90" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ó -->
+ <char id="243" x="99" y="39" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ó -->
+ <char id="213" x="99" y="149" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Õ -->
+ <char id="245" x="108" y="68" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- õ -->
+ <char id="338" x="0" y="101" width="12" height="12" xoffset="0" yoffset="4" xadvance="11" /><!-- Œ -->
+ <char id="339" x="0" y="67" width="12" height="9" xoffset="0" yoffset="7" xadvance="11" /><!-- œ -->
+ <char id="216" x="0" y="53" width="12" height="13" xoffset="0" yoffset="3" xadvance="11" /><!-- Ø -->
+ <char id="248" x="13" y="24" width="10" height="10" xoffset="0" yoffset="6" xadvance="9" /><!-- ø -->
+ <char id="350" x="117" y="107" width="8" height="15" xoffset="0" yoffset="4" xadvance="7" /><!-- Ş -->
+ <char id="351" x="90" y="106" width="8" height="12" xoffset="0" yoffset="7" xadvance="7" /><!-- ş -->
+ <char id="220" x="90" y="74" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ü -->
+ <char id="252" x="72" y="92" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ü -->
+ <char id="217" x="72" y="76" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ù -->
+ <char id="249" x="55" y="0" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ù -->
+ <char id="219" x="81" y="86" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Û -->
+ <char id="251" x="63" y="59" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- û -->
+ <char id="218" x="117" y="22" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ú -->
+ <char id="250" x="81" y="102" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ú -->
+ <char id="376" x="81" y="141" width="8" height="15" xoffset="0" yoffset="1" xadvance="7" /><!-- Ÿ -->
+ <char id="255" x="90" y="32" width="8" height="15" xoffset="0" yoffset="4" xadvance="7" /><!-- ÿ -->
+ <char id="191" x="99" y="107" width="8" height="12" xoffset="0" yoffset="4" xadvance="7" /><!-- ¿ -->
+ <char id="161" x="153" y="124" width="6" height="12" xoffset="0" yoffset="4" xadvance="5" /><!-- ¡ -->
+ <char id="223" x="45" y="39" width="9" height="12" xoffset="0" yoffset="4" xadvance="8" /><!-- ß -->
+ <char id="32" x="0" y="0" width="0" height="0" xoffset="0" yoffset="0" xadvance="4" /><!-- -->
+ <char id="9" x="0" y="0" width="0" height="0" xoffset="0" yoffset="0" xadvance="32" /><!-- -->
+ </chars>
+ <kernings count="0">
+ </kernings>
+</font>
diff --git a/examples/text.scm b/examples/text.scm
new file mode 100644
index 0000000..37ac22c
--- /dev/null
+++ b/examples/text.scm
@@ -0,0 +1,26 @@
+(use-modules (chickadee)
+ (chickadee math vector)
+ (chickadee render font))
+
+(define font #f)
+
+(define (load)
+ (set! font (load-font "fonts/good_neighbors_starling.xml")))
+
+(define (draw alpha)
+ (draw-text font "(draw-text font \"Hello, world!\" (vec2 100.0 200.0))"
+ (vec2 100.0 200.0))
+ (draw-text font "Chickadee is a game development toolkit for Guile Scheme."
+ (vec2 100.0 150.0))
+ (draw-text font "The quick brown fox jumps over the lazy dog"
+ (vec2 100.0 100.0)))
+
+(add-hook! load-hook load)
+(add-hook! draw-hook draw)
+(add-hook! quit-hook abort-game)
+(add-hook! key-press-hook
+ (lambda (key scan modifiers repeat?)
+ (when (eq? key 'q)
+ (abort-game))))
+
+(run-game)