1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Support for `TileSet`, `TileSetFont` and drawing text with `TextSprites`
20 # Efficiently retrieve tiles in a big texture
22 # Texture containing the tileset
31 # Number of columns of tiles in the texture
32 var nb_cols
: Int = (texture
.width
/ width
.to_f
).to_i
is lazy
34 # Number of rows of tiles in the texture
35 var nb_rows
: Int = (texture
.height
/ height
.to_f
).to_i
is lazy
37 # Cache of the subtextures of tiles
38 var subtextures
: Array[Texture] is lazy
do
39 var subtextures
= new Array[Texture]
40 for j
in [0..nb_rows
[ do
41 for i
in [0..nb_cols
[ do
42 subtextures
.add texture
.subtexture
(
43 i
.to_f
*width
.to_f
, j
.to_f
*height
.to_f
, width
.to_f
, height
.to_f
)
49 # Subtexture for the tile at `x, y`
51 # Require: `x < nb_cols and y < nb_rows`
52 fun [](x
,y
: Int): Texture
54 assert x
>= 0 and x
< nb_cols
and y
>= 0 and y
<= nb_rows
else print
"{x}x{y}<?{nb_cols}x{nb_rows}"
55 var idx
= x
+ y
* nb_cols
56 return subtextures
[idx
]
60 # A monospace bitmap font where glyphs are stored in a tileset
64 # Set the characters present in `texture`
66 # Last all characters from left to right, then top to bottom.
67 # Line skip `\n`, are ignored and space ' ' skips holes in the tileset.
68 fun chars
=(chars
: Text)
70 chars_cleaned
= chars
.replace
("\n", "")
73 # Character present in the texture, set by `chars=`
74 private var chars_cleaned
: Text is noautoinit
76 # Additional space to insert horizontally between characters
78 # A negative value may display overlapped tiles.
79 var hspace
: Numeric = 0.0 is writable
81 # Additional space to insert vertically between characters
83 # A negative value may display overlapped tiles.
84 var vspace
: Numeric = 0.0 is writable
86 # Line spacing modifier for `pld` and `plu`
88 # This value acts as multiplier to `height + vspace`.
89 # Defaults to 0.4, so a `pld` moves chars down by about half a line.
90 var partial_line_mod
: Numeric = 0.4 is writable
92 # The glyph/tile/texture associated to `char`
94 # Returns null if `char` is not in `chars`.
95 fun char
(char
: Char): nullable Texture
97 var i
= chars_cleaned
.index_of
(char
)
98 if i
== -1 then return null
102 # Distance between the beginning of a letter tile and the beginning of the next letter tile
103 fun advance
: Float do return width
.to_f
+ hspace
.to_f
105 # Distance between the beginning and the end of the longest line of `text`
106 fun text_width
(text
: Text): Numeric
108 var lines
= text
.split
('\n')
109 if lines
.is_empty
then return 0
112 for line
in lines
do longest
= longest
.max
(line
.length
)
114 return longest
.mul
(advance
)
117 # Distance between the top of the first line to the bottom of the last line in `text`
118 fun text_height
(text
: Text): Numeric
120 if text
.is_empty
then return 0
122 var n_lines
= text
.chars
.count
('\n')
123 return (n_lines
+1).mul
(height
.add
(vspace
)).sub
(vspace
)
127 # Manage a set of sprites to display some text
130 # Font used to draw text
131 var font
: TileSetFont
133 # Top left of the first character in UI coordinates
134 var anchor
: Point3d[Float]
136 # Last set of sprites generated to display `text=`
137 var sprites
= new Array[Sprite]
139 # Sprite set where to put created sprites
141 # Defaults to `app::ui_sprites`, but it could also be set to a
142 # `app::sprites` or a custom collection.
143 var target_sprite_set
: Set[Sprite] = app
.ui_sprites
is lazy
, writable
145 private var cached_text
: nullable Text = ""
148 fun text
: nullable Text do return cached_text
150 # Update the text displayed by inserting new sprites into `app.ui_sprites`
152 # Does not redraw if `text` has not changed.
153 fun text
=(text
: nullable Text)
155 # Don't redraw if text hasn't changed
156 if text
== cached_text
then return
159 # Clean up last used sprites
160 for s
in sprites
do if target_sprite_set
.has
(s
) then target_sprite_set
.remove s
163 if text
== null then return
166 var dx
= font
.advance
/2.0
167 var dy
= font
.hspace
.to_f
/2.0
170 dy
-= font
.height
.to_f
+ font
.vspace
.to_f
171 dx
= font
.advance
/2.0
173 else if c
== pld
then
174 dy
-= (font
.height
.to_f
+ font
.vspace
.to_f
) * font
.partial_line_mod
.to_f
176 else if c
== plu
then
177 dy
+= (font
.height
.to_f
+ font
.vspace
.to_f
) * font
.partial_line_mod
.to_f
179 else if c
.is_whitespace
then
184 var tex
= font
.char
(c
)
186 # Try to fallback to '?'
188 if tex
== null then continue
191 sprites
.add
new Sprite(tex
, anchor
.offset
(dx
, dy
, 0))
195 # Register sprites to be drawn by `app.ui_camera`
196 target_sprite_set
.add_all sprites
200 # Partial line forward (U+008B)
201 fun pld
: Char do return '\8b'
203 # Partial line backward (U+008C)
204 fun plu
: Char do return '\8c'