From: Brendan Hansen Date: Fri, 4 Jun 2021 03:44:39 +0000 (-0500) Subject: starting working on the ui library; going to be part of onyx/modules when done X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=1919a9105b689c3c62fbf88c53be7d349689051a;p=tower.git starting working on the ui library; going to be part of onyx/modules when done --- diff --git a/build.sh b/build.sh index 9953f84..1bbe97e 100755 --- a/build.sh +++ b/build.sh @@ -10,6 +10,6 @@ cp "$ONYX_INSTALLATION_FOLDER/bin/onyx-loader.js" ./site/js/onyx-loader.js cp "$ONYX_INSTALLATION_FOLDER/modules/webgl2/webgl2.js" ./site/js/webgl2.js cp "$ONYX_INSTALLATION_FOLDER/modules/js_events/js_events.js" ./site/js/js_events.js -onyx -r js --use-post-mvp-features -V -o $TARGET \ +onyx -r js -V --use-post-mvp-features -o $TARGET \ src/build.onyx \ -I "$ONYX_INSTALLATION_FOLDER" # Include the folder that contains the "modules" diff --git a/src/build.onyx b/src/build.onyx index 373d6be..85329ac 100644 --- a/src/build.onyx +++ b/src/build.onyx @@ -8,5 +8,7 @@ #load "modules/js_events/module" #load "modules/immediate_mode/module" +#load "src/ui/ui" +#load "src/config" #load "src/font/bitmap_font" #load "src/tower" diff --git a/src/config.onyx b/src/config.onyx new file mode 100644 index 0000000..7dab26d --- /dev/null +++ b/src/config.onyx @@ -0,0 +1,2 @@ + +DEBUG :: true diff --git a/src/font/bitmap_font.onyx b/src/font/bitmap_font.onyx index 8807862..5cb0afa 100644 --- a/src/font/bitmap_font.onyx +++ b/src/font/bitmap_font.onyx @@ -42,6 +42,22 @@ Bitmap_Font :: struct { get_glyph :: (use bmp: ^Bitmap_Font, char: u8) -> ^Glyph { return map.get_ptr(^glyphs, ~~char); } + + get_width :: (use bmp: ^Bitmap_Font, text: str, size: f32) -> f32 { + width: f32 = 0; + for char: text { + glyph := map.get_ptr(^glyphs, ~~char); + + if glyph == null { + glyph = map.get_ptr(^glyphs, 255); + assert(glyph != null, "NO NULL GLYPH"); + } + + width += glyph.w * size * em; + } + + return width; + } } Bitmap_Font_Texture :: struct { @@ -128,4 +144,4 @@ bitmap_font_prepare_glyphs :: (use bmp: ^Bitmap_Font, glyph_str: str) -> bool { } return true; -} +} \ No newline at end of file diff --git a/src/tower.onyx b/src/tower.onyx index 47a97a4..a59d2df 100644 --- a/src/tower.onyx +++ b/src/tower.onyx @@ -6,18 +6,15 @@ use package core #private_file gfx :: package immediate_mode #private_file bitmap_font :: package bitmap_font +#private_file ui :: package ui - -font : bitmap_font.Bitmap_Font; -font_texture : gl.GLTexture; - main :: (args: [] cstr) { gl.init("game"); events.init(); gfx.immediate_renderer_init(); - init_font(); + ui.init_ui(); gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); @@ -26,27 +23,6 @@ main :: (args: [] cstr) { start_loop(); } -init_font :: () { - font_data := #file_contents "src/res/font_2.data"; - - bft := bitmap_font.Bitmap_Font_Texture.{ - data = font_data, - width = 256, - height = 256, - }; - - font = bitmap_font.bitmap_font_create(bft, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \xff:"); - - font_texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, font_texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, font_data); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.bindTexture(gl.TEXTURE_2D, -1); -} - last_time := 0; #export "loop" () { time_now :: () -> i32 #foreign "game" "time_now" --- @@ -81,16 +57,22 @@ poll_events :: () { } } -fps := 0; -fps_timer := 1.0f; -frames := 0 +#if DEBUG { + fps := 0 + fps_timer := 1.0f + frames := 0 +} + update :: (dt: f32) { - fps_timer -= dt; - frames += 1; - if fps_timer < 0 { - fps = frames; - frames = 0; - fps_timer = 1.0f; + + #if DEBUG { // Frame counting + fps_timer -= dt; + frames += 1; + if fps_timer < 0 { + fps = frames; + frames = 0; + fps_timer = 1.0f; + } } } @@ -98,46 +80,37 @@ draw :: () { gl.clearColor(0.1, 0.1, 0.1, 1); gl.clear(gl.COLOR_BUFFER_BIT); - fps_buffer : [16] u8; - fps_str := conv.str_format("FPS: %i", ~~ fps_buffer, fps); - draw_text(fps_str, 0, 0, 32, .{0,1,0}); + #if false { + ui.draw_text("Hello World", 100, 100, 128); + ui.draw_text("something else...", 100, 230, 32, .{1,0,0}); - draw_text("Hello World", 100, 100, 128); - draw_text("something else...", 100, 230, 32, .{1,0,0}); + ui.draw_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 100, 300, 16); + ui.draw_text("abcdefghijklmnopqrstuvwxyz", 100, 340, 16); - draw_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 100, 300, 16); - draw_text("abcdefghijklmnopqrstuvwxyz", 100, 340, 16); + gfx.set_texture(); + gfx.rect(.{100, 400}, .{200, 200}, .{0, 0, 1}); + } - gfx.flush(); -} + master_rectangle := ui.Rectangle.{ x1 = ~~window_width, y1 = ~~window_height }; + left, right := ui.Flow.split_vertical(master_rectangle, left_percent=0.4); + right_top, right_bottom := ui.Flow.split_horizontal(right, top_height=200); + ui.draw_rect(left, .{ 0.5, 0, 0.5 }); + ui.draw_rect(right, .{ 0, 0.25, 0.5 }); + ui.draw_rect(right_top, .{ 1, 0, 0 }); + ui.draw_text("Something here", right_bottom.x0, right_bottom.y0, 48, .{ 1, 1, 1 }); + #if DEBUG { + fps_buffer : [16] u8; + fps_str := conv.str_format("FPS: %i", ~~ fps_buffer, fps); + ui.draw_text(fps_str, 0, 0, 32, .{0,1,0}); + } -draw_text :: (text: str, x: f32, y: f32, size := 32.0f, color := gfx.Color4.{1,1,1}) { + gfx.flush(); +} - gl.bindTexture(gl.TEXTURE_2D, font_texture); - gfx.set_texture(0); - for char: text { - glyph := font->get_glyph(char); - - if glyph == null { - glyph = font->get_glyph(255); - assert(glyph != null, "NO NULL GLYPH"); - } - gfx.textured_rect( - .{ x, y }, - .{ glyph.w * size * font.em, glyph.h * size * font.em }, - .{ glyph.x0, glyph.y0 }, - .{ glyph.x1 - glyph.x0, glyph.y1 - glyph.y0 }, - color = color); - x += glyph.w * size * 16; - } - - gfx.flush(); - gl.bindTexture(gl.TEXTURE_2D, -1); -} diff --git a/src/ui/ui.onyx b/src/ui/ui.onyx new file mode 100644 index 0000000..ccb6b2f --- /dev/null +++ b/src/ui/ui.onyx @@ -0,0 +1,168 @@ +package ui + +#private_file gfx :: package immediate_mode +#private_file bitmap_font :: package bitmap_font +#private_file gl :: package gl +#private_file math :: package core.math + +#private font : bitmap_font.Bitmap_Font; +#private font_texture : gl.GLTexture; + +@Temporary +DEFAULT_TEXT_SIZE :: 32.0f + + +init_ui :: () { + init_font(); +} + +#private init_font :: () { + font_data := #file_contents "./../res/font_2.data"; + + bft := bitmap_font.Bitmap_Font_Texture.{ + data = font_data, + width = 256, + height = 256, + }; + + font = bitmap_font.bitmap_font_create(bft, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \xff:"); + + font_texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, font_texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, font_data); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindTexture(gl.TEXTURE_2D, -1); +} + +get_text_width :: (text: str, size: f32 = DEFAULT_TEXT_SIZE) -> f32 { + return font->get_width(text, size); +} + +// 'x' and 'y' are the top-left coordinates of the text. 'y' is NOT the baseline. +draw_text :: (text: str, x: f32, y: f32, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) { + gl.bindTexture(gl.TEXTURE_2D, font_texture); + gfx.set_texture(0); + + for char: text { + glyph := font->get_glyph(char); + + if glyph == null { + glyph = font->get_glyph(255); + assert(glyph != null, "NO NULL GLYPH"); + } + + gfx.textured_rect( + .{ x, y }, + .{ glyph.w * size * font.em, glyph.h * size * font.em }, + .{ glyph.x0, glyph.y0 }, + .{ glyph.x1 - glyph.x0, glyph.y1 - glyph.y0 }, + color = color); + + x += glyph.w * size * font.em; + } + + gfx.flush(); + gl.bindTexture(gl.TEXTURE_2D, -1); +} + +draw_rect :: proc { + (use r: Rectangle, color := gfx.Color4.{1,1,1}) { + gfx.set_texture(); + + width, height := Rectangle.dimensions(r); + gfx.rect(.{ x0, y0 }, .{ width, height }, color); + }, + + (x: f32, y: f32, w: f32, h: f32, color := gfx.Color4.{1,1,1}) { + gfx.set_texture(); + gfx.rect(.{ x, y }, .{ w, h }, color); + } +} + + + +Rectangle :: struct { + // + // x0,y0 ------------+ + // | | + // | | + // +------------ x1, y1 + // + + x0: f32 = 0; + y0: f32 = 0; + x1: f32 = 0; + y1: f32 = 0; + + width :: (use r: Rectangle) -> f32 do return math.abs(x1 - x0); + height :: (use r: Rectangle) -> f32 do return math.abs(y1 - y0); + + dimensions :: (use r: Rectangle) -> (width: f32, height: f32) { + return math.abs(x1 - x0), math.abs(y1 - y0); + } + + top_left :: (use r: Rectangle) -> (x: f32, y: f32) do return math.min(x0, x1), math.min(y0, y1); + bottom_right :: (use r: Rectangle) -> (x: f32, y: f32) do return math.max(x0, x1), math.max(y0, y1); +} + + + +// UI Flow + +Flow :: struct { + split_vertical :: proc { + (r: Rectangle, left_percent: f32) -> (left: Rectangle, right: Rectangle) { + return split_vertical(r, left_width=left_percent * Rectangle.width(r)); + }, + + (r: Rectangle, right_percent: f32) -> (left: Rectangle, right: Rectangle) { + return split_vertical(r, right_width=right_percent * Rectangle.width(r)); + }, + + (r: Rectangle, left_width: f32) -> (left: Rectangle, right: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x0+left_width, y0=y0, y1=y1 }, + .{ x0=x0+left_width, x1=x1, y0=y0, y1=y1 }; + }, + + (r: Rectangle, right_width: f32) -> (left: Rectangle, right: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x1-right_width, y0=y0, y1=y1 }, + .{ x0=x1-right_width, x1=x1, y0=y0, y1=y1 }; + } + } + + + split_horizontal :: proc { + (r: Rectangle, top_percent: f32) -> (top: Rectangle, bottom: Rectangle) { + return split_horizontal(r, top_height=top_percent * Rectangle.height(r)); + }, + + (r: Rectangle, bottom_percent: f32) -> (top: Rectangle, bottom: Rectangle) { + return split_horizontal(r, bottom_height=bottom_percent * Rectangle.height(r)); + }, + + (r: Rectangle, top_height: f32) -> (top: Rectangle, bottom: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x1, y0=y0, y1=y0+top_height }, + .{ x0=x0, x1=x1, y0=y0+top_height, y1=y1 }; + }, + + (r: Rectangle, bottom_height: f32) -> (top: Rectangle, bottom: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x1, y0=y0, y1=y1-bottom_height }, + .{ x0=x0, x1=x1, y0=y1-bottom_height, y1=y1 }; + } + } +} \ No newline at end of file