# HG changeset patch # User Michael Pavone # Date 1428127699 25200 # Node ID b8f721bde066bce0fbba4a67744c8833e1a0bace # Parent 2a0463c46913b8c038a1f1d2b6a49df1b5cf64fc Add support for text elements in ui module diff -r 2a0463c46913 -r b8f721bde066 modules/ui.tp --- a/modules/ui.tp Fri Apr 03 23:07:06 2015 -0700 +++ b/modules/ui.tp Fri Apr 03 23:08:19 2015 -0700 @@ -18,6 +18,196 @@ } base } + _ft <- option none + _getFT <- { + _ft value: :ft { ft } none: { + ft <- freetype init + _ft <- option value: ft + ft + } + } + + //TODO: Fix this for multi window + _atlasDict <- dict hash + _currentTex <- option none + _texX <- 0 + _texY <- 0 + _texRowHeight <- 0 + _getFontAtlas <- :path _size renderer { + sizes <- _atlasDict get: path else: { + new <- dict hash + _atlasDict set: path new + new + } + _getTexture <- :width height { + _currentTex value: { + if: _texX + width > 2048 { + _texY <- _texY + _texRowHeight + _texRowHeight <- 0 + _texX <- 0 + } + if: _texY + height > 2048 { + _currentTex <- renderer createTexture: ((sdl pixelFormats) bgra8888) access: ((sdl textureAccess) streaming) width: 2048 height: 2048 + _currentTex value: :tex { + tex blendMode!: ((sdl blendModes) blend) + } none: {} + _texX <- 0 + _texY <- 0 + _texRowHeight <- 0 + } + if: _texRowHeight < height { + _texRowHeight <- height + } + } none: { + _currentTex <- renderer createTexture: ((sdl pixelFormats) bgra8888) access: ((sdl textureAccess) streaming) width: 2048 height: 2048 + _currentTex value: :tex { + tex blendMode!: ((sdl blendModes) blend) + } none: {} + } + _currentTex + } + atlas <- sizes get: _size else: { + //TODO: Only load face once for all sizes + a <- ((_getFT: ) faceFromPath: path index: 0) value: :_face { + _textures <- #[] + + _charmap <- _face charmap + //TODO: Feed in window system DPI or at least make this configurable + dpi <- 96 + _face setCharSize: _size res: dpi + _pixelFactor <- ((_face unitsPerEm) f64) * 72.0 / (_size * (dpi f64)) + _emUnits <- _face unitsPerEm + _glyphs <- dict hash + _getGlyph <- :codePoint face { + _glyphs get: codePoint else: { + flags <- freetype loadFlags + _charmap ifget: codePoint :_glyphIndex { + slot <- face glyphSlot + face loadGlyph: _glyphIndex flags: ((flags render) or (flags linearDesign) or (flags noHinting)) + w <- slot bitmapWidth + h <- slot bitmapRows + _advX <- slot linearHoriAdvance + _advY <- slot linearVertAdvance + _texture <- _getTexture: w h + _rect <- sdl rect: _texX _texY size: w h + _texture value: :tex { + srcPitch <- slot bitmapPitch + srcBuffer <- slot bitmapData + tex lockRect: (sdl rect: _texX _texY size: w h ) with: :dstBuffer dstPitch { + srcY <- 0 + dstY <- 0 + while: { srcY < h } do: { + srcX <- 0 + srcIdx <- srcY * srcPitch + dstIdx <- dstY * dstPitch + while: { srcX < w } do: { + //Set destination pixel to white with the source pixel as alpha + //This allows text color to be set using colorMod! on the texture + dstBuffer set: dstIdx (srcBuffer get: srcIdx) + dstBuffer set: (dstIdx + 1) 255u8 + dstBuffer set: (dstIdx + 2) 255u8 + dstBuffer set: (dstIdx + 3) 255u8 + + srcX <- srcX + 1 + srcIdx <- srcIdx + 1 + dstIdx <- dstIdx + 4 + } + + srcY <- srcY + 1 + dstY <- dstY + 1 + } + } + } none: {} + _texX <- _texX + w + _leftOff <- slot bitmapLeft + _topOff <- slot bitmapTop + g <- #{ + advanceX <- { _advX } + advanceY <- { _advY } + atlasRect <- { _rect } + + glyphIndex <- { _glyphIndex } + drawAt:color <- :x y :color { + _texture value: :tex { + tex colorMod!: color + tex copyRect: _rect To: (sdl rect: x+_leftOff y-_topOff size: (_rect w) (_rect h)) + } none: {} + } + } + _glyphs set: codePoint g + g + } else: { + //get fallback + _getGlyph: 0u32 face + } + } + } + + _getGlyphs <- :str face { + i <- 0 + lines <- #[] + curline <- #[] + nl <- ("\n" byte: 0) uint32 + while: { i < (str byte_length) } do: { + //TODO: Unicode + codePoint <- (str byte: i) uint32 + if: codePoint = nl { + lines append: curline + curline <- #[] + } else: { + glyph <- _getGlyph: codePoint face + curline append: glyph + } + i <- i + 1 + } + lines append: curline + lines + } + _iterateGlyphs:leading:using <- :str :leading :fun { + lines <- _getGlyphs: str _face + y <- 0.0 + maxX <- 0.0 + print: "Leading: " . leading . ", EM units: " . _emUnits . "\n" + leading <- leading * (_emUnits f64) / _size + foreach: lines :_ glyphs { + x <- 0.0 + baseline <- y + (_emUnits f64) + foreach: glyphs :_ glyph { + fun: glyph x baseline + x <- x + ((glyph advanceX) f64) + //baseline <- baseline + ((glyph advanceY) f64) + //TODO: kerning + } + y <- y + leading + if: x > maxX { + maxX <- x + } + } + //convert font units into pixels + x <- (maxX / _pixelFactor + 0.5) truncInt32 + y <- (y / _pixelFactor + 0.5) truncInt32 + vec x: x y: y + } + option value: #{ + stringSize:leading <- :str :leading { + _iterateGlyphs: str leading: leading using: :glyph x y {} + } + + drawString:at:color:leading <- :str :xpos ypos :color :lead { + _iterateGlyphs: str leading: lead using: :glyph x y { + x <- ((x / _pixelFactor + 0.5) truncInt32) + xpos + y <- ((y / _pixelFactor + 0.5) truncInt32) + ypos + glyph drawAt: x y color: color + } + } + } + } none: { + option none + } + sizes set: _size a + a + } + } #{ import: [ r:g:b @@ -27,6 +217,8 @@ window <- :properties { _wind <- option none _renderer <- option none + + base <- #{ title <- "Window" width <- 640 @@ -50,29 +242,31 @@ } layout <- { - yPos <- 0 - xPos <- 0 - rowMaxHeight <- 0 - foreach: children :_ child { - softMax <- (width - xPos) - child softMaxWidth: softMax maxWidth: width maxHeight: (height - yPos) renderer: _renderer - if: (child width) > softMax { - yPos <- yPos + rowMaxHeight - xPos <- 0 - rowMaxHeight <- 0 + _renderer value: :renderer { + yPos <- 0 + xPos <- 0 + rowMaxHeight <- 0 + foreach: children :_ child { + softMax <- (width - xPos) + child softMaxWidth: softMax maxWidth: width maxHeight: (height - yPos) renderer: renderer + if: (child width) > softMax { + yPos <- yPos + rowMaxHeight + xPos <- 0 + rowMaxHeight <- 0 + } + child x!: xPos + child y!: yPos + xPos <- xPos + (child width) + if: (child height) > rowMaxHeight { + rowMaxHeight <- (child height) + } + if: xPos >= width { + yPos <- yPos + rowMaxHeight + xPos <- 0 + rowMaxHeight <- 0 + } } - child x!: xPos - child y!: yPos - xPos <- xPos + (child width) - if: (child height) > rowMaxHeight { - rowMaxHeight <- (child height) - } - if: xPos >= width { - yPos <- yPos + rowMaxHeight - xPos <- 0 - rowMaxHeight <- 0 - } - } + } none: {} } draw <- { @@ -101,20 +295,50 @@ } text <- :properties { - #{ + _fontSize <- 12.0 + _leading <- 15.0 + _explicitLeading <- false + _applyProps: #{ text <- "" //TODO: replace this with font family and style once fontconfig is hooked up font <- "/usr/share/fonts/truetype/droid/DroidSans.ttf" - fontSize <- 12.0 + fontSize <- { _fontSize } + fontSize! <- :newSize { + _fontSize <- newSize + if: (not: _explicitLeading) { + _leading <- newSize * 1.25 + } + } + leading <- { _leading } + leading! <- :newLeading { + _explicitLeading <- true + _leading <- newLeading + } + color <- (ui r: 0u8 g: 0u8 b: 0u8) width <- -1 height <- -1 x <- 0 y <- 0 - softMaxWidth:maxWidth:maxHeight <- :softMax :maxWidth :maxHeight { - + softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :renderer { + (_getFontAtlas: font fontSize renderer) value: :atlas { + //TODO: word wrap + bbox <- atlas stringSize: text leading: _leading + width <- bbox x + height <- bbox y + print: "Text: " . text . " has size: " . width . ", " . height . "\n" + } none: { + } } - } + + draw <- :renderer { + (_getFontAtlas: font fontSize renderer) value: :atlas { + print: "Drawing: " . text . " at " . x . ", " . y . "\n" + atlas drawString: text at: x y color: color leading: _leading + } none: { + } + } + } properties } image <- :properties { @@ -126,8 +350,9 @@ x <- 0 y <- 0 - softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :_renderer { - _renderer value: :renderer { + softMaxWidth:maxWidth:maxHeight:renderer <- :softMax :maxWidth :maxHeight :renderer { + _texture value: :_ { + } none: { (sdl loadBMP: source) value: :surface { (surface asTexture: renderer) value: :texture { _texture <- option value: texture @@ -149,7 +374,6 @@ width <- 0 height <- 0 } - } none: { } } diff -r 2a0463c46913 -r b8f721bde066 samples/ui.tp --- a/samples/ui.tp Fri Apr 03 23:07:06 2015 -0700 +++ b/samples/ui.tp Fri Apr 03 23:08:19 2015 -0700 @@ -7,6 +7,9 @@ ui image: #{ source <- "944.bmp" } + ui text: #{ + text <- "The quick brown fox\njumps over the lazy dog." + } ] }