From c1651bd271dd59f88cdffb582658796f128d799d Mon Sep 17 00:00:00 2001 From: spaceface777 Date: Wed, 19 Aug 2020 07:10:42 +0200 Subject: [PATCH] gg: fixes and Android support (#6161) --- examples/2048/main.v | 6 ++-- examples/tetris/tetris.v | 4 +-- vlib/gg/gg.v | 16 ++++++---- vlib/gg/text_rendering.v | 69 +++++++++++++++++++++------------------- vlib/gx/text.v | 44 ++++++++++++++++++------- vlib/os/os_android.c.v | 30 +++++++++++++++++ vlib/sokol/sapp/sapp.v | 4 +++ vlib/v/parser/parser.v | 2 +- 8 files changed, 118 insertions(+), 57 deletions(-) create mode 100644 vlib/os/os_android.c.v diff --git a/examples/2048/main.v b/examples/2048/main.v index 795e046d0a..d185ee0e4b 100644 --- a/examples/2048/main.v +++ b/examples/2048/main.v @@ -34,7 +34,7 @@ const ( text: 'Points: ' pos: Pos{10, 5} cfg: gx.TextCfg{ - align: gx.align_left + align: .left size: 24 color: gx.rgb(0, 0, 0) } @@ -43,7 +43,7 @@ const ( text: 'Moves: ' pos: Pos{window_width - 160, 5} cfg: gx.TextCfg{ - align: gx.align_left + align: .left size: 24 color: gx.rgb(0, 0, 0) } @@ -52,7 +52,7 @@ const ( text: 'Game Over' pos: Pos{80, 220} cfg: gx.TextCfg{ - align: gx.align_left + align: .left size: 100 color: gx.rgb(0, 0, 255) } diff --git a/examples/tetris/tetris.v b/examples/tetris/tetris.v index 0a33474556..a6a3cdb707 100644 --- a/examples/tetris/tetris.v +++ b/examples/tetris/tetris.v @@ -25,12 +25,12 @@ const ( const ( text_cfg = gx.TextCfg{ - align:gx.align_left + align:.left size:text_size color:gx.rgb(0, 0, 0) } over_cfg = gx.TextCfg{ - align:gx.align_left + align:.left size:text_size color:gx.white } diff --git a/vlib/gg/gg.v b/vlib/gg/gg.v index 2b1778840f..db7e2e3a98 100644 --- a/vlib/gg/gg.v +++ b/vlib/gg/gg.v @@ -185,13 +185,11 @@ pub fn new_context(cfg Config) &Context { mut g := &Context{ width: cfg.width height: cfg.height - clear_pass: gfx.create_clear_pass(f32(cfg.bg_color.r) / 255.0, f32(cfg.bg_color.g) / 255.0, - f32(cfg.bg_color.b) / 255.0, 1.0) config: cfg render_text: cfg.font_path != '' ft: 0 - } + g.set_bg_color(cfg.bg_color) // C.printf('new_context() %p\n', cfg.user_data) window := C.sapp_desc{ user_data: g @@ -218,8 +216,14 @@ pub fn (gg &Context) run() { sapp.run(&gg.window) } +pub fn (mut ctx Context) set_bg_color(c gx.Color) { + ctx.clear_pass = gfx.create_clear_pass(f32(c.r) / 255.0, f32(c.g) / 255.0, + f32(c.b) / 255.0, f32(c.a) / 255.0) +} + +// TODO: Fix alpha pub fn (ctx &Context) draw_rect(x, y, w, h f32, c gx.Color) { - sgl.c4b(c.r, c.g, c.b, 255) + sgl.c4b(c.r, c.g, c.b, c.a) sgl.begin_quads() sgl.v2f(x * ctx.scale, y * ctx.scale) sgl.v2f((x + w) * ctx.scale, y * ctx.scale) @@ -229,7 +233,7 @@ pub fn (ctx &Context) draw_rect(x, y, w, h f32, c gx.Color) { } pub fn (ctx &Context) draw_empty_rect(x, y, w, h f32, c gx.Color) { - sgl.c4b(c.r, c.g, c.b, 255) + sgl.c4b(c.r, c.g, c.b, c.a) sgl.begin_line_strip() if ctx.scale == 1 { sgl.v2f(x, y) @@ -271,7 +275,7 @@ pub fn (gg &Context) end() { } pub fn (ctx &Context) draw_line(x, y, x2, y2 f32, c gx.Color) { - sgl.c4b(c.r, c.g, c.b, 255) + sgl.c4b(c.r, c.g, c.b, c.a) sgl.begin_line_strip() sgl.v2f(x * ctx.scale, y * ctx.scale) sgl.v2f(x2 * ctx.scale, y2 * ctx.scale) diff --git a/vlib/gg/text_rendering.v b/vlib/gg/text_rendering.v index 6fba37c82f..43ca0c9855 100644 --- a/vlib/gg/text_rendering.v +++ b/vlib/gg/text_rendering.v @@ -6,10 +6,6 @@ import sokol.sfons import gx import os -const ( - default_font_size = 16 -) - struct FT { pub: fons &C.FONScontext @@ -31,14 +27,26 @@ fn new_ft(c FTConfig) ?&FT{ if c.font_path == '' { // Load default font } - if c.font_path == '' || !os.exists(c.font_path) { - println('failed to load font "$c.font_path"') - return none + $if !android { + if c.font_path == '' || !os.exists(c.font_path) { + println('failed to load font "$c.font_path"') + return none + } } - bytes := os.read_bytes(c.font_path) or { - println('failed to load font "$c.font_path"') - return none + + mut bytes := []byte{} + $if android { + bytes = os.read_apk_asset(c.font_path) or { + println('failed to load font "$c.font_path"') + return none + } + } $else { + bytes = os.read_bytes(c.font_path) or { + println('failed to load font "$c.font_path"') + return none + } } + bold_path := 'SFNS-bold.ttf'// c.font_path.replace('.ttf', '-bold.ttf') bytes_bold := os.read_bytes(bold_path) or { println('failed to load font "$bold_path"') @@ -66,15 +74,10 @@ fn new_ft(c FTConfig) ?&FT{ } -pub fn (ctx &Context) draw_text(x, y int, text_ string, cfg gx.TextCfg) { +fn (ctx &Context) set_cfg(cfg gx.TextCfg) { if !ctx.font_inited { return } - //text := text_.trim_space() // TODO remove/optimize - mut text := text_ - if text.contains('\t') { - text = text.replace('\t', ' ') - } if cfg.bold { ctx.ft.fons.set_font(ctx.ft.font_bold) } @@ -88,33 +91,30 @@ pub fn (ctx &Context) draw_text(x, y int, text_ string, cfg gx.TextCfg) { ctx.ft.fons.set_font(ctx.ft.font_normal) } scale := if ctx.ft.scale == 0 { f32(1) } else { ctx.ft.scale } - mut size := if cfg.size == 0 { gg.default_font_size } else { cfg.size } - if cfg.mono { - size -= 2 - } + size := if cfg.mono { cfg.size - 2 } else { cfg.size } ctx.ft.fons.set_size(scale * f32(size)) - if cfg.align == gx.align_right { - C.fonsSetAlign(ctx.ft.fons, C.FONS_ALIGN_RIGHT | C.FONS_ALIGN_TOP) - } - else { - C.fonsSetAlign(ctx.ft.fons, C.FONS_ALIGN_LEFT | C.FONS_ALIGN_TOP) - } + C.fonsSetAlign(ctx.ft.fons, int(cfg.align) | int(cfg.vertical_align)) color := C.sfons_rgba(cfg.color.r, cfg.color.g, cfg.color.b, 255) C.fonsSetColor(ctx.ft.fons, color) ascender := f32(0.0) descender := f32(0.0) lh := f32(0.0) ctx.ft.fons.vert_metrics(&ascender, &descender, &lh) - C.fonsDrawText(ctx.ft.fons, x*scale, y*scale, text.str, 0) // TODO: check offsets/alignment +} + +pub fn (ctx &Context) draw_text(x, y int, text_ string, cfg gx.TextCfg) { + //text := text_.trim_space() // TODO remove/optimize + mut text := text_ + if text.contains('\t') { + text = text.replace('\t', ' ') + } + ctx.set_cfg(cfg) + scale := if ctx.ft.scale == 0 { f32(1) } else { ctx.ft.scale } + C.fonsDrawText(ctx.ft.fons, x * scale, y * scale, text.str, 0) // TODO: check offsets/alignment } pub fn (ctx &Context) draw_text_def(x, y int, text string) { - cfg := gx.TextCfg { - color: gx.black - size: default_font_size - align: gx.align_left - } - ctx.draw_text(x, y, text, cfg) + ctx.draw_text(x, y, text, {}) } /* @@ -127,6 +127,7 @@ pub fn (ft &FT) flush(){ } pub fn (ctx &Context) text_width(s string) int { + // ctx.set_cfg(cfg) TODO if !ctx.font_inited { return 0 } @@ -136,6 +137,7 @@ pub fn (ctx &Context) text_width(s string) int { } pub fn (ctx &Context) text_height(s string) int { + // ctx.set_cfg(cfg) TODO if !ctx.font_inited { return 0 } @@ -145,6 +147,7 @@ pub fn (ctx &Context) text_height(s string) int { } pub fn (ctx &Context) text_size(s string) (int, int) { + // ctx.set_cfg(cfg) TODO if !ctx.font_inited { return 0,0 } diff --git a/vlib/gx/text.v b/vlib/gx/text.v index 0a2ec5e4c3..72ddfa988f 100644 --- a/vlib/gx/text.v +++ b/vlib/gx/text.v @@ -1,19 +1,39 @@ module gx -pub const ( - align_left = 1 - align_right = 4 +import fontstash + +const ( + used_import = fontstash.used_import ) +// TODO: remove these and uae the enum everywhere +const ( + align_left = HorizontalAlign.left + align_right = HorizontalAlign.right +) + +pub enum HorizontalAlign { + left = C.FONS_ALIGN_LEFT + center = C.FONS_ALIGN_CENTER + right = C.FONS_ALIGN_RIGHT +} + +pub enum VerticalAlign { + top = C.FONS_ALIGN_TOP + middle = C.FONS_ALIGN_MIDDLE + bottom = C.FONS_ALIGN_BOTTOM + baseline = C.FONS_ALIGN_BASELINE +} + pub struct TextCfg { pub: - color Color - size int - align int - max_width int - family string - bold bool - mono bool - italic bool - + color Color = black + size int = 16 + align HorizontalAlign = .left + vertical_align VerticalAlign = .top + max_width int + family string + bold bool + mono bool + italic bool } diff --git a/vlib/os/os_android.c.v b/vlib/os/os_android.c.v new file mode 100644 index 0000000000..88ce6fcd80 --- /dev/null +++ b/vlib/os/os_android.c.v @@ -0,0 +1,30 @@ +module os + +struct C.ANativeActivity { + assetManager &C.AAsetManager +} + +struct C.AAset {} + +fn C.AAssetManager_open(&C.AAsetManager, charptr, int) &C.AAset +fn C.AAsset_getLength(&C.AAset) int +fn C.AAsset_read(&C.AAset, voidptr, int) int +fn C.AAsset_close(&C.AAsset) + +pub fn read_apk_asset(file string) ?[]byte { + act := &C.ANativeActivity(C.sapp_android_get_native_activity()) + if isnil(act) { + return error('Could not get reference to Android activity') + } + asset := C.AAssetManager_open(act.assetManager, file.str, C.AASSET_MODE_STREAMING) + if isnil(asset) { + return error('File `$file` not found') + } + len := C.AAsset_getLength(asset) + buf := []byte{ len: len } + for { + if C.AAsset_read(asset, buf.data, len) > 0 { break } + } + C.AAsset_close(asset) + return buf +} diff --git a/vlib/sokol/sapp/sapp.v b/vlib/sokol/sapp/sapp.v index a204117e16..a307426c7c 100644 --- a/vlib/sokol/sapp/sapp.v +++ b/vlib/sokol/sapp/sapp.v @@ -1,5 +1,8 @@ module sapp +// Android needs a global reference to `g_desc` +__global g_desc C.sapp_desc + /* returns true after sokol-app has been initialized */ [inline] pub fn isvalid() bool { @@ -111,6 +114,7 @@ pub fn get_clipboard_string() byteptr { /* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ [inline] pub fn run(desc &C.sapp_desc) int { + g_desc = desc return C.sapp_run(desc) } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 51aa5cd10f..70fade5018 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1656,7 +1656,7 @@ fn (mut p Parser) return_stmt() ast.Return { const ( // modules which allow globals by default - global_enabled_mods = ['rand'] + global_enabled_mods = ['rand', 'sokol.sapp'] ) // left hand side of `=` or `:=` in `a,b,c := 1,2,3`