diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 830ab6e45a..f4f3666003 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,10 +108,10 @@ jobs: run: ./v build-examples # - name: Test vsh # run: ./v examples/v_script.vsh -## - name: Test vid -## run: | -## git clone --depth 1 https://github.com/vlang/vid.git -## cd vid && ../v -o vid . + - name: Test vid + run: | + git clone --depth 1 https://github.com/vlang/vid + cd vid && ../v -o vid . - name: Build V UI examples run: | git clone --depth 1 https://github.com/vlang/ui diff --git a/examples/gg/gg2.v b/examples/gg/gg2.v index 637ab6976c..e4ba99b0fa 100644 --- a/examples/gg/gg2.v +++ b/examples/gg/gg2.v @@ -1,6 +1,6 @@ module main -import gg2 as gg +import gg import gx import os diff --git a/examples/gg/gg_freetype.v b/examples/gg/gg_freetype.v index 9f2f33b995..4689241753 100644 --- a/examples/gg/gg_freetype.v +++ b/examples/gg/gg_freetype.v @@ -1,10 +1,9 @@ module main import gg -import freetype +import gg.ft import gx -import glfw -import time +import os const ( win_width = 600 @@ -60,52 +59,46 @@ lines = text.split('\n') ) -struct Context { +struct App { mut: gg &gg.GG - ft &freetype.FreeType + ft &ft.FT } -fn main() { - glfw.init_glfw() - mut ctx := &Context{ - gg: gg.new_context(gg.Cfg { - width: win_width - height: win_height - use_ortho: true // This is needed for 2D drawing - create_window: true - window_title: 'Empty window' - //window_user_ptr: ctx - }) - } - ctx.gg.window.set_user_ptr(ctx) // TODO remove this when `window_user_ptr:` works - gg.clear(bg_color) - // Try to load font - ctx.ft = freetype.new_context(gg.Cfg{ - width: win_width - height: win_height - use_ortho: true +fn init_gui(mut game App){ + x := ft.new({ font_size: 13 scale: 2 - }) - for { - t := time.ticks() - gg.clear(bg_color) - ctx.draw() - ctx.gg.render() - println(time.ticks()-t) - if ctx.gg.window.should_close() { - ctx.gg.window.destroy() - return - } + font_path: os.resource_abs_path('../assets/fonts/RobotoMono-Regular.ttf') + }) or { panic(err) } + game.ft = x } + +fn main() { + mut app := &App{} + app.gg = gg.new_context({ + width: win_width + height: win_height + use_ortho: true // This is needed for 2D drawing + create_window: true + window_title: 'Empty window' + user_data: app + bg_color: bg_color + init_fn: init_gui + frame_fn: frame + //window_user_ptr: ctx + }) + app.gg.run() } -fn (mut ctx Context) draw() { +fn frame(mut app App) { + app.ft.flush() + app.gg.begin() mut y := 10 for line in lines { - ctx.ft.draw_text_def(10,y, line) - y += 15 + app.ft.draw_text_def(10,y, line) + y += 30 } + app.gg.end() } diff --git a/examples/tetris/tetris.v b/examples/tetris/tetris.v index 04cb3b755e..8724377508 100644 --- a/examples/tetris/tetris.v +++ b/examples/tetris/tetris.v @@ -8,8 +8,8 @@ import os import rand import time import gx -import gg2 as gg -import gg2.ft +import gg +import gg.ft import sokol.sapp const ( @@ -139,7 +139,7 @@ struct Game { const ( fpath = os.resource_abs_path('../assets/fonts/RobotoMono-Regular.ttf') ) fn init_gui(mut game Game){ - x := ft.new({ font_path: fpath }) or {panic(err)} + x := ft.new({ font_path: fpath, scale: 2 }) or {panic(err)} game.ft = x game.font_loaded = true } @@ -184,6 +184,7 @@ fn main() { init_fn: init_gui frame_fn: frame event_fn: on_event + scale: 2 ) game.init_game() go game.run() // Run the game loop in a new thread diff --git a/thirdparty/fontstash/fontstash.h b/thirdparty/fontstash/fontstash.h index 251f18ec01..aa34ad55b9 100644 --- a/thirdparty/fontstash/fontstash.h +++ b/thirdparty/fontstash/fontstash.h @@ -155,6 +155,8 @@ FONS_DEF void fonsDrawDebug(FONScontext* s, float x, float y); #define FONS_NOTUSED(v) (void)sizeof(v) +#define FONS_USE_FREETYPE + #ifdef FONS_USE_FREETYPE #include diff --git a/vlib/gg2/ft/ft.v b/vlib/gg/ft/ft.v similarity index 88% rename from vlib/gg2/ft/ft.v rename to vlib/gg/ft/ft.v index e39e852f35..4b6aaf8b3f 100644 --- a/vlib/gg2/ft/ft.v +++ b/vlib/gg/ft/ft.v @@ -5,7 +5,7 @@ import gx import os const ( - default_font_size = 24 + default_font_size = 20 ) // TODO remove globals /* @@ -18,14 +18,21 @@ __global g_font_path string pub struct FT { pub: fons &C.FONScontext + font_normal int + scale f32 = 1.0 } pub struct Config { font_path string + scale f32 = 1.0 + font_size int } pub fn new(c Config) ?&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 @@ -38,13 +45,14 @@ pub fn new(c Config) ?&FT{ return &FT{ fons : fons font_normal: C.fonsAddFontMem(fons, 'sans', bytes.data, bytes.len, false) + scale: c.scale } } pub fn (ft &FT) draw_text(x, y int, text string, cfg gx.TextCfg) { ft.fons.set_font(ft.font_normal) - ft.fons.set_size(2*f32(cfg.size)) // TODO: is this 2* needed? + ft.fons.set_size(2.0 * ft.scale * f32(cfg.size)) C.fonsSetAlign(ft.fons, C.FONS_ALIGN_LEFT | C.FONS_ALIGN_TOP) color := C.sfons_rgba(cfg.color.r, cfg.color.g, cfg.color.b, 255) C.fonsSetColor(ft.fons, color) diff --git a/vlib/gg/gg.v b/vlib/gg/gg.v index b741fe6e12..c969d98086 100644 --- a/vlib/gg/gg.v +++ b/vlib/gg/gg.v @@ -1,553 +1,210 @@ // Copyright (c) 2019-2020 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 stbi -import glm -import gl import gx import os -import glfw +import sokol +import sokol.sapp +import sokol.sgl +import sokol.gfx -pub struct Vec2 { +type FNvoidptr1 fn(voidptr) +type FNvoidptr2 fn(voidptr,voidptr) +type FNFail fn(string,voidptr) + +pub struct Config { pub: - x int - y int -} - -pub fn (v Vec2) str() string { - return 'Vec2{ x: $v.x y: $v.y }' -} - -pub fn vec2(x, y int) Vec2 { - res := Vec2 { - x: x - y: y - } - return res -} - -pub fn init_gg() { - glfw.init_glfw() - gl.init_glad() -} - - -pub struct Cfg { -pub: - width int - height int - use_ortho bool - retina bool - resizable bool - decorated bool = true - - font_size int - font_path string + width int + height int + use_ortho bool + retina bool + resizable bool + user_data voidptr + font_size int create_window bool - window_user_ptr voidptr - window_title string + // window_user_ptr voidptr + window_title string always_on_top bool - scale int + scale f32 = 1.0 + bg_color gx.Color + init_fn FNvoidptr1 = voidptr(0) + frame_fn FNvoidptr1 = voidptr(0) + event_fn FNvoidptr2 = voidptr(0) + cleanup_fn FNvoidptr1 = voidptr(0) + fail_fn FNFail = voidptr(0) + wait_events bool = false // set this to true for UIs, to save power } -pub type RenderFn fn() pub struct GG { - shader gl.Shader - // use_ortho bool - vao u32 - rect_vao u32 - rect_vbo u32 - line_vao u32 - line_vbo u32 - vbo u32 - scale int // retina = 2 , normal = 1 -//pub: + scale f32 = 1.0// retina = 2 , normal = 1 pub mut: - width int - height int - window &glfw.Window - render_fn RenderFn + width int + height int + clear_pass C.sg_pass_action + window C.sapp_desc + config Config } +fn gg_init_sokol_window(user_data voidptr) { + mut g := &GG(user_data) + 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) + if g.config.init_fn != voidptr(0) { + g.config.init_fn( g.config.user_data ) + } +} -// fn new_context(width, height int, use_ortho bool, font_size int) *GG { -pub fn new_context(cfg Cfg) &GG { - mut window := &glfw.Window(0) - if cfg.create_window { - if cfg.resizable { - glfw.window_hint(C.GLFW_RESIZABLE, 1) - } else { - glfw.window_hint(C.GLFW_RESIZABLE, 0) - } - if cfg.decorated { - glfw.window_hint(C.GLFW_DECORATED, 1) - } else { - glfw.window_hint(C.GLFW_DECORATED, 0) - } - window = glfw.create_window(glfw.WinCfg{ - title: cfg.window_title - width: cfg.width - height: cfg.height - ptr: cfg.window_user_ptr - always_on_top: cfg.always_on_top - }) - window.make_context_current() - init_gg() +fn gg_frame_fn(user_data voidptr) { + mut g := &GG(user_data) + if g.config.frame_fn != voidptr(0) { + g.config.frame_fn( g.config.user_data ) } - shader := gl.new_shader('simple') - shader.use() - if cfg.use_ortho { - projection := glm.ortho(0, f32(cfg.width), f32(cfg.height), 0) - shader.set_mat4('projection', projection) +} + +fn gg_event_fn(e &C.sapp_event, user_data voidptr){ + mut g := &GG(user_data) + if g.config.event_fn != voidptr(0) { + g.config.event_fn(e, g.config.user_data) } - else { - // TODO move to function (allow volt functions to return arrays without allocations) - // i := glm.identity3() - shader.set_mat4('projection', glm.identity()) +} + +fn gg_cleanup_fn(user_data voidptr){ + mut g := &GG(user_data) + if g.config.cleanup_fn != voidptr(0) { + g.config.cleanup_fn(g.config.user_data) } - vao := gl.gen_vertex_array() - //println('new gg context VAO=$VAO') - vbo := gl.gen_buffer() - mut scale := 1 - if cfg.retina { - scale = 2 +} + +fn gg_fail_fn(msg charptr, user_data voidptr){ + mut g := &GG(user_data) + vmsg := tos3(msg) + if g.config.fail_fn != voidptr(0) { + g.config.fail_fn(vmsg, g.config.user_data) + }else{ + eprintln('gg error: $vmsg') } - gl.enable(C.GL_SCISSOR_TEST) - //gl.enable(GL_BLEND) - //# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //println('new gg text context VAO=$VAO') - //gl.bind_vao(VAO) - //gl.bind_buffer(GL_ARRAY_BUFFER, VBO) - //gl.enable_vertex_attrib_array(0) - //gl.vertex_attrib_pointer(0, 4, GL_FLOAT, false, 4, 0) - todo_remove_me(cfg, scale) - return &GG { - shader: shader +} + +// + +pub fn new_context(cfg Config) &GG { + mut g := &GG{ width: cfg.width height: cfg.height - vao: vao - vbo: vbo - window: window - - // /line_vao: gl.gen_vertex_array() - // /line_vbo: gl.gen_buffer() - //text_ctx: new_context_text(cfg, scale), - scale: scale - // use_ortho: use_ortho + 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) + scale: cfg.scale //sapp.dpi_scale()// cfg.scale + config: cfg } - // ctx.init_rect_vao() - //return ctx -} - -/* -pub fn (gg &GG) render_loop() bool { - for !gg.window.show_close() { - gg.render_fn() - gg.window.swap_buffers() - glfw.wait_events() + //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: cfg.window_title.str + html5_canvas_name: cfg.window_title.str + width: cfg.width + height: cfg.height + high_dpi: cfg.scale > 1 } -} -*/ - -pub fn clear(color gx.Color) { - gl.clear_color(color.r, color.g, color.b, 255) - gl.clear() + //b := sapp.high_dpi() + //println('scale=$g.scale high_dpi=$b') + if cfg.use_ortho {} + else {} + g.window = window + return g } -pub fn (gg &GG) render() { - gg.window.swap_buffers() - glfw.wait_events() -} - -pub fn (ctx &GG) draw_triangle(x1, y1, x2, y2, x3, y3 f32, c gx.Color) { - // println('draw_triangle $x1,$y1 $x2,$y2 $x3,$y3') - ctx.shader.use() - ctx.shader.set_color('color', c) - vertices := [ - x1, y1, 0, - x2, y2, 0, - x3, y3, 0, - ] ! - // bind the Vertex Array Object first, then bind and set vertex buffer(s), - // and then configure vertex attributes(s). - gl.bind_vao(ctx.vao) - gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) - gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 3, 0) - gl.enable_vertex_attrib_array(0) - // gl.bind_buffer(GL_ARRAY_BUFFER, uint(0)) - // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, - // but this rarely happens. Modifying other - // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs - // (nor VBOs) when it's not directly necessary. - // gl.bind_vertex_array(uint(0)) - // gl.bind_vertex_array(ctx.VAO) - gl.draw_arrays(C.GL_TRIANGLES, 0, 3) -} - -pub fn (ctx &GG) draw_triangle_tex(x1, y1, x2, y2, x3, y3 f32, c gx.Color) { - ctx.shader.use() - ctx.shader.set_color('color', c) - ctx.shader.set_int('has_texture', 1) - vertices := [ - x1, y1, 0, 0, 0, 0, 1, 1, - x2, y2, 0, 0, 0, 0, 1, 0, - x3, y3, 0, 0, 0, 0, 0, 0, - ] ! - gl.bind_vao(ctx.vao) - gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) - // position attribute - gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 3, 0) - gl.enable_vertex_attrib_array(0) - // color attribute - gl.vertex_attrib_pointer(1, 3, C.GL_FLOAT, false, 8, 3) - gl.enable_vertex_attrib_array(1) - // texture attribute - gl.vertex_attrib_pointer(2, 2, C.GL_FLOAT, false, 8, 6) - gl.enable_vertex_attrib_array(2) - // / - // gl.draw_arrays(GL_TRIANGLES, 0, 3) - gl.draw_elements(C.GL_TRIANGLES, 6, C.GL_UNSIGNED_INT, 0) +pub fn (gg &GG) run() { + sapp.run(&gg.window) } pub fn (ctx &GG) draw_rect(x, y, w, h f32, c gx.Color) { - // println('gg.draw_rect($x,$y,$w,$h)') - // wrong order - // // ctx.draw_triangle(x, y, x + w, y, x + w, y + h, c) - // // ctx.draw_triangle(x, y, x, y + h, x + w, y + h, c) - // good order. counter clockwise - // ctx.draw_triangle(x, y, x, y + h, x + w, y + h, c) - // ctx.draw_triangle(x, y, x + w, y + h, x + w, y, c) - ctx.draw_rect2(x, y, w, h, c) + sgl.c4b(c.r, c.g, c.b, 128) + 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() } -// Useful for debugging meshes. -pub fn set_mode_wireframe() { - C.glPolygonMode(C.GL_FRONT_AND_BACK, C.GL_LINE) -} -pub fn set_mode_point() { - C.glPolygonMode(C.GL_FRONT_AND_BACK, C.GL_POINT) -} -pub fn set_mode_fill() { - C.glPolygonMode(C.GL_FRONT_AND_BACK, C.GL_FILL) -} - -/* -fn (mut ctx GG) init_rect_vao() { - - ctx.rect_vao = gl.gen_vertex_array() - ctx.rect_vbo = gl.gen_buffer() - vertices := [ - x + w, y, 0, - x + w, y + h, 0, - x, y + h, 0, - x, y, 0, - ] ! - indices := [ - 0, 1, 3,// first triangle - 1, 2, 3// second triangle - ] ! - gl.bind_vao(ctx.rect_vao) - gl.set_vbo(ctx.rect_vbo, vertices, C.GL_STATIC_DRAW) - ebo := gl.gen_buffer() - // /////// - gl.set_ebo(ebo, indices, C.GL_STATIC_DRAW) -} -*/ -pub fn (ctx &GG) draw_rect2(x, y, w, h f32, c gx.Color) { - C.glDeleteBuffers(1, &ctx.vao) - C.glDeleteBuffers(1, &ctx.vbo) - ctx.shader.use() - ctx.shader.set_color('color', c) - ctx.shader.set_int('has_texture', 0) - // 4--1 - // 3--2 - $if linux { - // y += h - } - vertices := [ - x + w, y, 0, - x + w, y + h, 0, - x, y + h, 0, - x, y, 0, - ] ! - indices := [ - 0, 1, 3,// first triangle - 1, 2, 3// second triangle - ] ! - gl.bind_vao(ctx.vao) - gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) - ebo := gl.gen_buffer() - // /////// - gl.set_ebo(ebo, indices, C.GL_STATIC_DRAW)// !!! LEAKS - // ///// - gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 3, 0) - gl.enable_vertex_attrib_array(0) - // gl.bind_vao(ctx.rect_vao) - gl.bind_vao(ctx.vao) - gl.draw_elements(C.GL_TRIANGLES, 6, C.GL_UNSIGNED_INT, 0) - C.glDeleteBuffers(1, &ebo) -} - -fn todo_remove_me(cfg Cfg, scale int) { - // Can only have text in ortho mode - if !cfg.use_ortho { - return - } - width := cfg.width * scale - height := cfg.height * scale - //font_size := cfg.font_size * scale - gl.enable(C.GL_BLEND) - //# glBlendFunc(C.GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - shader := gl.new_shader('text') - shader.use() - projection := glm.ortho(0, f32(width), 0, f32(height))// 0 at BOT - // projection_new := ortho(0, width, 0, height)// 0 at BOT - // projection := gl.ortho(0, width,height,0) // 0 at TOP - shader.set_mat4('projection', projection) - vao := gl.gen_vertex_array() - //println('new gg text context VAO=$VAO') - vbo := gl.gen_buffer() - gl.bind_vao(vao) - gl.bind_buffer(C.GL_ARRAY_BUFFER, vbo) - gl.enable_vertex_attrib_array(0) - gl.vertex_attrib_pointer(0, 4, C.GL_FLOAT, false, 4, 0) -} - -fn update() { - // # ui__post_empty_event(); -} - -pub fn post_empty_event() { - glfw.post_empty_event() -} - -pub fn (c GG) circle(x, y, r int) { -} - -fn (c GG) fill_color(color gx.Color) { -} - -fn (c GG) fill() { -} - -fn (c GG) move_to(x, y int) { -} - -fn (c GG) line_to(x, y int) { -} - -fn (c GG) stroke_width(size int) { -} - -fn (c GG) stroke_color(color gx.Color) { -} - -fn (c GG) stroke() { -} - -fn (c GG) save() { -} - -fn (c GG) restore() { -} - -fn (c GG) intersect_scissor(x, y, w, h int) { -} - -fn (c GG) translate(x, y int) { -} - -fn (c GG) create_font(name, file string) int { - return 0 -} - -fn (c GG) text(x, y int, text string) { -} - -fn (c GG) text_box(x, y, max int, text string) { -} - -fn (c GG) font_face(f string) { -} - -fn (c GG) font_size(size int) { -} - -fn (c GG) text_align(a int) { -} - -pub fn (ctx &GG) create_image(file string) u32 { - return create_image(file) +pub fn (gg &GG) draw_empty_rect(x, y, w, h f32, c gx.Color) { + sgl.c4b(c.r, c.g, c.b, 128) + sgl.begin_line_strip() + sgl.v2f(x, y) + sgl.v2f(x + w, y) + sgl.v2f(x + w, y + h) + sgl.v2f(x, y + h) + sgl.v2f(x, y) + sgl.end() } pub fn create_image(file string) u32 { - //println('gg create image "$file"') - if file.contains('twitch') { - return u32(0)// TODO - } + // println('gg create image "$file"') if !os.exists(file) { println('gg create image no such file "$file"') return u32(0) } - texture := gl.gen_texture() - img := stbi.load(file) - gl.bind_2d_texture(texture) - img.tex_image_2d() - gl.generate_mipmap(C.GL_TEXTURE_2D) - img.free() - return texture + // img := stbi.load(file) + // img.free() + return 0 // texture } pub fn create_image_from_memory(buf byteptr) u32 { - texture := gl.gen_texture() - img := stbi.load_from_memory(buf) - // TODO copy pasta - gl.bind_2d_texture(texture) - img.tex_image_2d() - gl.generate_mipmap(C.GL_TEXTURE_2D) - img.free() - return texture + // texture := gl.gen_texture() + // img := stbi.load_from_memory(buf) + // img.free() + return 0 // texture } -pub fn (ctx &GG) draw_line(x, y, x2, y2 f32, color gx.Color) { - ctx.use_color_shader(color) - vertices := [x, y, x2, y2] ! - ctx.bind_vertices(vertices) - gl.draw_arrays(C.GL_LINES, 0, 2) +pub fn (gg &GG) begin() { + sgl.defaults() + sgl.matrix_mode_projection() + sgl.ortho(0.0, f32(sapp.width()), f32(sapp.height()), 0.0, -1.0, 1.0) } -pub fn (ctx &GG) draw_arc(x, y, r, start_angle, end_angle f32, segments int, color gx.Color) { - ctx.use_color_shader(color) - vertices := arc_vertices(x, y, r, start_angle, end_angle, segments) - ctx.bind_vertices(vertices) - gl.draw_arrays(C.GL_LINE_STRIP, 0, segments + 1) - unsafe { vertices.free() } +pub fn (gg &GG) end() { + gfx.begin_default_pass(gg.clear_pass, sapp.width(), sapp.height()) + sgl.draw() + gfx.end_pass() + gfx.commit() + if gg.config.wait_events { + wait_events() + } } -pub fn (ctx &GG) draw_filled_arc(x, y, r, start_angle, end_angle f32, segments int, color gx.Color) { - ctx.use_color_shader(color) +pub fn (ctx &GG) draw_line(x, y, x2, y2 f32, color gx.Color) {} +fn C.WaitMessage() - mut vertices := []f32{} - vertices << [x, y] ! - vertices << arc_vertices(x, y, r, start_angle, end_angle, segments) - ctx.bind_vertices(vertices) - gl.draw_arrays(C.GL_TRIANGLE_FAN, 0, segments + 2) - unsafe { vertices.free() } -} - -pub fn (ctx &GG) draw_circle(x, y, r f32, color gx.Color) { - ctx.draw_filled_arc(x, y, r, 0, 360, 24 + int(r / 2), color) -} - -pub fn (ctx &GG) draw_rounded_rect(x, y, w, h, r f32, color gx.Color) { - ctx.use_color_shader(color) - mut vertices := []f32{} - segments := 6 + int(r / 8) - - // Create a rounded rectangle using a triangle fan mesh. - vertices << [x + (w/2.0), y + (h/2.0)] ! - vertices << arc_vertices(x + w - r, y + h - r, r, 0, 90, segments) - vertices << arc_vertices(x + r, y + h - r, r, 90, 180, segments) - vertices << arc_vertices(x + r, y + r, r, 180, 270, segments) - vertices << arc_vertices(x + w - r, y + r, r, 270, 360, segments) - // Finish the loop by going back to the first vertex - vertices << [vertices[2], vertices[3]] ! - - ctx.bind_vertices(vertices) - gl.draw_arrays(C.GL_TRIANGLE_FAN, 0, segments * 4 + 6) - unsafe { vertices.free() } -} - -pub fn (ctx &GG) draw_empty_rounded_rect(x, y, w, h, r f32, color gx.Color) { - ctx.use_color_shader(color) - mut vertices := []f32{} - segments := 6 + int(r / 8) - - vertices << arc_vertices(x + w - r, y + h - r, r, 0, 90, segments) - vertices << arc_vertices(x + r, y + h - r, r, 90, 180, segments) - vertices << arc_vertices(x + r, y + r, r, 180, 270, segments) - vertices << arc_vertices(x + w - r, y + r, r, 270, 360, segments) - - ctx.bind_vertices(vertices) - gl.draw_arrays(C.GL_LINE_STRIP, 0, segments * 4 + 1) - unsafe { vertices.free() } -} - -/* -pub fn (c &GG) draw_gray_line(x, y, x2, y2 f32) { - c.draw_line(x, y, x2, y2, gx.gray) -} - -pub fn (c &GG) draw_vertical(x, y, height int) { - c.draw_line(x, y, x, y + height) -} -*/ - - -//ctx.gg.draw_line(center + prev_x, center+prev_y, center + x*10.0, center+y) - -// fn (ctx &GG) draw_image(x, y, w, h f32, img stbi.Image) { -pub fn (ctx &GG) draw_image(x, y, w, h f32, tex_id u32) { - - // NB: HACK to ensure same state ... TODO: remove next line - ctx.draw_empty_rect(0,0,0,0, gx.white) - - last_array_buffer := 0 - last_texture := 0 - C.glGetIntegerv(C.GL_ARRAY_BUFFER_BINDING, &last_array_buffer) - C.glGetIntegerv(C.GL_TEXTURE_BINDING_2D, &last_texture) - - // println('DRAW IMAGE $x $y $w $h $tex_id') - ctx.shader.use() - // ctx.shader.set_color('color', c) - ctx.shader.set_int('has_texture', 1) - // 4--1 - // | | - // 3--2 - vertices := [ - x + w, y, 0, 1, 0, 0, 1, 1, - x + w, y + h, 0, 0, 1, 0, 1, 0, - x, y + h, 0, 0, 0, 1, 0, 0, - x, y, 0, 1, 1, 0, 0, 1, - ] ! - indices := [ - 0, 1, 3,// first triangle - 1, 2, 3// second triangle - ] ! - // VAO := gl.gen_vertex_array() - // VBO := gl.gen_buffer() - C.glEnable(C.GL_TEXTURE_2D) - gl.bind_vao(ctx.vao) - gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) - ebo := gl.gen_buffer() - gl.set_ebo(ebo, indices, C.GL_STATIC_DRAW) - gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 8, 0) - gl.enable_vertex_attrib_array(0) - gl.vertex_attrib_pointer(1, 3, C.GL_FLOAT, false, 8, 3) - gl.enable_vertex_attrib_array(1) - gl.vertex_attrib_pointer(2, 2, C.GL_FLOAT, false, 8, 6) - gl.enable_vertex_attrib_array(2) - gl.bind_2d_texture(tex_id) - gl.bind_vao(ctx.vao) - gl.draw_elements(C.GL_TRIANGLES, 6, C.GL_UNSIGNED_INT, 0) - C.glDisable(C.GL_TEXTURE_2D) - // restore state - C.glBindBuffer(C.GL_ARRAY_BUFFER, last_array_buffer) - C. glBindTexture(C.GL_TEXTURE_2D, last_texture) -} - -pub fn (c &GG) draw_empty_rect(x, y, w, h f32, color gx.Color) { - c.draw_line(x, y, x + w, y, color) - c.draw_line(x, y, x, y + h, color) - c.draw_line(x, y + h, x + w, y + h, color) - c.draw_line(x + w, y, x + w, y + h, color) -} - -pub fn scissor(x, y, w, h f32) { - C.glScissor(x, y, w, h) +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/gg2/gg.v b/vlib/gg2/gg.v deleted file mode 100644 index fc1a9388e4..0000000000 --- a/vlib/gg2/gg.v +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) 2019-2020 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 gg2 - -import gx -import os -import sokol -import sokol.sapp -import sokol.sgl -import sokol.gfx - -type FNvoidptr1 fn(voidptr) -type FNvoidptr2 fn(voidptr,voidptr) -type FNFail fn(string,voidptr) - -pub struct Config { -pub: - width int - height int - use_ortho bool - retina bool - resizable bool - user_data voidptr - font_size int - create_window bool - // window_user_ptr voidptr - window_title string - always_on_top bool - scale int - bg_color gx.Color - init_fn FNvoidptr1 = voidptr(0) - frame_fn FNvoidptr1 = voidptr(0) - event_fn FNvoidptr2 = voidptr(0) - cleanup_fn FNvoidptr1 = voidptr(0) - fail_fn FNFail = voidptr(0) - wait_events bool = false // set this to true for UIs, to save power -} - -pub struct GG { - scale int // retina = 2 , normal = 1 -pub mut: - width int - height int - clear_pass C.sg_pass_action - window C.sapp_desc - config Config -} - -fn gg_init_sokol_window(user_data voidptr) { - mut g := &GG(user_data) - 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) - if g.config.init_fn != voidptr(0) { - g.config.init_fn( g.config.user_data ) - } -} - -fn gg_frame_fn(user_data voidptr) { - mut g := &GG(user_data) - if g.config.frame_fn != voidptr(0) { - g.config.frame_fn( g.config.user_data ) - } -} - -fn gg_event_fn(e &C.sapp_event, user_data voidptr){ - mut g := &GG(user_data) - if g.config.event_fn != voidptr(0) { - g.config.event_fn(e, g.config.user_data) - } -} - -fn gg_cleanup_fn(user_data voidptr){ - mut g := &GG(user_data) - if g.config.cleanup_fn != voidptr(0) { - g.config.cleanup_fn(g.config.user_data) - } -} - -fn gg_fail_fn(msg charptr, user_data voidptr){ - mut g := &GG(user_data) - vmsg := tos3(msg) - if g.config.fail_fn != voidptr(0) { - g.config.fail_fn(vmsg, g.config.user_data) - }else{ - eprintln('gg error: $vmsg') - } -} - -// - -pub fn new_context(cfg Config) &GG { - mut g := &GG{ - 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) - scale: 1 // scale - config: cfg - } - - //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: cfg.window_title.str - html5_canvas_name: cfg.window_title.str - width: cfg.width - height: cfg.height - //high_dpi: true - } - if cfg.use_ortho {} - else {} - g.window = window - return g -} - -pub fn (gg &GG) run() { - sapp.run(&gg.window) -} - -pub fn (ctx &GG) draw_rect(x, y, w, h f32, c gx.Color) { - sgl.c4b(c.r, c.g, c.b, 128) - sgl.begin_quads() - sgl.v2f(x, y) - sgl.v2f(x + w, y) - sgl.v2f(x + w, y + h) - sgl.v2f(x, y + h) - sgl.end() -} - -pub fn draw_rect(x, y, w, h f32, c gx.Color) { - sgl.c4b(c.r, c.g, c.b, 128) - sgl.begin_quads() - sgl.v2f(x, y) - sgl.v2f(x + w, y) - sgl.v2f(x + w, y + h) - sgl.v2f(x, y + h) - sgl.end() -} - -pub fn (gg &GG) draw_empty_rect(x, y, w, h f32, c gx.Color) { - sgl.c4b(c.r, c.g, c.b, 128) - sgl.begin_line_strip() - sgl.v2f(x, y) - sgl.v2f(x + w, y) - sgl.v2f(x + w, y + h) - sgl.v2f(x, y + h) - sgl.v2f(x, y) - sgl.end() -} - -pub fn create_image(file string) u32 { - // println('gg create image "$file"') - if !os.exists(file) { - println('gg create image no such file "$file"') - return u32(0) - } - // img := stbi.load(file) - // img.free() - return 0 // texture -} - -pub fn create_image_from_memory(buf byteptr) u32 { - // texture := gl.gen_texture() - // img := stbi.load_from_memory(buf) - // img.free() - return 0 // texture -} - -pub fn (gg &GG) begin() { - sgl.defaults() - sgl.matrix_mode_projection() - sgl.ortho(0.0, f32(sapp.width()), f32(sapp.height()), 0.0, -1.0, 1.0) -} - -pub fn (gg &GG) end() { - gfx.begin_default_pass(gg.clear_pass, sapp.width(), sapp.height()) - sgl.draw() - gfx.end_pass() - gfx.commit() - if gg.config.wait_events { - wait_events() - } -} - -pub fn (ctx &GG) draw_line(x, y, x2, y2 f32, color gx.Color) {} - -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/README.md b/vlib/oldgg/README.md similarity index 100% rename from vlib/gg/README.md rename to vlib/oldgg/README.md diff --git a/vlib/oldgg/gg.v b/vlib/oldgg/gg.v new file mode 100644 index 0000000000..b741fe6e12 --- /dev/null +++ b/vlib/oldgg/gg.v @@ -0,0 +1,553 @@ +// Copyright (c) 2019-2020 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 stbi +import glm +import gl +import gx +import os +import glfw + +pub struct Vec2 { +pub: + x int + y int +} + +pub fn (v Vec2) str() string { + return 'Vec2{ x: $v.x y: $v.y }' +} + +pub fn vec2(x, y int) Vec2 { + res := Vec2 { + x: x + y: y + } + return res +} + +pub fn init_gg() { + glfw.init_glfw() + gl.init_glad() +} + + +pub struct Cfg { +pub: + width int + height int + use_ortho bool + retina bool + resizable bool + decorated bool = true + + font_size int + font_path string + create_window bool + window_user_ptr voidptr + window_title string + always_on_top bool + scale int +} + +pub type RenderFn fn() +pub struct GG { + shader gl.Shader + // use_ortho bool + vao u32 + rect_vao u32 + rect_vbo u32 + line_vao u32 + line_vbo u32 + vbo u32 + scale int // retina = 2 , normal = 1 +//pub: +pub mut: + width int + height int + window &glfw.Window + render_fn RenderFn +} + + +// fn new_context(width, height int, use_ortho bool, font_size int) *GG { +pub fn new_context(cfg Cfg) &GG { + mut window := &glfw.Window(0) + if cfg.create_window { + if cfg.resizable { + glfw.window_hint(C.GLFW_RESIZABLE, 1) + } else { + glfw.window_hint(C.GLFW_RESIZABLE, 0) + } + if cfg.decorated { + glfw.window_hint(C.GLFW_DECORATED, 1) + } else { + glfw.window_hint(C.GLFW_DECORATED, 0) + } + window = glfw.create_window(glfw.WinCfg{ + title: cfg.window_title + width: cfg.width + height: cfg.height + ptr: cfg.window_user_ptr + always_on_top: cfg.always_on_top + }) + window.make_context_current() + init_gg() + } + shader := gl.new_shader('simple') + shader.use() + if cfg.use_ortho { + projection := glm.ortho(0, f32(cfg.width), f32(cfg.height), 0) + shader.set_mat4('projection', projection) + } + else { + // TODO move to function (allow volt functions to return arrays without allocations) + // i := glm.identity3() + shader.set_mat4('projection', glm.identity()) + } + vao := gl.gen_vertex_array() + //println('new gg context VAO=$VAO') + vbo := gl.gen_buffer() + mut scale := 1 + if cfg.retina { + scale = 2 + } + gl.enable(C.GL_SCISSOR_TEST) + //gl.enable(GL_BLEND) + //# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //println('new gg text context VAO=$VAO') + //gl.bind_vao(VAO) + //gl.bind_buffer(GL_ARRAY_BUFFER, VBO) + //gl.enable_vertex_attrib_array(0) + //gl.vertex_attrib_pointer(0, 4, GL_FLOAT, false, 4, 0) + todo_remove_me(cfg, scale) + return &GG { + shader: shader + width: cfg.width + height: cfg.height + vao: vao + vbo: vbo + window: window + + // /line_vao: gl.gen_vertex_array() + // /line_vbo: gl.gen_buffer() + //text_ctx: new_context_text(cfg, scale), + scale: scale + // use_ortho: use_ortho + } + + // ctx.init_rect_vao() + //return ctx +} + +/* +pub fn (gg &GG) render_loop() bool { + for !gg.window.show_close() { + gg.render_fn() + gg.window.swap_buffers() + glfw.wait_events() + } +} +*/ + +pub fn clear(color gx.Color) { + gl.clear_color(color.r, color.g, color.b, 255) + gl.clear() +} + +pub fn (gg &GG) render() { + gg.window.swap_buffers() + glfw.wait_events() +} + +pub fn (ctx &GG) draw_triangle(x1, y1, x2, y2, x3, y3 f32, c gx.Color) { + // println('draw_triangle $x1,$y1 $x2,$y2 $x3,$y3') + ctx.shader.use() + ctx.shader.set_color('color', c) + vertices := [ + x1, y1, 0, + x2, y2, 0, + x3, y3, 0, + ] ! + // bind the Vertex Array Object first, then bind and set vertex buffer(s), + // and then configure vertex attributes(s). + gl.bind_vao(ctx.vao) + gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) + gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 3, 0) + gl.enable_vertex_attrib_array(0) + // gl.bind_buffer(GL_ARRAY_BUFFER, uint(0)) + // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, + // but this rarely happens. Modifying other + // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs + // (nor VBOs) when it's not directly necessary. + // gl.bind_vertex_array(uint(0)) + // gl.bind_vertex_array(ctx.VAO) + gl.draw_arrays(C.GL_TRIANGLES, 0, 3) +} + +pub fn (ctx &GG) draw_triangle_tex(x1, y1, x2, y2, x3, y3 f32, c gx.Color) { + ctx.shader.use() + ctx.shader.set_color('color', c) + ctx.shader.set_int('has_texture', 1) + vertices := [ + x1, y1, 0, 0, 0, 0, 1, 1, + x2, y2, 0, 0, 0, 0, 1, 0, + x3, y3, 0, 0, 0, 0, 0, 0, + ] ! + gl.bind_vao(ctx.vao) + gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) + // position attribute + gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 3, 0) + gl.enable_vertex_attrib_array(0) + // color attribute + gl.vertex_attrib_pointer(1, 3, C.GL_FLOAT, false, 8, 3) + gl.enable_vertex_attrib_array(1) + // texture attribute + gl.vertex_attrib_pointer(2, 2, C.GL_FLOAT, false, 8, 6) + gl.enable_vertex_attrib_array(2) + // / + // gl.draw_arrays(GL_TRIANGLES, 0, 3) + gl.draw_elements(C.GL_TRIANGLES, 6, C.GL_UNSIGNED_INT, 0) +} + +pub fn (ctx &GG) draw_rect(x, y, w, h f32, c gx.Color) { + // println('gg.draw_rect($x,$y,$w,$h)') + // wrong order + // // ctx.draw_triangle(x, y, x + w, y, x + w, y + h, c) + // // ctx.draw_triangle(x, y, x, y + h, x + w, y + h, c) + // good order. counter clockwise + // ctx.draw_triangle(x, y, x, y + h, x + w, y + h, c) + // ctx.draw_triangle(x, y, x + w, y + h, x + w, y, c) + ctx.draw_rect2(x, y, w, h, c) +} + +// Useful for debugging meshes. +pub fn set_mode_wireframe() { + C.glPolygonMode(C.GL_FRONT_AND_BACK, C.GL_LINE) +} +pub fn set_mode_point() { + C.glPolygonMode(C.GL_FRONT_AND_BACK, C.GL_POINT) +} +pub fn set_mode_fill() { + C.glPolygonMode(C.GL_FRONT_AND_BACK, C.GL_FILL) +} + +/* +fn (mut ctx GG) init_rect_vao() { + + ctx.rect_vao = gl.gen_vertex_array() + ctx.rect_vbo = gl.gen_buffer() + vertices := [ + x + w, y, 0, + x + w, y + h, 0, + x, y + h, 0, + x, y, 0, + ] ! + indices := [ + 0, 1, 3,// first triangle + 1, 2, 3// second triangle + ] ! + gl.bind_vao(ctx.rect_vao) + gl.set_vbo(ctx.rect_vbo, vertices, C.GL_STATIC_DRAW) + ebo := gl.gen_buffer() + // /////// + gl.set_ebo(ebo, indices, C.GL_STATIC_DRAW) +} +*/ +pub fn (ctx &GG) draw_rect2(x, y, w, h f32, c gx.Color) { + C.glDeleteBuffers(1, &ctx.vao) + C.glDeleteBuffers(1, &ctx.vbo) + ctx.shader.use() + ctx.shader.set_color('color', c) + ctx.shader.set_int('has_texture', 0) + // 4--1 + // 3--2 + $if linux { + // y += h + } + vertices := [ + x + w, y, 0, + x + w, y + h, 0, + x, y + h, 0, + x, y, 0, + ] ! + indices := [ + 0, 1, 3,// first triangle + 1, 2, 3// second triangle + ] ! + gl.bind_vao(ctx.vao) + gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) + ebo := gl.gen_buffer() + // /////// + gl.set_ebo(ebo, indices, C.GL_STATIC_DRAW)// !!! LEAKS + // ///// + gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 3, 0) + gl.enable_vertex_attrib_array(0) + // gl.bind_vao(ctx.rect_vao) + gl.bind_vao(ctx.vao) + gl.draw_elements(C.GL_TRIANGLES, 6, C.GL_UNSIGNED_INT, 0) + C.glDeleteBuffers(1, &ebo) +} + +fn todo_remove_me(cfg Cfg, scale int) { + // Can only have text in ortho mode + if !cfg.use_ortho { + return + } + width := cfg.width * scale + height := cfg.height * scale + //font_size := cfg.font_size * scale + gl.enable(C.GL_BLEND) + //# glBlendFunc(C.GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + shader := gl.new_shader('text') + shader.use() + projection := glm.ortho(0, f32(width), 0, f32(height))// 0 at BOT + // projection_new := ortho(0, width, 0, height)// 0 at BOT + // projection := gl.ortho(0, width,height,0) // 0 at TOP + shader.set_mat4('projection', projection) + vao := gl.gen_vertex_array() + //println('new gg text context VAO=$VAO') + vbo := gl.gen_buffer() + gl.bind_vao(vao) + gl.bind_buffer(C.GL_ARRAY_BUFFER, vbo) + gl.enable_vertex_attrib_array(0) + gl.vertex_attrib_pointer(0, 4, C.GL_FLOAT, false, 4, 0) +} + +fn update() { + // # ui__post_empty_event(); +} + +pub fn post_empty_event() { + glfw.post_empty_event() +} + +pub fn (c GG) circle(x, y, r int) { +} + +fn (c GG) fill_color(color gx.Color) { +} + +fn (c GG) fill() { +} + +fn (c GG) move_to(x, y int) { +} + +fn (c GG) line_to(x, y int) { +} + +fn (c GG) stroke_width(size int) { +} + +fn (c GG) stroke_color(color gx.Color) { +} + +fn (c GG) stroke() { +} + +fn (c GG) save() { +} + +fn (c GG) restore() { +} + +fn (c GG) intersect_scissor(x, y, w, h int) { +} + +fn (c GG) translate(x, y int) { +} + +fn (c GG) create_font(name, file string) int { + return 0 +} + +fn (c GG) text(x, y int, text string) { +} + +fn (c GG) text_box(x, y, max int, text string) { +} + +fn (c GG) font_face(f string) { +} + +fn (c GG) font_size(size int) { +} + +fn (c GG) text_align(a int) { +} + +pub fn (ctx &GG) create_image(file string) u32 { + return create_image(file) +} + +pub fn create_image(file string) u32 { + //println('gg create image "$file"') + if file.contains('twitch') { + return u32(0)// TODO + } + if !os.exists(file) { + println('gg create image no such file "$file"') + return u32(0) + } + texture := gl.gen_texture() + img := stbi.load(file) + gl.bind_2d_texture(texture) + img.tex_image_2d() + gl.generate_mipmap(C.GL_TEXTURE_2D) + img.free() + return texture +} + +pub fn create_image_from_memory(buf byteptr) u32 { + texture := gl.gen_texture() + img := stbi.load_from_memory(buf) + // TODO copy pasta + gl.bind_2d_texture(texture) + img.tex_image_2d() + gl.generate_mipmap(C.GL_TEXTURE_2D) + img.free() + return texture +} + +pub fn (ctx &GG) draw_line(x, y, x2, y2 f32, color gx.Color) { + ctx.use_color_shader(color) + vertices := [x, y, x2, y2] ! + ctx.bind_vertices(vertices) + gl.draw_arrays(C.GL_LINES, 0, 2) +} + +pub fn (ctx &GG) draw_arc(x, y, r, start_angle, end_angle f32, segments int, color gx.Color) { + ctx.use_color_shader(color) + vertices := arc_vertices(x, y, r, start_angle, end_angle, segments) + ctx.bind_vertices(vertices) + gl.draw_arrays(C.GL_LINE_STRIP, 0, segments + 1) + unsafe { vertices.free() } +} + +pub fn (ctx &GG) draw_filled_arc(x, y, r, start_angle, end_angle f32, segments int, color gx.Color) { + ctx.use_color_shader(color) + + + mut vertices := []f32{} + vertices << [x, y] ! + vertices << arc_vertices(x, y, r, start_angle, end_angle, segments) + ctx.bind_vertices(vertices) + gl.draw_arrays(C.GL_TRIANGLE_FAN, 0, segments + 2) + unsafe { vertices.free() } +} + +pub fn (ctx &GG) draw_circle(x, y, r f32, color gx.Color) { + ctx.draw_filled_arc(x, y, r, 0, 360, 24 + int(r / 2), color) +} + +pub fn (ctx &GG) draw_rounded_rect(x, y, w, h, r f32, color gx.Color) { + ctx.use_color_shader(color) + mut vertices := []f32{} + segments := 6 + int(r / 8) + + // Create a rounded rectangle using a triangle fan mesh. + vertices << [x + (w/2.0), y + (h/2.0)] ! + vertices << arc_vertices(x + w - r, y + h - r, r, 0, 90, segments) + vertices << arc_vertices(x + r, y + h - r, r, 90, 180, segments) + vertices << arc_vertices(x + r, y + r, r, 180, 270, segments) + vertices << arc_vertices(x + w - r, y + r, r, 270, 360, segments) + // Finish the loop by going back to the first vertex + vertices << [vertices[2], vertices[3]] ! + + ctx.bind_vertices(vertices) + gl.draw_arrays(C.GL_TRIANGLE_FAN, 0, segments * 4 + 6) + unsafe { vertices.free() } +} + +pub fn (ctx &GG) draw_empty_rounded_rect(x, y, w, h, r f32, color gx.Color) { + ctx.use_color_shader(color) + mut vertices := []f32{} + segments := 6 + int(r / 8) + + vertices << arc_vertices(x + w - r, y + h - r, r, 0, 90, segments) + vertices << arc_vertices(x + r, y + h - r, r, 90, 180, segments) + vertices << arc_vertices(x + r, y + r, r, 180, 270, segments) + vertices << arc_vertices(x + w - r, y + r, r, 270, 360, segments) + + ctx.bind_vertices(vertices) + gl.draw_arrays(C.GL_LINE_STRIP, 0, segments * 4 + 1) + unsafe { vertices.free() } +} + +/* +pub fn (c &GG) draw_gray_line(x, y, x2, y2 f32) { + c.draw_line(x, y, x2, y2, gx.gray) +} + +pub fn (c &GG) draw_vertical(x, y, height int) { + c.draw_line(x, y, x, y + height) +} +*/ + + +//ctx.gg.draw_line(center + prev_x, center+prev_y, center + x*10.0, center+y) + +// fn (ctx &GG) draw_image(x, y, w, h f32, img stbi.Image) { +pub fn (ctx &GG) draw_image(x, y, w, h f32, tex_id u32) { + + // NB: HACK to ensure same state ... TODO: remove next line + ctx.draw_empty_rect(0,0,0,0, gx.white) + + last_array_buffer := 0 + last_texture := 0 + C.glGetIntegerv(C.GL_ARRAY_BUFFER_BINDING, &last_array_buffer) + C.glGetIntegerv(C.GL_TEXTURE_BINDING_2D, &last_texture) + + // println('DRAW IMAGE $x $y $w $h $tex_id') + ctx.shader.use() + // ctx.shader.set_color('color', c) + ctx.shader.set_int('has_texture', 1) + // 4--1 + // | | + // 3--2 + vertices := [ + x + w, y, 0, 1, 0, 0, 1, 1, + x + w, y + h, 0, 0, 1, 0, 1, 0, + x, y + h, 0, 0, 0, 1, 0, 0, + x, y, 0, 1, 1, 0, 0, 1, + ] ! + indices := [ + 0, 1, 3,// first triangle + 1, 2, 3// second triangle + ] ! + // VAO := gl.gen_vertex_array() + // VBO := gl.gen_buffer() + C.glEnable(C.GL_TEXTURE_2D) + gl.bind_vao(ctx.vao) + gl.set_vbo(ctx.vbo, vertices, C.GL_STATIC_DRAW) + ebo := gl.gen_buffer() + gl.set_ebo(ebo, indices, C.GL_STATIC_DRAW) + gl.vertex_attrib_pointer(0, 3, C.GL_FLOAT, false, 8, 0) + gl.enable_vertex_attrib_array(0) + gl.vertex_attrib_pointer(1, 3, C.GL_FLOAT, false, 8, 3) + gl.enable_vertex_attrib_array(1) + gl.vertex_attrib_pointer(2, 2, C.GL_FLOAT, false, 8, 6) + gl.enable_vertex_attrib_array(2) + gl.bind_2d_texture(tex_id) + gl.bind_vao(ctx.vao) + gl.draw_elements(C.GL_TRIANGLES, 6, C.GL_UNSIGNED_INT, 0) + C.glDisable(C.GL_TEXTURE_2D) + // restore state + C.glBindBuffer(C.GL_ARRAY_BUFFER, last_array_buffer) + C. glBindTexture(C.GL_TEXTURE_2D, last_texture) +} + +pub fn (c &GG) draw_empty_rect(x, y, w, h f32, color gx.Color) { + c.draw_line(x, y, x + w, y, color) + c.draw_line(x, y, x, y + h, color) + c.draw_line(x, y + h, x + w, y + h, color) + c.draw_line(x + w, y, x + w, y + h, color) +} + +pub fn scissor(x, y, w, h f32) { + C.glScissor(x, y, w, h) +} diff --git a/vlib/gg/utils.v b/vlib/oldgg/utils.v similarity index 100% rename from vlib/gg/utils.v rename to vlib/oldgg/utils.v diff --git a/vlib/sokol/f/f.v b/vlib/sokol/f/f.v index 3329680dc9..b4db406ee0 100644 --- a/vlib/sokol/f/f.v +++ b/vlib/sokol/f/f.v @@ -24,6 +24,5 @@ pub const ( #include "ft2build.h" -#define FONS_USE_FREETYPE #define SOKOL_FONTSTASH_IMPL #include "util/sokol_fontstash.h"