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 # The glyph/tile/texture associated to `char`
88 # Returns null if `char` is not in `chars`.
89 fun char
(char
: Char): nullable Texture
91 var i
= chars_cleaned
.index_of
(char
)
92 if i
== -1 then return null
96 # Distance between the beginning of a letter tile and the beginning of the next letter tile
97 fun advance
: Float do return width
.to_f
+ hspace
.to_f
99 # Distance between the beginning and the end of the longest line of `text`
100 fun text_width
(text
: Text): Numeric
102 var lines
= text
.split
('\n')
103 if lines
.is_empty
then return 0
106 for line
in lines
do longest
= longest
.max
(line
.length
)
108 return longest
.mul
(advance
)
111 # Distance between the top of the first line to the bottom of the last line in `text`
112 fun text_height
(text
: Text): Numeric
114 if text
.is_empty
then return 0
116 var n_lines
= text
.chars
.count
('\n')
117 return (n_lines
+1).mul
(height
.add
(vspace
)).sub
(vspace
)
121 # Manage a set of sprites to display some text
124 # Font used to draw text
125 var font
: TileSetFont
127 # Top left of the first character in UI coordinates
128 var anchor
: Point3d[Float]
130 # Last set of sprites generated to display `text=`
131 var sprites
= new Array[Sprite]
133 # Sprite set where to put created sprites
135 # Defaults to `app::ui_sprites`, but it could also be set to a
136 # `app::sprites` or a custom collection.
137 var target_sprite_set
: Set[Sprite] = app
.ui_sprites
is lazy
, writable
139 private var cached_text
: nullable Text = ""
142 fun text
: nullable Text do return cached_text
144 # Update the text displayed by inserting new sprites into `app.ui_sprites`
146 # Does not redraw if `text` has not changed.
147 fun text
=(text
: nullable Text)
149 # Don't redraw if text hasn't changed
150 if text
== cached_text
then return
153 # Clean up last used sprites
154 for s
in sprites
do if target_sprite_set
.has
(s
) then target_sprite_set
.remove s
157 if text
== null then return
160 var dx
= font
.advance
/2.0
161 var dy
= font
.hspace
.to_f
/2.0
164 dy
-= font
.height
.to_f
+ font
.vspace
.to_f
165 dx
= font
.advance
/2.0
167 else if c
.is_whitespace
then
172 var tex
= font
.char
(c
)
174 # Try to fallback to '?'
176 if tex
== null then continue
179 sprites
.add
new Sprite(tex
, anchor
.offset
(dx
, dy
, 0))
183 # Register sprites to be drawn by `app.ui_camera`
184 target_sprite_set
.add_all sprites