From c4ebdf305590aa417c0377cd00881df679d93ae5 Mon Sep 17 00:00:00 2001 From: Ronja Date: Sat, 12 Sep 2020 11:35:28 +0200 Subject: [PATCH] layout and pixel font shaders --- Luxe/blocks/tooltip.wren | 4 +- Luxe/blocks/ui.wren | 49 ++++++--- Luxe/game.wren | 1 - Luxe/shaders/pixel_text.emsl | 50 +++++++++ Luxe/shaders/pixel_text.material_basis.lx | 63 +++++++++++ Luxe/shaders/pixel_text_ui.emsl | 104 +++++++++++++++++++ Luxe/shaders/pixel_text_ui.material_basis.lx | 63 +++++++++++ 7 files changed, 314 insertions(+), 20 deletions(-) create mode 100644 Luxe/shaders/pixel_text.emsl create mode 100644 Luxe/shaders/pixel_text.material_basis.lx create mode 100644 Luxe/shaders/pixel_text_ui.emsl create mode 100644 Luxe/shaders/pixel_text_ui.material_basis.lx diff --git a/Luxe/blocks/tooltip.wren b/Luxe/blocks/tooltip.wren index 811af72..55991de 100644 --- a/Luxe/blocks/tooltip.wren +++ b/Luxe/blocks/tooltip.wren @@ -14,7 +14,7 @@ class Tooltip{ construct new(app){ _text = Entity.create(app.ui) - var mat = Assets.material("luxe: material/font") + var mat = Material.create("shaders/pixel_text") Text.create(_text, mat, 8, "assets/fonts/BabyBlocks", color) Transform.create(_text) @@ -24,7 +24,7 @@ class Tooltip{ _shadows = [] for(i in offsets){ var shadow = Entity.create(app.ui) - Text.create(shadow, Material.clone(mat), 8, "assets/fonts/BabyBlocks", background) + Text.create(shadow, mat, 8, "assets/fonts/BabyBlocks", background) Transform.create(shadow) Transform.set_snap(shadow, 1, 1, 0) _shadows.add(shadow) diff --git a/Luxe/blocks/ui.wren b/Luxe/blocks/ui.wren index 2daf7db..2cb95e7 100644 --- a/Luxe/blocks/ui.wren +++ b/Luxe/blocks/ui.wren @@ -1,5 +1,6 @@ import "luxe: draw" for Draw, PathStyle import "luxe: world" for Entity, Transform, UI, UIRenderMode +import "luxe: world" for UILayout, UILayoutBehave, UILayoutContain import "luxe: ui/control" for Control import "luxe: ui/panel" for UIPanel import "luxe: ui/list" for UIList @@ -7,6 +8,7 @@ import "luxe: ui/button" for UIButton import "luxe: ui/image" for UIImage import "luxe: assets" for Assets import "luxe: ui/text" for UIText +import "luxe: render" for Material import "globals" for Globals import "blocks/ui/image_button" for ImageButton @@ -32,6 +34,12 @@ class Ui{ UI.create(_ui, ui_rect.x, ui_rect.y, ui_rect.width, ui_rect.height, 0, app.ui_camera) UI.set_render_mode(_ui, UIRenderMode.world) + var solid_mat = Material.create("luxe: material_basis/ui_solid") + var text_mat = Material.create("luxe: material_basis/ui_font") + //var text_mat = Material.create("shaders/pixel_text_ui") + UI.set_material_basis(_ui, "luxe: material_basis/ui_solid", "shaders/pixel_text_ui") + + UILayout.create(_ui) _info = setup_info() _planning = setup_planning() @@ -47,13 +55,16 @@ class Ui{ } UI.commit(_ui) + UILayout.commit(_ui) } setup_info(){ var ui_rect = Globals["UiRect"] var root = Control.create(_ui) - Control.set_size(root, ui_rect.width, ui_rect.height) + UILayout.set_behave(_ui, root, UILayoutBehave.fill) + UILayout.set_margin(_ui, root, 0, 0, 0, 0) + setup_info_toolbar(root) setup_info_human(root) return root @@ -66,9 +77,11 @@ class Ui{ var list = Control.create(_ui) Control.set_id(list, "info list") Control.child_add(root, list) - //todo: make list horizontal? - Control.set_pos(list, 0, ui_rect.height-16) - Control.set_size(list, ui_rect.width, 16) + //make list span bottom area + UILayout.set_behave(_ui, list, UILayoutBehave.left | UILayoutBehave.right | UILayoutBehave.bottom) + UILayout.set_margin(_ui, list, 0, 0, 0, 0) + UILayout.set_contain(_ui, list, UILayoutContain.row | UILayoutContain.start) + Control.set_size(list, 16, 16) var adventureButtons = Assets.image("assets/AdventureButtons") var tiles = [10, 1] @@ -76,12 +89,10 @@ class Ui{ //plan adventure button = list_button(list) - Control.set_id(button, "info button %(0)") UIImage.set_image(button, adventureButtons) ImageButton.set_tooltip(button, "Adventure!") ImageButton.set_tile_uv(button, tiles, [1, 0]) ImageButton.set_state_change(button) { |data| - System.print("adventure button: %(data)") if(data["press"]){ ui_mode = Ui.Planning } @@ -112,13 +123,15 @@ class Ui{ Control.set_size(portrait, 30, 46) Control.set_id(portrait, "person info portrait") Control.child_add(root, portrait) + UILayout.set_behave(_ui, portrait, UILayoutBehave.left | UILayoutBehave.top) + UILayout.set_margin(_ui, portrait, 1, 1, 0, 0) var frame = UIImage.create(_ui) UIImage.set_image(frame, Assets.image("assets/wip/Frame")) Control.set_pos(frame, 1, 1) Control.set_size(frame, 30, 46) Control.set_id(frame, "person info frame") - Control.child_add(root, frame) + Control.child_add(portrait, frame) Globals["Game"].Focus.on_change(true) {|val| //todo: more sophisticated portrait generation @@ -126,9 +139,13 @@ class Ui{ UIImage.set_color(portrait, Human.get_color(val) || [0, 0, 0, 1]) } + var statBlock = Control.create(_ui) + UILayout.set_behave(_ui, statBlock, UILayoutBehave.fill) + UILayout.set_margin(_ui, statBlock, 33, 1, 0, 16) + UILayout.set_contain(_ui, statBlock, UILayoutContain.column | UILayoutContain.start) + var name = UISimpleText.create(_ui) - Control.set_pos(name, 33, 1) - Control.child_add(root, name) + Control.child_add(statBlock, name) Control.set_id(name, "human name info") Globals["Game"].Focus.on_change(true) {|val| var name_string = Human.get_name(val) || "-" @@ -136,8 +153,7 @@ class Ui{ } var adventures = UISimpleText.create(_ui) - Control.set_pos(adventures, 33, 10) - Control.child_add(root, adventures) + Control.child_add(statBlock, adventures) Control.set_id(name, "human adventure count") Globals["Game"].Focus.on_change(true) {|val| var count = Human.get_adventure_count(val) @@ -156,8 +172,10 @@ class Ui{ //list var list = Control.create(_ui) Control.child_add(root, list) - Control.set_pos(list, 0, ui_rect.height-16) - Control.set_size(list, ui_rect.width, 16) + Control.set_size(list, 0, 16) + UILayout.set_behave(_ui, list, UILayoutBehave.left | UILayoutBehave.right | UILayoutBehave.bottom) + UILayout.set_margin(_ui, list, 0, 0, 0, 0) + UILayout.set_contain(_ui, list, UILayoutContain.row | UILayoutContain.start) var adventureButtons = Assets.image("assets/AdventureButtons") var tiles = [10, 1] @@ -169,7 +187,6 @@ class Ui{ ImageButton.set_tooltip(button, "Info") ImageButton.set_tile_uv(button, tiles, [1, 0]) ImageButton.set_state_change(button) { |data| - System.print("info button: %(data)") if(data["press"]){ ui_mode = Ui.Info } @@ -210,10 +227,8 @@ class Ui{ list_button(parent){ var button = ImageButton.create(_ui) - Control.child_add(parent, button) - var i = Control.child_index(parent, button) Control.set_size(button, 16, 16) - Control.set_pos(button, i*16, 0) //let list handle this in future + Control.child_add(parent, button) return button } } diff --git a/Luxe/game.wren b/Luxe/game.wren index d62776b..8077d9d 100644 --- a/Luxe/game.wren +++ b/Luxe/game.wren @@ -57,7 +57,6 @@ class Game is Ready { DrawDebug.commit() - app.tick(delta) _tooltip.tick() //important to tick after systems to not have a 1 frame lag after setting text } //tick diff --git a/Luxe/shaders/pixel_text.emsl b/Luxe/shaders/pixel_text.emsl new file mode 100644 index 0000000..5c2eaf0 --- /dev/null +++ b/Luxe/shaders/pixel_text.emsl @@ -0,0 +1,50 @@ + +input View { + mat4 mvp, + mat4 proj, + mat4 proj_inverse, + mat4 view, + mat4 world, //geometry.world atm + float2 fov, //fov.x, fov.y + float2 resolution, + float4 target_region, + float4 target_region_size +} + +input Font { + image2D pages[8] +} + +stage vertex vert( + input { View view }, + vertex in { #0 float4 pos, #1 float4 color, #2 float2 uv }, + fragment out { float4 color, float2 uv, float page }) +{ + out.color = in.color; + out.uv = in.uv; + out.page = in.pos.w; + stage.pos = input.view.mvp * float4(in.pos.xyz, 1.0); +} + +stage fragment frag( + input { Font font }, + fragment in { float4 color, float2 uv, float page }) +{ + int page = int(in.page); + float4 msdf_sample = texture(input.font.pages[0], in.uv.xy); + if(page == 1) { msdf_sample = texture(input.font.pages[1], in.uv.xy); } + if(page == 2) { msdf_sample = texture(input.font.pages[2], in.uv.xy); } + if(page == 3) { msdf_sample = texture(input.font.pages[3], in.uv.xy); } + if(page == 4) { msdf_sample = texture(input.font.pages[4], in.uv.xy); } + if(page == 5) { msdf_sample = texture(input.font.pages[5], in.uv.xy); } + if(page == 6) { msdf_sample = texture(input.font.pages[6], in.uv.xy); } + if(page == 7) { msdf_sample = texture(input.font.pages[7], in.uv.xy); } + + float r = msdf_sample.r; + float g = msdf_sample.g; + float b = msdf_sample.b; + float median = max(min(r, g), min(max(r, g), b)); + float opacity = float(median > 0.5); + + stage.color[0] = float4(in.color.rgb, in.color.a * opacity); +} \ No newline at end of file diff --git a/Luxe/shaders/pixel_text.material_basis.lx b/Luxe/shaders/pixel_text.material_basis.lx new file mode 100644 index 0000000..2e548c7 --- /dev/null +++ b/Luxe/shaders/pixel_text.material_basis.lx @@ -0,0 +1,63 @@ +material_basis = { + vertex_format = "luxe.textured" + shaders = { + vertex = { library="shaders/pixel_text" function="vert" } + fragment = { library="shaders/pixel_text" function="frag" } + } + depth_test = true + depth_write = false + depth_compare = "less_equal" + stencil_test = false + write_mask = { red=true green=true blue=true alpha=true } + blending = true + alpha_blend = "add" + rgb_blend = "add" + src_alpha = "source_alpha" + src_rgb = "source_alpha" + dest_alpha = "one_minus_source_alpha" + dest_rgb = "one_minus_source_alpha" + blend_color = [0 0 0 0] + cull = "none" + winding = "counter_clockwise" + layers = ["default"] + inputs = { + font.pages = { + type = "image" + count = 8 + value = [ + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + ] + } + } +} \ No newline at end of file diff --git a/Luxe/shaders/pixel_text_ui.emsl b/Luxe/shaders/pixel_text_ui.emsl new file mode 100644 index 0000000..0215627 --- /dev/null +++ b/Luxe/shaders/pixel_text_ui.emsl @@ -0,0 +1,104 @@ + +input View { + mat4 mvp, + mat4 proj, + mat4 proj_inverse, + mat4 view, + mat4 world, //geometry.world atm + float2 fov, //fov.x, fov.y + float2 resolution, + float4 target_region, + float4 target_region_size +} + +input Font { + image2D pages[8] +} + +input FUI { + float2 canvas_size, + #0 image2D tex_mask +} + +stage vertex vert( + input { View view }, + vertex in { + #0 float4 pos, + #1 float4 color, + #2 float2 uv, + #3 float4 data + }, + fragment out { + float4 color, + float2 uv, + float2 mask_uv, + float clip + }) +{ + out.uv = in.uv; + out.color = in.color; + out.clip = in.data.x; + out.mask_uv = float2(in.data.y, 1.0 - in.data.z); + + stage.pos = input.view.mvp * float4(in.pos.xyz, 1.0); +} + +stage fragment frag( + input { FUI ui, Font font }, + fragment in { + float4 color, + float2 uv, + float2 mask_uv, + float clip, + float page + }) +{ + //outside mask uvs? + bool outside_mask = in.mask_uv.x < 0.0 || + in.mask_uv.x > 1.0 || + in.mask_uv.y < 0.0 || + in.mask_uv.y > 1.0; + + if(outside_mask) { + discard; + // stage.color[0] = float4(1,0.2,0.3,1); + return; + } + + float4 mask = texture(input.ui.tex_mask, in.mask_uv); + + //16 bit mask + // float mask_clip = round(mask.r * 65535.0); + //8 bit mask + int lsb = int(round(mask.r * 255.0)); + int msb = int(round(mask.g * 255.0)) * 256; //<< 8; + int mask_clip = lsb | msb; + // int mask_clip = lsb + msb; //webgl1 + + //outside our clipping bounds? + int my_clip = int(in.clip); + if(my_clip != 0 && mask_clip < my_clip) { + discard; + // stage.color[0] = float4(0,1,1,0.2); + return; + } + + int page = int(in.page); + float4 msdf_sample = texture(input.font.pages[0], in.uv.xy); + if(page == 1) { msdf_sample = texture(input.font.pages[1], in.uv.xy); } + if(page == 2) { msdf_sample = texture(input.font.pages[2], in.uv.xy); } + if(page == 3) { msdf_sample = texture(input.font.pages[3], in.uv.xy); } + if(page == 4) { msdf_sample = texture(input.font.pages[4], in.uv.xy); } + if(page == 5) { msdf_sample = texture(input.font.pages[5], in.uv.xy); } + if(page == 6) { msdf_sample = texture(input.font.pages[6], in.uv.xy); } + if(page == 7) { msdf_sample = texture(input.font.pages[7], in.uv.xy); } + + float r = msdf_sample.r; + float g = msdf_sample.g; + float b = msdf_sample.b; + float median = max(min(r, g), min(max(r, g), b)); + float opacity = float(median > 0.5); + + stage.color[0] = float4(in.color.rgb, in.color.a * opacity * mask.a); + +} \ No newline at end of file diff --git a/Luxe/shaders/pixel_text_ui.material_basis.lx b/Luxe/shaders/pixel_text_ui.material_basis.lx new file mode 100644 index 0000000..fe97f85 --- /dev/null +++ b/Luxe/shaders/pixel_text_ui.material_basis.lx @@ -0,0 +1,63 @@ +material_basis = { + vertex_format = "luxe.textured" + shaders = { + vertex = { library="shaders/pixel_text_ui" function="vert" } + fragment = { library="shaders/pixel_text_ui" function="frag" } + } + depth_test = true + depth_write = false + depth_compare = "less_equal" + stencil_test = false + write_mask = { red=true green=true blue=true alpha=true } + blending = true + alpha_blend = "add" + rgb_blend = "add" + src_alpha = "source_alpha" + src_rgb = "source_alpha" + dest_alpha = "one_minus_source_alpha" + dest_rgb = "one_minus_source_alpha" + blend_color = [0 0 0 0] + cull = "none" + winding = "counter_clockwise" + layers = ["default"] + inputs = { + font.pages = { + type = "image" + count = 8 + value = [ + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + { + type = "image2D" + sampler_state = "linear_repeat" + } + ] + } + } +} \ No newline at end of file