diff --git a/cmd/tools/vtest-cleancode.v b/cmd/tools/vtest-cleancode.v index 3c849b7432..d7e9287b1d 100644 --- a/cmd/tools/vtest-cleancode.v +++ b/cmd/tools/vtest-cleancode.v @@ -46,7 +46,6 @@ const ( 'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */, 'vlib/readline/readline_test.v' /* vfmt eats `{ Readline }` from `import readline { Readline }` */, 'vlib/glm/glm.v' /* `mut res &f32` => `mut res f32`, which then fails to compile */, - 'vlib/fontstash/fontstash_structs.v' /* eats fn arg names for inline callback types in struct field declarations */, 'vlib/crypto/sha512/sha512block_generic.v' /* formatting of large constant arrays wraps to too many lines */, 'vlib/crypto/aes/const.v' /* formatting of large constant arrays wraps to too many lines */, ]) diff --git a/vlib/fontstash/fontstash.v b/vlib/fontstash/fontstash.c.v similarity index 100% rename from vlib/fontstash/fontstash.v rename to vlib/fontstash/fontstash.c.v diff --git a/vlib/fontstash/fontstash_funcs.v b/vlib/fontstash/fontstash_funcs.c.v similarity index 100% rename from vlib/fontstash/fontstash_funcs.v rename to vlib/fontstash/fontstash_funcs.c.v diff --git a/vlib/fontstash/fontstash_structs.c.v b/vlib/fontstash/fontstash_structs.c.v new file mode 100644 index 0000000000..e34ef26ed3 --- /dev/null +++ b/vlib/fontstash/fontstash_structs.c.v @@ -0,0 +1,51 @@ +module fontstash + +pub struct C.FONSparams { + width int + height int + flags char + userPtr voidptr + // int (*renderCreate)(void* uptr, int width, int height) + renderCreate fn (uptr voidptr, width int, height int) int + // int (*renderResize)(void* uptr, int width, int height) + renderResize fn (uptr voidptr, width int, height int) int + // void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data) + renderUpdate fn (uptr voidptr, rect &int, data &byte) + // void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) + renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int) + // void (*renderDelete)(void* uptr) + renderDelete fn (uptr voidptr) +} + +pub struct C.FONSquad { + x0 f32 + y0 f32 + s0 f32 + t0 f32 + x1 f32 + y1 f32 + s1 f32 + t1 f32 +} + +pub struct C.FONStextIter { + x f32 + y f32 + nextx f32 + nexty f32 + scale f32 + spacing f32 + codepoint u32 + isize i16 + iblur i16 + font &C.FONSfont + prevGlyphIndex int + str &byte + next &byte + end &byte + utf8state u32 +} + +pub struct C.FONSfont {} + +pub struct C.FONScontext {} diff --git a/vlib/fontstash/fontstash_structs.v b/vlib/fontstash/fontstash_structs.v index 83daa52bde..8779bc0d8d 100644 --- a/vlib/fontstash/fontstash_structs.v +++ b/vlib/fontstash/fontstash_structs.v @@ -7,14 +7,14 @@ pub enum FonsFlags { pub enum FonsAlign { // Horizontal align - left = 1 // Default - center = 2 - right = 4 + left = 1 // Default + center = 2 + right = 4 // Vertical align - top = 8 - middle = 16 - bottom = 32 - baseline = 64 // Default + top = 8 + middle = 16 + bottom = 32 + baseline = 64 // Default } pub enum FonsErrorCode { @@ -27,54 +27,3 @@ pub enum FonsErrorCode { // Trying to pop too many states fonsPopState(). states_underflow = 4 } - -pub struct C.FONSparams { - width int - height int - flags char - userPtr voidptr - // int (*renderCreate)(void* uptr, int width, int height) - renderCreate fn(uptr voidptr, width int, height int) int - // int (*renderResize)(void* uptr, int width, int height) - renderResize fn(uptr voidptr, width int, height int) int - // void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data) - renderUpdate fn(uptr voidptr, rect &int, data byteptr) - // void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts) - renderDraw fn(uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int) - // void (*renderDelete)(void* uptr) - renderDelete fn(uptr voidptr) -} - -pub struct C.FONSquad -{ - x0 f32 - y0 f32 - s0 f32 - t0 f32 - x1 f32 - y1 f32 - s1 f32 - t1 f32 -} - -pub struct C.FONStextIter { - x f32 - y f32 - nextx f32 - nexty f32 - scale f32 - spacing f32 - codepoint u32 - isize i16 - iblur i16 - font &C.FONSfont - prevGlyphIndex int - str byteptr - next byteptr - end byteptr - utf8state u32 -} - -pub struct C.FONSfont {} - -pub struct C.FONScontext {} diff --git a/vlib/gg/gg.c.v b/vlib/gg/gg.c.v new file mode 100644 index 0000000000..f6956e60ef --- /dev/null +++ b/vlib/gg/gg.c.v @@ -0,0 +1,278 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. + +module gg + +import os +import gx +import sokol +import sokol.sapp +import sokol.sgl +import sokol.gfx +import math + +pub struct Event { +pub mut: + frame_count u64 + typ sapp.EventType + key_code KeyCode + char_code u32 + key_repeat bool + modifiers u32 + mouse_button MouseButton + mouse_x f32 + mouse_y f32 + mouse_dx f32 + mouse_dy f32 + scroll_x f32 + scroll_y f32 + num_touches int + touches [8]C.sapp_touchpoint + window_width int + window_height int + framebuffer_width int + framebuffer_height int +} + +[heap] +pub struct Context { +mut: + render_text bool = true + // a cache with all images created by the user. used for sokol image init and to save space + // (so that the user can store image ids, not entire Image objects) + image_cache []Image + needs_refresh bool = true + ticks int // for ui mode only +pub: + native_rendering bool +pub mut: + scale f32 = 1.0 + // will get set to 2.0 for retina, will remain 1.0 for normal + width int + height int + clear_pass C.sg_pass_action + window C.sapp_desc + timage_pip C.sgl_pipeline + config Config + ft &FT + font_inited bool + ui_mode bool // do not redraw everything 60 times/second, but only when the user requests + frame u64 // the current frame counted from the start of the application; always increasing + // + mbtn_mask byte + mouse_buttons MouseButtons // typed version of mbtn_mask; easier to use for user programs + mouse_pos_x int + mouse_pos_y int + mouse_dx int + mouse_dy int + scroll_x int + scroll_y int + // + key_modifiers Modifier // the current key modifiers + key_repeat bool // whether the pressed key was an autorepeated one + pressed_keys [key_code_max]bool // an array representing all currently pressed keys + pressed_keys_edge [key_code_max]bool // true when the previous state of pressed_keys, + // *before* the current event was different +} + +fn gg_init_sokol_window(user_data voidptr) { + mut g := unsafe { &Context(user_data) } + desc := sapp.create_desc() + /* + desc := C.sg_desc{ + mtl_device: sapp.metal_get_device() + mtl_renderpass_descriptor_cb: sapp.metal_get_renderpass_descriptor + mtl_drawable_cb: sapp.metal_get_drawable + d3d11_device: sapp.d3d11_get_device() + d3d11_device_context: sapp.d3d11_get_device_context() + d3d11_render_target_view_cb: sapp.d3d11_get_render_target_view + d3d11_depth_stencil_view_cb: sapp.d3d11_get_depth_stencil_view + } + */ + gfx.setup(&desc) + sgl_desc := C.sgl_desc_t{} + sgl.setup(&sgl_desc) + g.scale = dpi_scale() + // is_high_dpi := sapp.high_dpi() + // fb_w := sapp.width() + // fb_h := sapp.height() + // println('g.scale=$g.scale is_high_dpi=$is_high_dpi fb_w=$fb_w fb_h=$fb_h') + // if g.config.init_text { + // `os.is_file()` won't work on Android if the font file is embedded into the APK + exists := $if !android { os.is_file(g.config.font_path) } $else { true } + if g.config.font_path != '' && !exists { + g.render_text = false + } else if g.config.font_path != '' && exists { + // t := time.ticks() + g.ft = new_ft( + font_path: g.config.font_path + custom_bold_font_path: g.config.custom_bold_font_path + scale: dpi_scale() + ) or { panic(err) } + // println('FT took ${time.ticks()-t} ms') + g.font_inited = true + } else { + if g.config.font_bytes_normal.len > 0 { + g.ft = new_ft( + bytes_normal: g.config.font_bytes_normal + bytes_bold: g.config.font_bytes_bold + bytes_mono: g.config.font_bytes_mono + bytes_italic: g.config.font_bytes_italic + scale: sapp.dpi_scale() + ) or { panic(err) } + g.font_inited = true + } else { + sfont := system_font_path() + if g.config.font_path != '' { + eprintln('font file "$g.config.font_path" does not exist, the system font ($sfont) was used instead.') + } + + g.ft = new_ft( + font_path: sfont + custom_bold_font_path: g.config.custom_bold_font_path + scale: sapp.dpi_scale() + ) or { panic(err) } + g.font_inited = true + } + } + // + mut pipdesc := C.sg_pipeline_desc{ + label: c'alpha_image' + } + unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) } + + color_state := C.sg_color_state{ + blend: C.sg_blend_state{ + enabled: true + src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) + dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) + } + } + pipdesc.colors[0] = color_state + + g.timage_pip = sgl.make_pipeline(&pipdesc) + // + if g.config.init_fn != voidptr(0) { + g.config.init_fn(g.config.user_data) + } + // Create images now that we can do that after sg is inited + if g.native_rendering { + return + } + + for i in 0 .. g.image_cache.len { + if g.image_cache[i].simg.id == 0 { + g.image_cache[i].init_sokol_image() + } + } +} + +// +pub fn new_context(cfg Config) &Context { + mut g := &Context{ + width: cfg.width + height: cfg.height + config: cfg + ft: 0 + ui_mode: cfg.ui_mode + native_rendering: cfg.native_rendering + } + g.set_bg_color(cfg.bg_color) + // C.printf('new_context() %p\n', cfg.user_data) + window := C.sapp_desc{ + user_data: g + init_userdata_cb: gg_init_sokol_window + frame_userdata_cb: gg_frame_fn + event_userdata_cb: gg_event_fn + fail_userdata_cb: gg_fail_fn + cleanup_userdata_cb: gg_cleanup_fn + window_title: &char(cfg.window_title.str) + html5_canvas_name: &char(cfg.window_title.str) + width: cfg.width + height: cfg.height + sample_count: cfg.sample_count + high_dpi: true + fullscreen: cfg.fullscreen + __v_native_render: cfg.native_rendering + } + g.window = window + return g +} + +pub fn (ctx &Context) draw_circle_line(x f32, y f32, r int, segments int, c gx.Color) { + $if macos { + if ctx.native_rendering { + C.darwin_draw_circle(x - r + 1, ctx.height - (y + r + 3), r, c) + return + } + } + if c.a != 255 { + sgl.load_pipeline(ctx.timage_pip) + } + sgl.c4b(c.r, c.g, c.b, c.a) + nx := x * ctx.scale + ny := y * ctx.scale + nr := r * ctx.scale + mut theta := f32(0) + mut xx := f32(0) + mut yy := f32(0) + sgl.begin_line_strip() + for i := 0; i < segments + 1; i++ { + theta = 2.0 * f32(math.pi) * f32(i) / f32(segments) + xx = nr * math.cosf(theta) + yy = nr * math.sinf(theta) + sgl.v2f(xx + nx, yy + ny) + } + sgl.end() +} + +pub fn high_dpi() bool { + return C.sapp_high_dpi() +} + +pub fn screen_size() Size { + $if macos { + return C.gg_get_screen_size() + } + // TODO windows, linux, etc + return Size{} +} + +fn C.WaitMessage() + +/* +pub fn wait_events() { + unsafe { + $if macos { + #NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny + #untilDate:[NSDate distantFuture] + #inMode:NSDefaultRunLoopMode + #dequeue:YES]; + #[NSApp sendEvent:event]; + } + $if windows { + C.WaitMessage() + } + } +} +*/ + +// TODO: Fix alpha +pub fn (ctx &Context) draw_rect(x f32, y f32, w f32, h f32, c gx.Color) { + $if macos { + if ctx.native_rendering { + C.darwin_draw_rect(x, ctx.height - (y + h), w, h, c) + return + } + } + if c.a != 255 { + sgl.load_pipeline(ctx.timage_pip) + } + 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) + sgl.v2f((x + w) * ctx.scale, (y + h) * ctx.scale) + sgl.v2f(x * ctx.scale, (y + h) * ctx.scale) + sgl.end() +} diff --git a/vlib/gg/gg.v b/vlib/gg/gg.v index 3b882da86d..c8ecd3f865 100644 --- a/vlib/gg/gg.v +++ b/vlib/gg/gg.v @@ -3,9 +3,7 @@ module gg -import os import gx -import sokol import sokol.sapp import sokol.sgl import sokol.gfx @@ -29,29 +27,6 @@ pub type FNUnClick = fn (x f32, y f32, button MouseButton, data voidptr) pub type FNChar = fn (c u32, data voidptr) -pub struct Event { -pub mut: - frame_count u64 - typ sapp.EventType - key_code KeyCode - char_code u32 - key_repeat bool - modifiers u32 - mouse_button MouseButton - mouse_x f32 - mouse_y f32 - mouse_dx f32 - mouse_dy f32 - scroll_x f32 - scroll_y f32 - num_touches int - touches [8]C.sapp_touchpoint - window_width int - window_height int - framebuffer_width int - framebuffer_height int -} - pub struct Config { pub: width int @@ -110,145 +85,12 @@ pub struct PenConfig { thickness int = 1 } -[heap] -pub struct Context { -mut: - render_text bool = true - // a cache with all images created by the user. used for sokol image init and to save space - // (so that the user can store image ids, not entire Image objects) - image_cache []Image - needs_refresh bool = true - ticks int // for ui mode only -pub: - native_rendering bool -pub mut: - scale f32 = 1.0 - // will get set to 2.0 for retina, will remain 1.0 for normal - width int - height int - clear_pass C.sg_pass_action - window C.sapp_desc - timage_pip C.sgl_pipeline - config Config - ft &FT - font_inited bool - ui_mode bool // do not redraw everything 60 times/second, but only when the user requests - frame u64 // the current frame counted from the start of the application; always increasing - // - mbtn_mask byte - mouse_buttons MouseButtons // typed version of mbtn_mask; easier to use for user programs - mouse_pos_x int - mouse_pos_y int - mouse_dx int - mouse_dy int - scroll_x int - scroll_y int - // - key_modifiers Modifier // the current key modifiers - key_repeat bool // whether the pressed key was an autorepeated one - pressed_keys [key_code_max]bool // an array representing all currently pressed keys - pressed_keys_edge [key_code_max]bool // true when the previous state of pressed_keys, - // *before* the current event was different -} - pub struct Size { pub: width int height int } -fn gg_init_sokol_window(user_data voidptr) { - mut g := unsafe { &Context(user_data) } - desc := sapp.create_desc() - /* - desc := C.sg_desc{ - mtl_device: sapp.metal_get_device() - mtl_renderpass_descriptor_cb: sapp.metal_get_renderpass_descriptor - mtl_drawable_cb: sapp.metal_get_drawable - d3d11_device: sapp.d3d11_get_device() - d3d11_device_context: sapp.d3d11_get_device_context() - d3d11_render_target_view_cb: sapp.d3d11_get_render_target_view - d3d11_depth_stencil_view_cb: sapp.d3d11_get_depth_stencil_view - } - */ - gfx.setup(&desc) - sgl_desc := C.sgl_desc_t{} - sgl.setup(&sgl_desc) - g.scale = dpi_scale() - // is_high_dpi := sapp.high_dpi() - // fb_w := sapp.width() - // fb_h := sapp.height() - // println('g.scale=$g.scale is_high_dpi=$is_high_dpi fb_w=$fb_w fb_h=$fb_h') - // if g.config.init_text { - // `os.is_file()` won't work on Android if the font file is embedded into the APK - exists := $if !android { os.is_file(g.config.font_path) } $else { true } - if g.config.font_path != '' && !exists { - g.render_text = false - } else if g.config.font_path != '' && exists { - // t := time.ticks() - g.ft = new_ft( - font_path: g.config.font_path - custom_bold_font_path: g.config.custom_bold_font_path - scale: dpi_scale() - ) or { panic(err) } - // println('FT took ${time.ticks()-t} ms') - g.font_inited = true - } else { - if g.config.font_bytes_normal.len > 0 { - g.ft = new_ft( - bytes_normal: g.config.font_bytes_normal - bytes_bold: g.config.font_bytes_bold - bytes_mono: g.config.font_bytes_mono - bytes_italic: g.config.font_bytes_italic - scale: sapp.dpi_scale() - ) or { panic(err) } - g.font_inited = true - } else { - sfont := system_font_path() - if g.config.font_path != '' { - eprintln('font file "$g.config.font_path" does not exist, the system font ($sfont) was used instead.') - } - - g.ft = new_ft( - font_path: sfont - custom_bold_font_path: g.config.custom_bold_font_path - scale: sapp.dpi_scale() - ) or { panic(err) } - g.font_inited = true - } - } - // - mut pipdesc := C.sg_pipeline_desc{ - label: c'alpha_image' - } - unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) } - - color_state := C.sg_color_state{ - blend: C.sg_blend_state{ - enabled: true - src_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA) - dst_factor_rgb: gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA) - } - } - pipdesc.colors[0] = color_state - - g.timage_pip = sgl.make_pipeline(&pipdesc) - // - if g.config.init_fn != voidptr(0) { - g.config.init_fn(g.config.user_data) - } - // Create images now that we can do that after sg is inited - if g.native_rendering { - return - } - - for i in 0 .. g.image_cache.len { - if g.image_cache[i].simg.id == 0 { - g.image_cache[i].init_sokol_image() - } - } -} - fn gg_frame_fn(user_data voidptr) { mut ctx := unsafe { &Context(user_data) } ctx.frame++ @@ -402,38 +244,6 @@ fn gg_fail_fn(msg &char, user_data voidptr) { } } -// -pub fn new_context(cfg Config) &Context { - mut g := &Context{ - width: cfg.width - height: cfg.height - config: cfg - ft: 0 - ui_mode: cfg.ui_mode - native_rendering: cfg.native_rendering - } - g.set_bg_color(cfg.bg_color) - // C.printf('new_context() %p\n', cfg.user_data) - window := C.sapp_desc{ - user_data: g - init_userdata_cb: gg_init_sokol_window - frame_userdata_cb: gg_frame_fn - event_userdata_cb: gg_event_fn - fail_userdata_cb: gg_fail_fn - cleanup_userdata_cb: gg_cleanup_fn - window_title: &char(cfg.window_title.str) - html5_canvas_name: &char(cfg.window_title.str) - width: cfg.width - height: cfg.height - sample_count: cfg.sample_count - high_dpi: true - fullscreen: cfg.fullscreen - __v_native_render: cfg.native_rendering - } - g.window = window - return g -} - pub fn (gg &Context) run() { sapp.run(&gg.window) } @@ -448,26 +258,6 @@ pub fn (mut ctx Context) set_bg_color(c gx.Color) { f32(c.a) / 255.0) } -// TODO: Fix alpha -pub fn (ctx &Context) draw_rect(x f32, y f32, w f32, h f32, c gx.Color) { - $if macos { - if ctx.native_rendering { - C.darwin_draw_rect(x, ctx.height - (y + h), w, h, c) - return - } - } - if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) - } - 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) - sgl.v2f((x + w) * ctx.scale, (y + h) * ctx.scale) - sgl.v2f(x * ctx.scale, (y + h) * ctx.scale) - sgl.end() -} - [inline] pub fn (ctx &Context) draw_square(x f32, y f32, s f32, c gx.Color) { ctx.draw_rect(x, y, s, s, c) @@ -509,33 +299,6 @@ pub fn (ctx &Context) draw_empty_square(x f32, y f32, s f32, c gx.Color) { ctx.draw_empty_rect(x, y, s, s, c) } -pub fn (ctx &Context) draw_circle_line(x f32, y f32, r int, segments int, c gx.Color) { - $if macos { - if ctx.native_rendering { - C.darwin_draw_circle(x - r + 1, ctx.height - (y + r + 3), r, c) - return - } - } - if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) - } - sgl.c4b(c.r, c.g, c.b, c.a) - nx := x * ctx.scale - ny := y * ctx.scale - nr := r * ctx.scale - mut theta := f32(0) - mut xx := f32(0) - mut yy := f32(0) - sgl.begin_line_strip() - for i := 0; i < segments + 1; i++ { - theta = 2.0 * f32(math.pi) * f32(i) / f32(segments) - xx = nr * math.cosf(theta) - yy = nr * math.sinf(theta) - sgl.v2f(xx + nx, yy + ny) - } - sgl.end() -} - pub fn (ctx &Context) draw_circle(x f32, y f32, r f32, c gx.Color) { ctx.draw_circle_with_segments(x, y, r, 10, c) } @@ -890,14 +653,6 @@ pub fn (ctx &Context) draw_empty_poly(points []f32, c gx.Color) { sgl.end() } -pub fn screen_size() Size { - $if macos { - return C.gg_get_screen_size() - } - // TODO windows, linux, etc - return Size{} -} - // window_size returns the `Size` of the active window pub fn window_size() Size { s := dpi_scale() @@ -921,26 +676,3 @@ pub fn dpi_scale() f32 { } return s } - -pub fn high_dpi() bool { - return C.sapp_high_dpi() -} - -fn C.WaitMessage() - -/* -pub fn wait_events() { - unsafe { - $if macos { - #NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny - #untilDate:[NSDate distantFuture] - #inMode:NSDefaultRunLoopMode - #dequeue:YES]; - #[NSApp sendEvent:event]; - } - $if windows { - C.WaitMessage() - } - } -} -*/ diff --git a/vlib/gg/image.c.v b/vlib/gg/image.c.v new file mode 100644 index 0000000000..352eac4170 --- /dev/null +++ b/vlib/gg/image.c.v @@ -0,0 +1,169 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module gg + +import os +import stbi +import sokol.gfx + +fn C.sg_isvalid() bool + +// TODO return ?Image +pub fn (mut ctx Context) create_image(file string) Image { + // println('\ncreate_image("$file")') + if !os.exists(file) { + return Image{} + } + $if macos { + if ctx.native_rendering { + // return C.darwin_create_image(file) + mut img := C.darwin_create_image(file) + // println('created macos image: $img.path w=$img.width') + // C.printf('p = %p\n', img.data) + img.id = ctx.image_cache.len + ctx.image_cache << img + return img + } + } + if !C.sg_isvalid() { + // Sokol is not initialized yet, add stbi object to a queue/cache + // ctx.image_queue << file + stb_img := stbi.load(file) or { return Image{} } + img := Image{ + width: stb_img.width + height: stb_img.height + nr_channels: stb_img.nr_channels + ok: false + data: stb_img.data + ext: stb_img.ext + path: file + id: ctx.image_cache.len + } + ctx.image_cache << img + return img + } + mut img := create_image(file) + img.id = ctx.image_cache.len + ctx.image_cache << img + return img +} + +pub fn (mut img Image) init_sokol_image() &Image { + // println('\n init sokol image $img.path ok=$img.simg_ok') + mut img_desc := C.sg_image_desc{ + width: img.width + height: img.height + num_mipmaps: 0 + wrap_u: .clamp_to_edge + wrap_v: .clamp_to_edge + label: img.path.str + d3d11_texture: 0 + } + img_desc.data.subimage[0][0] = C.sg_range{ + ptr: img.data + size: size_t(img.nr_channels * img.width * img.height) + } + img.simg = C.sg_make_image(&img_desc) + img.simg_ok = true + img.ok = true + return img +} + +// draw_image draws the provided image onto the screen +pub fn (ctx &Context) draw_image(x f32, y f32, width f32, height f32, img_ &Image) { + $if macos { + if img_.id >= ctx.image_cache.len { + eprintln('gg: draw_image() bad img id $img_.id (img cache len = $ctx.image_cache.len)') + return + } + if ctx.native_rendering { + if img_.width == 0 { + return + } + if !os.exists(img_.path) { + return + } + C.darwin_draw_image(x, ctx.height - (y + height), width, height, img_) + return + } + } + + ctx.draw_image_with_config( + img: img_ + img_rect: Rect{x, y, width, height} + part_rect: Rect{0, 0, img_.width, img_.height} + ) +} + +// new_streaming_image returns a cached `image_idx` of a special image, that +// can be updated *each frame* by calling: gg.update_pixel_data(image_idx, buf) +// ... where buf is a pointer to the actual pixel data for the image. +// NB: you still need to call app.gg.draw_image after that, to actually draw it. +pub fn (mut ctx Context) new_streaming_image(w int, h int, channels int, sicfg StreamingImageConfig) int { + mut img := Image{} + img.width = w + img.height = h + img.nr_channels = channels // 4 bytes per pixel for .rgba8, see pixel_format + mut img_desc := C.sg_image_desc{ + width: img.width + height: img.height + pixel_format: sicfg.pixel_format + num_slices: 1 + num_mipmaps: 1 + usage: .stream + wrap_u: sicfg.wrap_u + wrap_v: sicfg.wrap_v + min_filter: sicfg.min_filter + mag_filter: sicfg.mag_filter + label: img.path.str + } + // Sokol requires that streamed images have NO .ptr/.size initially: + img_desc.data.subimage[0][0] = C.sg_range{ + ptr: 0 + size: size_t(0) + } + img.simg = C.sg_make_image(&img_desc) + img.simg_ok = true + img.ok = true + img_idx := ctx.cache_image(img) + return img_idx +} + +// update_pixel_data is a helper for working with image streams (i.e. images, +// that are updated dynamically by the CPU on each frame) +pub fn (mut ctx Context) update_pixel_data(cached_image_idx int, buf &byte) { + mut image := ctx.get_cached_image_by_idx(cached_image_idx) + image.update_pixel_data(buf) +} + +pub fn (mut img Image) update_pixel_data(buf &byte) { + mut data := C.sg_image_data{} + data.subimage[0][0].ptr = buf + data.subimage[0][0].size = size_t(img.width * img.height * img.nr_channels) + gfx.update_image(img.simg, &data) +} + +// TODO copypasta +pub fn (mut ctx Context) create_image_with_size(file string, width int, height int) Image { + if !C.sg_isvalid() { + // Sokol is not initialized yet, add stbi object to a queue/cache + // ctx.image_queue << file + stb_img := stbi.load(file) or { return Image{} } + img := Image{ + width: width + height: height + nr_channels: stb_img.nr_channels + ok: false + data: stb_img.data + ext: stb_img.ext + path: file + id: ctx.image_cache.len + } + ctx.image_cache << img + return img + } + mut img := create_image(file) + img.id = ctx.image_cache.len + ctx.image_cache << img + return img +} diff --git a/vlib/gg/image.v b/vlib/gg/image.v index 08a6e7a024..e4c2776408 100644 --- a/vlib/gg/image.v +++ b/vlib/gg/image.v @@ -48,73 +48,6 @@ pub: height f32 } -fn C.sg_isvalid() bool - -// TODO return ?Image -pub fn (mut ctx Context) create_image(file string) Image { - // println('\ncreate_image("$file")') - if !os.exists(file) { - return Image{} - } - $if macos { - if ctx.native_rendering { - // return C.darwin_create_image(file) - mut img := C.darwin_create_image(file) - // println('created macos image: $img.path w=$img.width') - // C.printf('p = %p\n', img.data) - img.id = ctx.image_cache.len - ctx.image_cache << img - return img - } - } - if !C.sg_isvalid() { - // Sokol is not initialized yet, add stbi object to a queue/cache - // ctx.image_queue << file - stb_img := stbi.load(file) or { return Image{} } - img := Image{ - width: stb_img.width - height: stb_img.height - nr_channels: stb_img.nr_channels - ok: false - data: stb_img.data - ext: stb_img.ext - path: file - id: ctx.image_cache.len - } - ctx.image_cache << img - return img - } - mut img := create_image(file) - img.id = ctx.image_cache.len - ctx.image_cache << img - return img -} - -// TODO copypasta -pub fn (mut ctx Context) create_image_with_size(file string, width int, height int) Image { - if !C.sg_isvalid() { - // Sokol is not initialized yet, add stbi object to a queue/cache - // ctx.image_queue << file - stb_img := stbi.load(file) or { return Image{} } - img := Image{ - width: width - height: height - nr_channels: stb_img.nr_channels - ok: false - data: stb_img.data - ext: stb_img.ext - path: file - id: ctx.image_cache.len - } - ctx.image_cache << img - return img - } - mut img := create_image(file) - img.id = ctx.image_cache.len - ctx.image_cache << img - return img -} - // TODO remove this fn create_image(file string) Image { if !os.exists(file) { @@ -165,27 +98,6 @@ pub fn (mut ctx Context) get_cached_image_by_idx(image_idx int) &Image { return &ctx.image_cache[image_idx] } -pub fn (mut img Image) init_sokol_image() &Image { - // println('\n init sokol image $img.path ok=$img.simg_ok') - mut img_desc := C.sg_image_desc{ - width: img.width - height: img.height - num_mipmaps: 0 - wrap_u: .clamp_to_edge - wrap_v: .clamp_to_edge - label: img.path.str - d3d11_texture: 0 - } - img_desc.data.subimage[0][0] = C.sg_range{ - ptr: img.data - size: size_t(img.nr_channels * img.width * img.height) - } - img.simg = C.sg_make_image(&img_desc) - img.simg_ok = true - img.ok = true - return img -} - pub struct StreamingImageConfig { pixel_format gfx.PixelFormat = .rgba8 wrap_u gfx.Wrap = .clamp_to_edge @@ -196,54 +108,6 @@ pub struct StreamingImageConfig { num_slices int = 1 } -// new_streaming_image returns a cached `image_idx` of a special image, that -// can be updated *each frame* by calling: gg.update_pixel_data(image_idx, buf) -// ... where buf is a pointer to the actual pixel data for the image. -// NB: you still need to call app.gg.draw_image after that, to actually draw it. -pub fn (mut ctx Context) new_streaming_image(w int, h int, channels int, sicfg StreamingImageConfig) int { - mut img := Image{} - img.width = w - img.height = h - img.nr_channels = channels // 4 bytes per pixel for .rgba8, see pixel_format - mut img_desc := C.sg_image_desc{ - width: img.width - height: img.height - pixel_format: sicfg.pixel_format - num_slices: 1 - num_mipmaps: 1 - usage: .stream - wrap_u: sicfg.wrap_u - wrap_v: sicfg.wrap_v - min_filter: sicfg.min_filter - mag_filter: sicfg.mag_filter - label: img.path.str - } - // Sokol requires that streamed images have NO .ptr/.size initially: - img_desc.data.subimage[0][0] = C.sg_range{ - ptr: 0 - size: size_t(0) - } - img.simg = C.sg_make_image(&img_desc) - img.simg_ok = true - img.ok = true - img_idx := ctx.cache_image(img) - return img_idx -} - -// update_pixel_data is a helper for working with image streams (i.e. images, -// that are updated dynamically by the CPU on each frame) -pub fn (mut ctx Context) update_pixel_data(cached_image_idx int, buf &byte) { - mut image := ctx.get_cached_image_by_idx(cached_image_idx) - image.update_pixel_data(buf) -} - -pub fn (mut img Image) update_pixel_data(buf &byte) { - mut data := C.sg_image_data{} - data.subimage[0][0].ptr = buf - data.subimage[0][0].size = size_t(img.width * img.height * img.nr_channels) - gfx.update_image(img.simg, &data) -} - // draw_image_with_config takes in a config that details how the // provided image should be drawn onto the screen pub fn (ctx &Context) draw_image_with_config(config DrawImageConfig) { @@ -332,32 +196,6 @@ pub fn (ctx &Context) draw_image_part(img_rect Rect, part_rect Rect, img_ &Image ) } -// draw_image draws the provided image onto the screen -pub fn (ctx &Context) draw_image(x f32, y f32, width f32, height f32, img_ &Image) { - $if macos { - if img_.id >= ctx.image_cache.len { - eprintln('gg: draw_image() bad img id $img_.id (img cache len = $ctx.image_cache.len)') - return - } - if ctx.native_rendering { - if img_.width == 0 { - return - } - if !os.exists(img_.path) { - return - } - C.darwin_draw_image(x, ctx.height - (y + height), width, height, img_) - return - } - } - - ctx.draw_image_with_config( - img: img_ - img_rect: Rect{x, y, width, height} - part_rect: Rect{0, 0, img_.width, img_.height} - ) -} - // draw_image_flipped draws the provided image flipped horizontally (use `draw_image_with_config` to flip vertically) pub fn (ctx &Context) draw_image_flipped(x f32, y f32, width f32, height f32, img_ &Image) { ctx.draw_image_with_config( diff --git a/vlib/gg/text_rendering.c.v b/vlib/gg/text_rendering.c.v new file mode 100644 index 0000000000..9530dd2ade --- /dev/null +++ b/vlib/gg/text_rendering.c.v @@ -0,0 +1,226 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module gg + +import sokol.sfons +import sokol.sgl +import gx +import os + +struct FT { +pub: + fons &C.FONScontext + font_normal int + font_bold int + font_mono int + font_italic int + scale f32 = 1.0 +} + +fn new_ft(c FTConfig) ?&FT { + if c.font_path == '' { + if c.bytes_normal.len > 0 { + fons := sfons.create(512, 512, 1) + bytes_normal := c.bytes_normal + bytes_bold := if c.bytes_bold.len > 0 { + c.bytes_bold + } else { + debug_font_println('setting bold variant to normal') + bytes_normal + } + bytes_mono := if c.bytes_mono.len > 0 { + c.bytes_mono + } else { + debug_font_println('setting mono variant to normal') + bytes_normal + } + bytes_italic := if c.bytes_italic.len > 0 { + c.bytes_italic + } else { + debug_font_println('setting italic variant to normal') + bytes_normal + } + + return &FT{ + fons: fons + font_normal: C.fonsAddFontMem(fons, c'sans', bytes_normal.data, bytes_normal.len, + false) + font_bold: C.fonsAddFontMem(fons, c'sans', bytes_bold.data, bytes_bold.len, + false) + font_mono: C.fonsAddFontMem(fons, c'sans', bytes_mono.data, bytes_mono.len, + false) + font_italic: C.fonsAddFontMem(fons, c'sans', bytes_italic.data, bytes_italic.len, + false) + scale: c.scale + } + } else { + // Load default font + } + } + + if c.font_path == '' || !os.exists(c.font_path) { + $if !android { + println('failed to load font "$c.font_path"') + return none + } + } + + mut bytes := []byte{} + $if android { + // First try any filesystem paths + bytes = os.read_bytes(c.font_path) or { []byte{} } + if bytes.len == 0 { + // ... then try the APK asset path + 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 := if c.custom_bold_font_path != '' { + c.custom_bold_font_path + } else { + get_font_path_variant(c.font_path, .bold) + } + bytes_bold := os.read_bytes(bold_path) or { + debug_font_println('failed to load font "$bold_path"') + bytes + } + mono_path := get_font_path_variant(c.font_path, .mono) + bytes_mono := os.read_bytes(mono_path) or { + debug_font_println('failed to load font "$mono_path"') + bytes + } + italic_path := get_font_path_variant(c.font_path, .italic) + bytes_italic := os.read_bytes(italic_path) or { + debug_font_println('failed to load font "$italic_path"') + bytes + } + fons := sfons.create(512, 512, 1) + return &FT{ + fons: fons + font_normal: C.fonsAddFontMem(fons, c'sans', bytes.data, bytes.len, false) + font_bold: C.fonsAddFontMem(fons, c'sans', bytes_bold.data, bytes_bold.len, false) + font_mono: C.fonsAddFontMem(fons, c'sans', bytes_mono.data, bytes_mono.len, false) + font_italic: C.fonsAddFontMem(fons, c'sans', bytes_italic.data, bytes_italic.len, + false) + scale: c.scale + } +} + +pub fn (ctx &Context) set_cfg(cfg gx.TextCfg) { + if !ctx.font_inited { + return + } + if cfg.bold { + ctx.ft.fons.set_font(ctx.ft.font_bold) + } else if cfg.mono { + ctx.ft.fons.set_font(ctx.ft.font_mono) + } else if cfg.italic { + ctx.ft.fons.set_font(ctx.ft.font_italic) + } else { + ctx.ft.fons.set_font(ctx.ft.font_normal) + } + scale := if ctx.ft.scale == 0 { f32(1) } else { ctx.ft.scale } + size := if cfg.mono { cfg.size - 2 } else { cfg.size } + ctx.ft.fons.set_size(scale * f32(size)) + 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, cfg.color.a) + if cfg.color.a != 255 { + sgl.load_pipeline(ctx.timage_pip) + } + 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) +} + +pub fn (ctx &Context) draw_text(x int, y int, text_ string, cfg gx.TextCfg) { + $if macos { + if ctx.native_rendering { + if cfg.align == gx.align_right { + width := ctx.text_width(text_) + C.darwin_draw_string(x - width, ctx.height - y, text_, cfg) + } else { + C.darwin_draw_string(x, ctx.height - y, text_, cfg) + } + return + } + } + if !ctx.font_inited { + eprintln('gg: draw_text(): font not initialized') + return + } + // 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, &char(text_.str), 0) // TODO: check offsets/alignment +} + +pub fn (ctx &Context) draw_text_def(x int, y int, text string) { + ctx.draw_text(x, y, text) +} + +/* +pub fn (mut gg FT) init_font() { +} +*/ +pub fn (ft &FT) flush() { + sfons.flush(ft.fons) +} + +pub fn (ctx &Context) text_width(s string) int { + $if macos { + if ctx.native_rendering { + return C.darwin_text_width(s) + } + } + // ctx.set_cfg(cfg) TODO + if !ctx.font_inited { + return 0 + } + mut buf := [4]f32{} + C.fonsTextBounds(ctx.ft.fons, 0, 0, &char(s.str), 0, &buf[0]) + if s.ends_with(' ') { + return int((buf[2] - buf[0]) / ctx.scale) + + ctx.text_width('i') // TODO fix this in fontstash? + } + res := int((buf[2] - buf[0]) / ctx.scale) + // println('TW "$s" = $res') + $if macos { + if ctx.native_rendering { + return res * 2 + } + } + return int((buf[2] - buf[0]) / ctx.scale) +} + +pub fn (ctx &Context) text_height(s string) int { + // ctx.set_cfg(cfg) TODO + if !ctx.font_inited { + return 0 + } + mut buf := [4]f32{} + C.fonsTextBounds(ctx.ft.fons, 0, 0, &char(s.str), 0, &buf[0]) + return int((buf[3] - buf[1]) / ctx.scale) +} + +pub fn (ctx &Context) text_size(s string) (int, int) { + // ctx.set_cfg(cfg) TODO + if !ctx.font_inited { + return 0, 0 + } + mut buf := [4]f32{} + C.fonsTextBounds(ctx.ft.fons, 0, 0, &char(s.str), 0, &buf[0]) + return int((buf[2] - buf[0]) / ctx.scale), int((buf[3] - buf[1]) / ctx.scale) +} diff --git a/vlib/gg/text_rendering.v b/vlib/gg/text_rendering.v index dd0499d06e..a34bbbb143 100644 --- a/vlib/gg/text_rendering.v +++ b/vlib/gg/text_rendering.v @@ -2,10 +2,8 @@ // Use of this source code is governed by an MIT license that can be found in the LICENSE file. module gg -import sokol.sfons -import sokol.sgl -import gx import os +import gx enum FontVariant { normal = 0 @@ -14,16 +12,6 @@ enum FontVariant { italic } -struct FT { -pub: - fons &C.FONScontext - font_normal int - font_bold int - font_mono int - font_italic int - scale f32 = 1.0 -} - struct FTConfig { font_path string custom_bold_font_path string @@ -42,214 +30,6 @@ struct StringToRender { cfg gx.TextCfg } -fn new_ft(c FTConfig) ?&FT { - if c.font_path == '' { - if c.bytes_normal.len > 0 { - fons := sfons.create(512, 512, 1) - bytes_normal := c.bytes_normal - bytes_bold := if c.bytes_bold.len > 0 { - c.bytes_bold - } else { - debug_font_println('setting bold variant to normal') - bytes_normal - } - bytes_mono := if c.bytes_mono.len > 0 { - c.bytes_mono - } else { - debug_font_println('setting mono variant to normal') - bytes_normal - } - bytes_italic := if c.bytes_italic.len > 0 { - c.bytes_italic - } else { - debug_font_println('setting italic variant to normal') - bytes_normal - } - - return &FT{ - fons: fons - font_normal: C.fonsAddFontMem(fons, c'sans', bytes_normal.data, bytes_normal.len, - false) - font_bold: C.fonsAddFontMem(fons, c'sans', bytes_bold.data, bytes_bold.len, - false) - font_mono: C.fonsAddFontMem(fons, c'sans', bytes_mono.data, bytes_mono.len, - false) - font_italic: C.fonsAddFontMem(fons, c'sans', bytes_italic.data, bytes_italic.len, - false) - scale: c.scale - } - } else { - // Load default font - } - } - - if c.font_path == '' || !os.exists(c.font_path) { - $if !android { - println('failed to load font "$c.font_path"') - return none - } - } - - mut bytes := []byte{} - $if android { - // First try any filesystem paths - bytes = os.read_bytes(c.font_path) or { []byte{} } - if bytes.len == 0 { - // ... then try the APK asset path - 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 := if c.custom_bold_font_path != '' { - c.custom_bold_font_path - } else { - get_font_path_variant(c.font_path, .bold) - } - bytes_bold := os.read_bytes(bold_path) or { - debug_font_println('failed to load font "$bold_path"') - bytes - } - mono_path := get_font_path_variant(c.font_path, .mono) - bytes_mono := os.read_bytes(mono_path) or { - debug_font_println('failed to load font "$mono_path"') - bytes - } - italic_path := get_font_path_variant(c.font_path, .italic) - bytes_italic := os.read_bytes(italic_path) or { - debug_font_println('failed to load font "$italic_path"') - bytes - } - fons := sfons.create(512, 512, 1) - return &FT{ - fons: fons - font_normal: C.fonsAddFontMem(fons, c'sans', bytes.data, bytes.len, false) - font_bold: C.fonsAddFontMem(fons, c'sans', bytes_bold.data, bytes_bold.len, false) - font_mono: C.fonsAddFontMem(fons, c'sans', bytes_mono.data, bytes_mono.len, false) - font_italic: C.fonsAddFontMem(fons, c'sans', bytes_italic.data, bytes_italic.len, - false) - scale: c.scale - } -} - -pub fn (ctx &Context) set_cfg(cfg gx.TextCfg) { - if !ctx.font_inited { - return - } - if cfg.bold { - ctx.ft.fons.set_font(ctx.ft.font_bold) - } else if cfg.mono { - ctx.ft.fons.set_font(ctx.ft.font_mono) - } else if cfg.italic { - ctx.ft.fons.set_font(ctx.ft.font_italic) - } else { - ctx.ft.fons.set_font(ctx.ft.font_normal) - } - scale := if ctx.ft.scale == 0 { f32(1) } else { ctx.ft.scale } - size := if cfg.mono { cfg.size - 2 } else { cfg.size } - ctx.ft.fons.set_size(scale * f32(size)) - 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, cfg.color.a) - if cfg.color.a != 255 { - sgl.load_pipeline(ctx.timage_pip) - } - 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) -} - -pub fn (ctx &Context) draw_text(x int, y int, text_ string, cfg gx.TextCfg) { - $if macos { - if ctx.native_rendering { - if cfg.align == gx.align_right { - width := ctx.text_width(text_) - C.darwin_draw_string(x - width, ctx.height - y, text_, cfg) - } else { - C.darwin_draw_string(x, ctx.height - y, text_, cfg) - } - return - } - } - if !ctx.font_inited { - eprintln('gg: draw_text(): font not initialized') - return - } - // 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, &char(text_.str), 0) // TODO: check offsets/alignment -} - -pub fn (ctx &Context) draw_text_def(x int, y int, text string) { - ctx.draw_text(x, y, text) -} - -/* -pub fn (mut gg FT) init_font() { -} -*/ -pub fn (ft &FT) flush() { - sfons.flush(ft.fons) -} - -pub fn (ctx &Context) text_width(s string) int { - $if macos { - if ctx.native_rendering { - return C.darwin_text_width(s) - } - } - // ctx.set_cfg(cfg) TODO - if !ctx.font_inited { - return 0 - } - mut buf := [4]f32{} - C.fonsTextBounds(ctx.ft.fons, 0, 0, &char(s.str), 0, &buf[0]) - if s.ends_with(' ') { - return int((buf[2] - buf[0]) / ctx.scale) + - ctx.text_width('i') // TODO fix this in fontstash? - } - res := int((buf[2] - buf[0]) / ctx.scale) - // println('TW "$s" = $res') - $if macos { - if ctx.native_rendering { - return res * 2 - } - } - return int((buf[2] - buf[0]) / ctx.scale) -} - -pub fn (ctx &Context) text_height(s string) int { - // ctx.set_cfg(cfg) TODO - if !ctx.font_inited { - return 0 - } - mut buf := [4]f32{} - C.fonsTextBounds(ctx.ft.fons, 0, 0, &char(s.str), 0, &buf[0]) - return int((buf[3] - buf[1]) / ctx.scale) -} - -pub fn (ctx &Context) text_size(s string) (int, int) { - // ctx.set_cfg(cfg) TODO - if !ctx.font_inited { - return 0, 0 - } - mut buf := [4]f32{} - C.fonsTextBounds(ctx.ft.fons, 0, 0, &char(s.str), 0, &buf[0]) - return int((buf[2] - buf[0]) / ctx.scale), int((buf[3] - buf[1]) / ctx.scale) -} - pub fn system_font_path() string { env_font := os.getenv('VUI_FONT') if env_font != '' && os.exists(env_font) { diff --git a/vlib/gx/text.c.v b/vlib/gx/text.c.v new file mode 100644 index 0000000000..6bd3b8e2a2 --- /dev/null +++ b/vlib/gx/text.c.v @@ -0,0 +1,18 @@ +module gx + +import fontstash + +const used_import = fontstash.used_import + +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 +} diff --git a/vlib/gx/text.v b/vlib/gx/text.v index 53c4bd4cd3..fee934a07c 100644 --- a/vlib/gx/text.v +++ b/vlib/gx/text.v @@ -1,30 +1,11 @@ module gx -import fontstash - -const ( - used_import = fontstash.used_import -) - // TODO: remove these and uae the enum everywhere pub 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 = black diff --git a/vlib/sokol/gfx/gfx.v b/vlib/sokol/gfx/gfx.c.v similarity index 100% rename from vlib/sokol/gfx/gfx.v rename to vlib/sokol/gfx/gfx.c.v diff --git a/vlib/sokol/gfx/gfx_funcs.v b/vlib/sokol/gfx/gfx_funcs.c.v similarity index 100% rename from vlib/sokol/gfx/gfx_funcs.v rename to vlib/sokol/gfx/gfx_funcs.c.v diff --git a/vlib/sokol/gfx/gfx_structs.v b/vlib/sokol/gfx/gfx_structs.c.v similarity index 100% rename from vlib/sokol/gfx/gfx_structs.v rename to vlib/sokol/gfx/gfx_structs.c.v diff --git a/vlib/sokol/gfx/gfx_utils.v b/vlib/sokol/gfx/gfx_utils.c.v similarity index 100% rename from vlib/sokol/gfx/gfx_utils.v rename to vlib/sokol/gfx/gfx_utils.c.v diff --git a/vlib/sokol/sapp/sapp.v b/vlib/sokol/sapp/sapp.c.v similarity index 99% rename from vlib/sokol/sapp/sapp.v rename to vlib/sokol/sapp/sapp.c.v index 7f60dc7695..6ee9cde57e 100644 --- a/vlib/sokol/sapp/sapp.v +++ b/vlib/sokol/sapp/sapp.c.v @@ -2,9 +2,7 @@ module sapp import sokol.gfx -pub const ( - used_import = gfx.used_import -) +pub const used_import = gfx.used_import // Android needs a global reference to `g_desc` __global ( diff --git a/vlib/sokol/sapp/sapp_funcs.v b/vlib/sokol/sapp/sapp_funcs.c.v similarity index 100% rename from vlib/sokol/sapp/sapp_funcs.v rename to vlib/sokol/sapp/sapp_funcs.c.v diff --git a/vlib/sokol/sapp/sapp_structs.v b/vlib/sokol/sapp/sapp_structs.c.v similarity index 100% rename from vlib/sokol/sapp/sapp_structs.v rename to vlib/sokol/sapp/sapp_structs.c.v diff --git a/vlib/sokol/sfons/sfons.v b/vlib/sokol/sfons/sfons.c.v similarity index 80% rename from vlib/sokol/sfons/sfons.v rename to vlib/sokol/sfons/sfons.c.v index 08d2dc6a83..003c112ceb 100644 --- a/vlib/sokol/sfons/sfons.v +++ b/vlib/sokol/sfons/sfons.c.v @@ -2,10 +2,8 @@ module sfons import fontstash -const ( - // keep v from warning about unused imports - used_import = fontstash.used_import + 1 -) +// keep v from warning about unused imports +const used_import = fontstash.used_import + 1 [inline] pub fn create(width int, height int, flags int) &C.FONScontext { diff --git a/vlib/sokol/sfons/sfons_funcs.v b/vlib/sokol/sfons/sfons_funcs.c.v similarity index 100% rename from vlib/sokol/sfons/sfons_funcs.v rename to vlib/sokol/sfons/sfons_funcs.c.v diff --git a/vlib/sokol/sgl/sgl.v b/vlib/sokol/sgl/sgl.c.v similarity index 100% rename from vlib/sokol/sgl/sgl.v rename to vlib/sokol/sgl/sgl.c.v diff --git a/vlib/sokol/sgl/sgl_funcs.v b/vlib/sokol/sgl/sgl_funcs.c.v similarity index 100% rename from vlib/sokol/sgl/sgl_funcs.v rename to vlib/sokol/sgl/sgl_funcs.c.v diff --git a/vlib/sokol/sgl/sgl_structs.v b/vlib/sokol/sgl/sgl_structs.c.v similarity index 100% rename from vlib/sokol/sgl/sgl_structs.v rename to vlib/sokol/sgl/sgl_structs.c.v diff --git a/vlib/stbi/stbi.v b/vlib/stbi/stbi.c.v similarity index 100% rename from vlib/stbi/stbi.v rename to vlib/stbi/stbi.c.v