1     object FontColor =
2         val black : u8 = 0
3         val blue : u8 = 1
4         val green : u8 = 2
5         val red : u8 = 3
6         val gray : u8 = 4
7         val light_gray : u8 = 5
8         let count : u8 = 6
9     
10    object TextMesh =
11        let palette = [Vector3.gray 0.1
12                       Vector3 0.1 0.3 0.8
13                       Vector3 0.1 0.5 0.1
14                       Vector3 0.7 0.12 0
15                       Vector3.gray 0.35
16                       Vector3.gray 0.5]
17    
18        val advance_char = 'A'
19    
20    type TextMeshMemory =
21        val memory : MeshMemory
22        val char_height : u32
23        val line_height : u32
24        val advance : u32
25        val margin : Margin
26        val width : u32
27        val height : u32
28    
29        def discard =
30            memory.discard
31    
32        is Discard
33    
34    type Font
35        def text_margin self =
36            let mut margin = self.margin divisor = 2.5
37            margin.down *= 20
38            margin
39    
40    let is_in_selection (position : TextPos
41                         maybe_selection : Option<(TextPos, TextPos)>) =
42        case maybe_selection of
43            None -> false
44            Some (from, to) -> position >= from && position < to
45    
46    module text_mesh
47    
48    def create (text : Slice<TextLine>
49                visible_up : u32
50                visible_down : u32
51                selection : Option<(TextPos, TextPos)>
52                font : Font) =
53        let space_width = font.space_width
54        let char_height = font.char_height
55        let rectangles = font.rectangles
56        let line_height = font.line_height
57        let font_width = font.memory.width
58        let font_height = font.memory.height
59        let font_height_rgba = font.memory_rgba.height
60        let margin = font.text_margin
61    
62        let quads = List.new
63        let mut x = margin.left as i32
64        let mut y = margin.up as i32
65        let mut width : u32 = 0
66        let mut maybe_prev_c : Option<Char> = None
67    
68        let skip_count = if visible_up < y as u32
69                         then 0
70                         else (visible_up - y as u32) / line_height
71    
72        let after_last_line_index =
73            if visible_down < margin.up
74            then 0
75            else (visible_down - margin.up) / line_height + 1
76                 |> min text.size as i32
77    
78        let mut line_index = skip_count
79        y += line_index * line_height |> as<i32>
80    
81        for l = line_index as i32 until after_last_line_index do
82            let line = text[l]
83            for i = 0 until line.length do
84                let char = line[i]
85                let c =
86                    let c = char.char
87                    if c == ' ' || c == '\n' || rectangles.contains c
88                    then c
89                    else Sys.unprintable_char
90    
91                let position = TextPos line_index i
92                let is_eol = c == '\n'
93                let color_index =
94                    if is_in_selection position selection
95                    then char.color + FontColor.count
96                    else char.color
97    
98                let (offset, char_width) =
99                    let prev_c = maybe_prev_c.unwrap_or ' '
100                   let offset = font.offset prev_c c
101                   let w = if c == ' ' || is_eol
102                           then space_width
103                           else rectangles[c].width
104   
105                   (offset, w)
106   
107               if not is_eol then
108                   x += offset
109   
110               if c <> ' ' && not is_eol then
111                   let rectangle = rectangles[c]
112                   let left = rectangle.left as f32 / font_width as f32
113                   let right = rectangle.right as f32 / font_width as f32
114                   let down = rectangle.down + color_index as u32 * font_height
115                              |> as<f32> / font_height_rgba as f32
116   
117                   let up = rectangle.up + color_index as u32 * font_height
118                            |> as<f32> / font_height_rgba as f32
119   
120                   let quad = Quad
121                       up_left = Vector3 x.as<f32> y.as<f32> 0
122                       up_right = Vector3 (x as f32 + rectangle.width as f32) y.as<f32> 0
123                       down_left = Vector3 x.as<f32> (y as f32 + rectangle.height as f32) 0
124                       down_right = Vector3
125                           x = x as f32 + rectangle.width as f32
126                           y = y as f32 + rectangle.height as f32
127                           z = 0
128   
129                       uv_up_left = Vector2 left down
130                       uv_up_right = Vector2 right down
131                       uv_down_left = Vector2 left up
132                       uv_down_right = Vector2 right up
133                       color = TextMesh.palette[char.color as u32]
134   
135                   quads.add quad
136   
137               if not is_eol then
138                   x += char_width as i32
139   
140               if x as u32 > width then
141                   width = x as u32
142   
143               maybe_prev_c = Some c
144   
145           x = margin.left as i32
146           y += line_height as i32
147           maybe_prev_c = None
148           line_index += 1
149   
150       width += margin.right
151       let memory = MeshMemory.from_quads quads.as_slice
152       let advance_char_offset =
153           font.offsets[(TextMesh.advance_char, TextMesh.advance_char)]
154   
155       assert advance_char_offset == 0
156       let advance = rectangles[TextMesh.advance_char].width
157       let height = margin.up + margin.down + (text.size - 1) * line_height + char_height
158   
159       TextMeshMemory =memory =char_height =line_height
160                      =advance =margin =width =height
161