comparison modules/ui.tp @ 337:b8f721bde066

Add support for text elements in ui module
author Michael Pavone <pavone@retrodev.com>
date Fri, 03 Apr 2015 23:08:19 -0700
parents 79a14e41b79a
children d61b1f0e1936
comparison
equal deleted inserted replaced
336:2a0463c46913 337:b8f721bde066
16 object setProperty: name on: base to: (object sendMessage: name to: properties) 16 object setProperty: name on: base to: (object sendMessage: name to: properties)
17 } 17 }
18 } 18 }
19 base 19 base
20 } 20 }
21 _ft <- option none
22 _getFT <- {
23 _ft value: :ft { ft } none: {
24 ft <- freetype init
25 _ft <- option value: ft
26 ft
27 }
28 }
29
30 //TODO: Fix this for multi window
31 _atlasDict <- dict hash
32 _currentTex <- option none
33 _texX <- 0
34 _texY <- 0
35 _texRowHeight <- 0
36 _getFontAtlas <- :path _size renderer {
37 sizes <- _atlasDict get: path else: {
38 new <- dict hash
39 _atlasDict set: path new
40 new
41 }
42 _getTexture <- :width height {
43 _currentTex value: {
44 if: _texX + width > 2048 {
45 _texY <- _texY + _texRowHeight
46 _texRowHeight <- 0
47 _texX <- 0
48 }
49 if: _texY + height > 2048 {
50 _currentTex <- renderer createTexture: ((sdl pixelFormats) bgra8888) access: ((sdl textureAccess) streaming) width: 2048 height: 2048
51 _currentTex value: :tex {
52 tex blendMode!: ((sdl blendModes) blend)
53 } none: {}
54 _texX <- 0
55 _texY <- 0
56 _texRowHeight <- 0
57 }
58 if: _texRowHeight < height {
59 _texRowHeight <- height
60 }
61 } none: {
62 _currentTex <- renderer createTexture: ((sdl pixelFormats) bgra8888) access: ((sdl textureAccess) streaming) width: 2048 height: 2048
63 _currentTex value: :tex {
64 tex blendMode!: ((sdl blendModes) blend)
65 } none: {}
66 }
67 _currentTex
68 }
69 atlas <- sizes get: _size else: {
70 //TODO: Only load face once for all sizes
71 a <- ((_getFT: ) faceFromPath: path index: 0) value: :_face {
72 _textures <- #[]
73
74 _charmap <- _face charmap
75 //TODO: Feed in window system DPI or at least make this configurable
76 dpi <- 96
77 _face setCharSize: _size res: dpi
78 _pixelFactor <- ((_face unitsPerEm) f64) * 72.0 / (_size * (dpi f64))
79 _emUnits <- _face unitsPerEm
80 _glyphs <- dict hash
81 _getGlyph <- :codePoint face {
82 _glyphs get: codePoint else: {
83 flags <- freetype loadFlags
84 _charmap ifget: codePoint :_glyphIndex {
85 slot <- face glyphSlot
86 face loadGlyph: _glyphIndex flags: ((flags render) or (flags linearDesign) or (flags noHinting))
87 w <- slot bitmapWidth
88 h <- slot bitmapRows
89 _advX <- slot linearHoriAdvance
90 _advY <- slot linearVertAdvance
91 _texture <- _getTexture: w h
92 _rect <- sdl rect: _texX _texY size: w h
93 _texture value: :tex {
94 srcPitch <- slot bitmapPitch
95 srcBuffer <- slot bitmapData
96 tex lockRect: (sdl rect: _texX _texY size: w h ) with: :dstBuffer dstPitch {
97 srcY <- 0
98 dstY <- 0
99 while: { srcY < h } do: {
100 srcX <- 0
101 srcIdx <- srcY * srcPitch
102 dstIdx <- dstY * dstPitch
103 while: { srcX < w } do: {
104 //Set destination pixel to white with the source pixel as alpha
105 //This allows text color to be set using colorMod! on the texture
106 dstBuffer set: dstIdx (srcBuffer get: srcIdx)
107 dstBuffer set: (dstIdx + 1) 255u8
108 dstBuffer set: (dstIdx + 2) 255u8
109 dstBuffer set: (dstIdx + 3) 255u8
110
111 srcX <- srcX + 1
112 srcIdx <- srcIdx + 1
113 dstIdx <- dstIdx + 4
114 }
115
116 srcY <- srcY + 1
117 dstY <- dstY + 1
118 }
119 }
120 } none: {}
121 _texX <- _texX + w
122 _leftOff <- slot bitmapLeft
123 _topOff <- slot bitmapTop
124 g <- #{
125 advanceX <- { _advX }
126 advanceY <- { _advY }
127 atlasRect <- { _rect }
128
129 glyphIndex <- { _glyphIndex }
130 drawAt:color <- :x y :color {
131 _texture value: :tex {
132 tex colorMod!: color
133 tex copyRect: _rect To: (sdl rect: x+_leftOff y-_topOff size: (_rect w) (_rect h))
134 } none: {}
135 }
136 }
137 _glyphs set: codePoint g
138 g
139 } else: {
140 //get fallback
141 _getGlyph: 0u32 face
142 }
143 }
144 }
145
146 _getGlyphs <- :str face {
147 i <- 0
148 lines <- #[]
149 curline <- #[]
150 nl <- ("\n" byte: 0) uint32
151 while: { i < (str byte_length) } do: {
152 //TODO: Unicode
153 codePoint <- (str byte: i) uint32
154 if: codePoint = nl {
155 lines append: curline
156 curline <- #[]
157 } else: {
158 glyph <- _getGlyph: codePoint face
159 curline append: glyph
160 }
161 i <- i + 1
162 }
163 lines append: curline
164 lines
165 }
166 _iterateGlyphs:leading:using <- :str :leading :fun {
167 lines <- _getGlyphs: str _face
168 y <- 0.0
169 maxX <- 0.0
170 print: "Leading: " . leading . ", EM units: " . _emUnits . "\n"
171 leading <- leading * (_emUnits f64) / _size
172 foreach: lines :_ glyphs {
173 x <- 0.0
174 baseline <- y + (_emUnits f64)
175 foreach: glyphs :_ glyph {
176 fun: glyph x baseline
177 x <- x + ((glyph advanceX) f64)
178 //baseline <- baseline + ((glyph advanceY) f64)
179 //TODO: kerning
180 }
181 y <- y + leading
182 if: x > maxX {
183 maxX <- x
184 }
185 }
186 //convert font units into pixels
187 x <- (maxX / _pixelFactor + 0.5) truncInt32
188 y <- (y / _pixelFactor + 0.5) truncInt32
189 vec x: x y: y
190 }
191 option value: #{
192 stringSize:leading <- :str :leading {
193 _iterateGlyphs: str leading: leading using: :glyph x y {}
194 }
195
196 drawString:at:color:leading <- :str :xpos ypos :color :lead {
197 _iterateGlyphs: str leading: lead using: :glyph x y {
198 x <- ((x / _pixelFactor + 0.5) truncInt32) + xpos
199 y <- ((y / _pixelFactor + 0.5) truncInt32) + ypos
200 glyph drawAt: x y color: color
201 }
202 }
203 }
204 } none: {
205 option none
206 }
207 sizes set: _size a
208 a
209 }
210 }
21 #{ 211 #{
22 import: [ 212 import: [
23 r:g:b 213 r:g:b
24 r:g:b:a 214 r:g:b:a
25 ] from: sdl 215 ] from: sdl
26 _styles <- [] 216 _styles <- []
27 window <- :properties { 217 window <- :properties {
28 _wind <- option none 218 _wind <- option none
29 _renderer <- option none 219 _renderer <- option none
220
221
30 base <- #{ 222 base <- #{
31 title <- "Window" 223 title <- "Window"
32 width <- 640 224 width <- 640
33 height <- 480 225 height <- 480
34 x <- 0 226 x <- 0
48 } 240 }
49 } 241 }
50 } 242 }
51 243
52 layout <- { 244 layout <- {
53 yPos <- 0 245 _renderer value: :renderer {
54 xPos <- 0 246 yPos <- 0
55 rowMaxHeight <- 0 247 xPos <- 0
56 foreach: children :_ child { 248 rowMaxHeight <- 0
57 softMax <- (width - xPos) 249 foreach: children :_ child {
58 child softMaxWidth: softMax maxWidth: width maxHeight: (height - yPos) renderer: _renderer 250 softMax <- (width - xPos)
59 if: (child width) > softMax { 251 child softMaxWidth: softMax maxWidth: width maxHeight: (height - yPos) renderer: renderer
60 yPos <- yPos + rowMaxHeight 252 if: (child width) > softMax {
61 xPos <- 0 253 yPos <- yPos + rowMaxHeight
62 rowMaxHeight <- 0 254 xPos <- 0
63 } 255 rowMaxHeight <- 0
64 child x!: xPos 256 }
65 child y!: yPos 257 child x!: xPos
66 xPos <- xPos + (child width) 258 child y!: yPos
67 if: (child height) > rowMaxHeight { 259 xPos <- xPos + (child width)
68 rowMaxHeight <- (child height) 260 if: (child height) > rowMaxHeight {
69 } 261 rowMaxHeight <- (child height)
70 if: xPos >= width { 262 }
71 yPos <- yPos + rowMaxHeight 263 if: xPos >= width {
72 xPos <- 0 264 yPos <- yPos + rowMaxHeight
73 rowMaxHeight <- 0 265 xPos <- 0
74 } 266 rowMaxHeight <- 0
75 } 267 }
268 }
269 } none: {}
76 } 270 }
77 271
78 draw <- { 272 draw <- {
79 print: "Draw!\n" 273 print: "Draw!\n"
80 _renderer value: :renderer { 274 _renderer value: :renderer {
99 } 293 }
100 _applyProps: base properties 294 _applyProps: base properties
101 } 295 }
102 296
103 text <- :properties { 297 text <- :properties {
104 #{ 298 _fontSize <- 12.0
299 _leading <- 15.0
300 _explicitLeading <- false
301 _applyProps: #{
105 text <- "" 302 text <- ""
106 //TODO: replace this with font family and style once fontconfig is hooked up 303 //TODO: replace this with font family and style once fontconfig is hooked up
107 font <- "/usr/share/fonts/truetype/droid/DroidSans.ttf" 304 font <- "/usr/share/fonts/truetype/droid/DroidSans.ttf"
108 fontSize <- 12.0 305 fontSize <- { _fontSize }
306 fontSize! <- :newSize {
307 _fontSize <- newSize
308 if: (not: _explicitLeading) {
309 _leading <- newSize * 1.25
310 }
311 }
312 leading <- { _leading }
313 leading! <- :newLeading {
314 _explicitLeading <- true
315 _leading <- newLeading
316 }
317 color <- (ui r: 0u8 g: 0u8 b: 0u8)
109 width <- -1 318 width <- -1
110 height <- -1 319 height <- -1
111 x <- 0 320 x <- 0
112 y <- 0 321 y <- 0
113 322
114 softMaxWidth:maxWidth:maxHeight <- :softMax :maxWidth :maxHeight { 323 softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :renderer {
115 324 (_getFontAtlas: font fontSize renderer) value: :atlas {
116 } 325 //TODO: word wrap
117 } 326 bbox <- atlas stringSize: text leading: _leading
327 width <- bbox x
328 height <- bbox y
329 print: "Text: " . text . " has size: " . width . ", " . height . "\n"
330 } none: {
331 }
332 }
333
334 draw <- :renderer {
335 (_getFontAtlas: font fontSize renderer) value: :atlas {
336 print: "Drawing: " . text . " at " . x . ", " . y . "\n"
337 atlas drawString: text at: x y color: color leading: _leading
338 } none: {
339 }
340 }
341 } properties
118 } 342 }
119 343
120 image <- :properties { 344 image <- :properties {
121 _texture <- option none 345 _texture <- option none
122 _applyProps: #{ 346 _applyProps: #{
124 width <- -1 348 width <- -1
125 height <- -1 349 height <- -1
126 x <- 0 350 x <- 0
127 y <- 0 351 y <- 0
128 352
129 softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :_renderer { 353 softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :renderer {
130 _renderer value: :renderer { 354 _texture value: :_ {
355 } none: {
131 (sdl loadBMP: source) value: :surface { 356 (sdl loadBMP: source) value: :surface {
132 (surface asTexture: renderer) value: :texture { 357 (surface asTexture: renderer) value: :texture {
133 _texture <- option value: texture 358 _texture <- option value: texture
134 width <- texture width 359 width <- texture width
135 height <- texture height 360 height <- texture height
147 print: "Failed to load " . source . "\n" 372 print: "Failed to load " . source . "\n"
148 //Should this have some kind of placeholder as a fallback? 373 //Should this have some kind of placeholder as a fallback?
149 width <- 0 374 width <- 0
150 height <- 0 375 height <- 0
151 } 376 }
152 } none: {
153 } 377 }
154 } 378 }
155 379
156 draw <- :_ { 380 draw <- :_ {
157 _texture value: :texture { 381 _texture value: :texture {