1 ! Copyright (C) 2005, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien alien.accessors alien.c-types arrays io kernel libc
4 math math.vectors namespaces opengl opengl.gl assocs
5 sequences io.files io.styles continuations freetype
6 ui.gadgets.worlds ui.render ui.backend byte-arrays accessors
7 locals specialized-arrays.direct.uchar ;
10 TUPLE: freetype-renderer ;
14 : freetype-error ( n -- )
15 zero? [ "FreeType error" throw ] unless ;
19 : init-freetype ( -- )
21 f <void*> dup FT_Init_FreeType freetype-error
23 H{ } clone open-fonts set
26 : freetype ( -- alien )
27 \ freetype get-global expired? [ init-freetype ] when
28 \ freetype get-global ;
30 TUPLE: font < identity-tuple
31 ascent descent height handle widths ;
33 M: font hashcode* drop font hashcode* ;
35 : close-font ( font -- ) handle>> FT_Done_Face ;
37 : close-freetype ( -- )
39 open-fonts [ [ drop close-font ] assoc-each f ] change
40 freetype [ FT_Done_FreeType f ] change
43 M: freetype-renderer free-fonts ( world -- )
44 [ handle>> select-gl-context ]
45 [ fonts>> [ nip second free-sprites ] assoc-each ] bi ;
47 : ttf-name ( font style -- name )
49 { { "monospace" plain } "VeraMono" }
50 { { "monospace" bold } "VeraMoBd" }
51 { { "monospace" bold-italic } "VeraMoBI" }
52 { { "monospace" italic } "VeraMoIt" }
53 { { "sans-serif" plain } "Vera" }
54 { { "sans-serif" bold } "VeraBd" }
55 { { "sans-serif" bold-italic } "VeraBI" }
56 { { "sans-serif" italic } "VeraIt" }
57 { { "serif" plain } "VeraSe" }
58 { { "serif" bold } "VeraSeBd" }
59 { { "serif" bold-italic } "VeraBI" }
60 { { "serif" italic } "VeraIt" }
63 : ttf-path ( name -- string )
64 "resource:fonts/" ".ttf" surround ;
66 : (open-face) ( path length -- face )
67 #! We use FT_New_Memory_Face, not FT_New_Face, since
68 #! FT_New_Face only takes an ASCII path name and causes
69 #! problems on localized versions of Windows
70 [ freetype ] 2dip 0 f <void*> [
71 FT_New_Memory_Face freetype-error
74 : open-face ( font style -- face )
75 ttf-name ttf-path malloc-file-contents (open-face) ;
81 : ft-floor -6 shift ; inline
83 : ft-ceil 63 + -64 bitand -6 shift ; inline
85 : font-units>pixels ( n font -- n )
86 face-size face-size-y-scale FT_MulFix ;
88 : init-ascent ( font face -- font )
89 dup face-y-max swap font-units>pixels >>ascent ; inline
91 : init-descent ( font face -- font )
92 dup face-y-min swap font-units>pixels >>descent ; inline
94 : init-font ( font -- font )
95 dup handle>> init-ascent
96 dup handle>> init-descent
97 dup [ ascent>> ] [ descent>> ] bi - ft-ceil >>height ; inline
99 : set-char-size ( open-font size -- open-font )
100 [ dup handle>> 0 ] dip
101 6 shift dpi get-global dup FT_Set_Char_Size freetype-error ;
103 : <font> ( font -- open-font )
106 over first2 open-face >>handle
107 swap third set-char-size
110 M: freetype-renderer open-font ( font -- open-font )
111 freetype drop open-fonts get [ <font> ] cache ;
113 : load-glyph ( font char -- glyph )
114 [ handle>> dup ] dip 0 FT_Load_Char
115 freetype-error face-glyph ;
117 : char-width ( open-font char -- w )
119 dupd load-glyph glyph-hori-advance ft-ceil
122 M: freetype-renderer string-width ( open-font string -- w )
123 [ 0 ] 2dip [ char-width + ] with each ;
125 M: freetype-renderer string-height ( open-font string -- h )
128 : glyph-size ( glyph -- dim )
129 dup glyph-hori-advance ft-ceil
130 swap glyph-height ft-ceil 2array ;
132 : render-glyph ( font char -- bitmap )
134 FT_RENDER_MODE_NORMAL FT_Render_Glyph freetype-error ;
136 :: copy-pixel ( i j bitmap texture -- i j )
137 255 j texture set-nth
138 i bitmap nth j 1 + texture set-nth
141 :: (copy-row) ( i j bitmap texture end -- )
143 i j bitmap texture copy-pixel
144 bitmap texture end (copy-row)
145 ] when ; inline recursive
147 :: copy-row ( i j bitmap texture width width2 -- i j )
148 i j bitmap texture i width + (copy-row)
152 :: copy-bitmap ( glyph texture -- )
153 [let* | bitmap [ glyph glyph-bitmap-buffer ]
154 rows [ glyph glyph-bitmap-rows ]
155 width [ glyph glyph-bitmap-width ]
156 width2 [ width next-power-of-2 2 * ] |
158 [let | bitmap' [ bitmap rows width * <direct-uchar-array> ] |
160 rows [ bitmap' texture width width2 copy-row ] times
166 : bitmap>texture ( glyph sprite -- id )
167 tuck sprite-size2 * 2 * <byte-array>
168 [ copy-bitmap ] keep gray-texture ;
170 : glyph-texture-loc ( glyph font -- loc )
171 [ drop glyph-hori-bearing-x ft-floor ]
172 [ ascent>> swap glyph-hori-bearing-y - ft-floor ]
175 : glyph-texture-size ( glyph -- dim )
176 [ glyph-bitmap-width next-power-of-2 ]
177 [ glyph-bitmap-rows next-power-of-2 ]
180 : <char-sprite> ( open-font char -- sprite )
181 over [ render-glyph dup ] dip glyph-texture-loc
182 over glyph-size pick glyph-texture-size <sprite>
183 [ bitmap>texture ] keep [ init-sprite ] keep ;
185 :: char-sprite ( open-font sprites char -- sprite )
186 char sprites [ open-font swap <char-sprite> ] cache ;
188 : draw-char ( open-font sprites char loc -- )
191 char-sprite dlist>> glCallList
194 : char-widths ( open-font string -- widths )
195 [ char-width ] with { } map-as ;
197 : scan-sums ( seq -- seq' )
198 0 [ + ] accumulate nip ;
200 :: (draw-string) ( open-font sprites string loc -- )
203 string open-font string char-widths scan-sums [
204 [ open-font sprites ] 2dip draw-char
209 : font-sprites ( font world -- open-font sprites )
210 fonts>> [ open-font H{ } clone 2array ] cache first2 ;
212 M: freetype-renderer draw-string ( font string loc -- )
213 [ world get font-sprites ] 2dip (draw-string) ;
215 : run-char-widths ( open-font string -- widths )
216 char-widths [ scan-sums ] [ 2 v/n ] bi v+ ;
218 M: freetype-renderer x>offset ( x open-font string -- n )
219 [ run-char-widths [ <= ] with find drop ] keep swap
222 T{ freetype-renderer } font-renderer set-global