Compare commits

..

5 commits

Author SHA1 Message Date
griffi-gh 15d1184451 uwu 2023-12-02 21:32:20 +01:00
griffi-gh 726dfa4b52 owo 2023-12-02 21:20:20 +01:00
griffi-gh f15ae91155 add new text test 2023-12-02 21:12:26 +01:00
griffi-gh a42a3d95c3 separate textured shader 2023-12-02 20:50:25 +01:00
griffi-gh adbab2b2a6 it works 2023-12-02 19:46:08 +01:00
11 changed files with 288 additions and 98 deletions

View file

@ -0,0 +1,111 @@
use std::time::Instant;
use glam::{UVec2, vec4};
use glium::{backend::glutin::SimpleWindowBuilder, Surface};
use winit::{
event::{Event, WindowEvent},
event_loop::{EventLoopBuilder, ControlFlow}
};
use kubi_ui::{
KubiUi,
element::{
progress_bar::ProgressBar,
container::{Container, Sides, Alignment},
text::Text
},
UiSize,
elements,
};
use kubi_ui_glium::GliumUiRenderer;
fn main() {
kubi_logging::init();
let event_loop = EventLoopBuilder::new().build().unwrap();
let (window, display) = SimpleWindowBuilder::new().build(&event_loop);
window.set_title("Mom Downloader 2000");
let mut kui = KubiUi::new();
let mut backend = GliumUiRenderer::new(&display);
let font_handle = kui.add_font_from_bytes(include_bytes!("../../assets/fonts/roboto/Roboto-Regular.ttf"));
let instant = Instant::now();
event_loop.run(|event, window_target| {
window_target.set_control_flow(ControlFlow::Poll);
match event {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
window_target.exit();
},
Event::AboutToWait => {
let mut frame = display.draw();
frame.clear_color_srgb(0., 0., 0., 1.);
let resolution = UVec2::from(display.get_framebuffer_dimensions()).as_vec2();
kui.begin();
let mom_ratio = (instant.elapsed().as_secs_f32() / 60.).powf(0.5);
kui.add(Container {
align: (Alignment::Center, Alignment::Center),
size: (UiSize::Percentage(1.), UiSize::Percentage(1.)),
background: Some(vec4(0.1, 0.1, 0.1, 1.)),
elements: vec![Box::new(Container {
gap: 5.,
padding: Sides::all(10.),
align: (Alignment::Begin, Alignment::Begin),
size: (UiSize::Pixels(450.), UiSize::Auto),
background: Some(vec4(0.2, 0.2, 0.5, 1.)),
elements: elements(|el| {
if instant.elapsed().as_secs_f32() < 5. {
el.add(Text {
text: "Downloading your mom...".into(),
font: font_handle,
text_size: 32,
..Default::default()
});
el.add(ProgressBar {
value: mom_ratio,
..Default::default()
});
el.add(Text {
text: format!("{:.2}% ({:.1} GB)", mom_ratio * 100., mom_ratio * 10000.).into(),
font: font_handle,
text_size: 24,
..Default::default()
});
} else if instant.elapsed().as_secs() < 10 {
el.add(Text {
text: "Error 413 Request Entity Too Large".into(),
font: font_handle,
color: vec4(1., 0.125, 0.125, 1.),
text_size: 26,
..Default::default()
});
el.add(Text {
text: format!("Exiting in {}...", 10 - instant.elapsed().as_secs()).into(),
font: font_handle,
text_size: 24,
..Default::default()
})
} else {
window_target.exit();
}
}),
..Default::default()
})],
..Default::default()
}, resolution);
kui.end();
backend.update(&kui);
backend.draw(&mut frame, resolution);
frame.finish().unwrap();
}
_ => (),
}
}).unwrap();
}

View file

@ -1,72 +0,0 @@
use std::time::Instant;
use glam::{UVec2, vec4};
use glium::{backend::glutin::SimpleWindowBuilder, Surface};
use winit::{
event::{Event, WindowEvent},
event_loop::{EventLoopBuilder, ControlFlow}
};
use kubi_ui::{
KubiUi,
element::{
UiElement,
progress_bar::ProgressBar,
container::{Container, Sides, Alignment},
rect::Rect, text::Text
},
interaction::IntoInteractable,
UiSize,
UiDirection, IfModified,
};
use kubi_ui_glium::GliumUiRenderer;
fn main() {
kubi_logging::init();
let event_loop = EventLoopBuilder::new().build().unwrap();
let (window, display) = SimpleWindowBuilder::new().build(&event_loop);
let mut kui = KubiUi::new();
let mut backend = GliumUiRenderer::new(&display);
let font_handle = kui.add_font_from_bytes(include_bytes!("../../assets/fonts/roboto/Roboto-Regular.ttf"));
event_loop.run(|event, window_target| {
window_target.set_control_flow(ControlFlow::Poll);
match event {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
window_target.exit();
},
Event::AboutToWait => {
let mut frame = display.draw();
frame.clear_color_srgb(0., 0., 0., 1.);
let resolution = UVec2::from(display.get_framebuffer_dimensions()).as_vec2();
kui.begin();
kui.add(Container {
gap: 5.,
padding: Sides::all(5.),
align: (Alignment::Begin, Alignment::Begin),
size: (UiSize::Percentage(1.), UiSize::Percentage(1.)),
elements: vec![
Box::new(Text {
text: "Hello_world".into(),
font: font_handle,
..Default::default()
}),
],
..Default::default()
}, resolution);
kui.end();
backend.update(&kui);
backend.draw(&mut frame, resolution);
frame.finish().unwrap();
}
_ => (),
}
}).unwrap();
}

View file

@ -0,0 +1,116 @@
use std::{time::Instant, vec};
use glam::{UVec2, vec4};
use glium::{backend::glutin::SimpleWindowBuilder, Surface};
use winit::{
event::{Event, WindowEvent},
event_loop::{EventLoopBuilder, ControlFlow}
};
use kubi_ui::{
KubiUi,
element::{
progress_bar::ProgressBar,
container::{Container, Sides, Alignment},
text::Text, rect::Rect, spacer::Spacer
},
UiSize,
elements,
};
use kubi_ui_glium::GliumUiRenderer;
fn main() {
kubi_logging::init();
let event_loop = EventLoopBuilder::new().build().unwrap();
let (window, display) = SimpleWindowBuilder::new().build(&event_loop);
window.set_title("Text rendering test");
let mut kui = KubiUi::new();
let mut backend = GliumUiRenderer::new(&display);
let font_handle = kui.add_font_from_bytes(include_bytes!("../../assets/fonts/roboto/Roboto-Regular.ttf"));
let instant = Instant::now();
event_loop.run(|event, window_target| {
window_target.set_control_flow(ControlFlow::Poll);
match event {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
window_target.exit();
},
Event::AboutToWait => {
let mut frame = display.draw();
frame.clear_color_srgb(0., 0., 0., 1.);
let resolution = UVec2::from(display.get_framebuffer_dimensions()).as_vec2();
kui.begin();
kui.add(Container {
size: (UiSize::Percentage(1.), UiSize::Percentage(1.)),
background: Some(vec4(0.1, 0.1, 0.1, 1.)),
elements: elements(|elem| {
elem.add(Text {
text: "THIS LINE SHOULD BE SHARP!".into(),
..Default::default()
});
elem.add(Text {
text: "THIS LINE SHOULD BE SHARP!".into(),
text_size: 32,
..Default::default()
});
elem.add(Text {
text: "All lines except 3 and 6 below will be blurry:".into(),
..Default::default()
});
for size in [9, 12, 16, 18, 24, 32] {
elem.add(Text {
text: "Testing default font, Proggy Tiny".into(),
text_size: size,
..Default::default()
});
}
elem.add(Rect {
size: (UiSize::Percentage(1.), UiSize::Pixels(10.)),
color: Some(vec4(0., 0., 1., 1.)),
});
elem.add(Rect {
size: (UiSize::Percentage(1.), UiSize::Pixels(10.)),
color: Some(vec4(1., 1., 0., 1.)),
});
elem.add(Text {
text: "Hello, world!\nżółty liść. życie nie ma sensu i wszyscy zginemy;\nтест кирилиці їїїїїїїїїїї\njapanese text: テスト".into(),
font: font_handle,
text_size: 32,
..Default::default()
});
if instant.elapsed().as_secs() & 1 != 0 {
elem.add(Rect {
size: (UiSize::Percentage(1.), UiSize::Pixels(10.)),
color: Some(vec4(1., 0., 0., 1.)),
});
elem.add(Rect {
size: (UiSize::Percentage(1.), UiSize::Pixels(10.)),
color: Some(vec4(0., 0., 0., 1.)),
});
elem.add(Spacer(100.));
elem.add(Text {
text: "FLAG SHOULD NOT OVERLAP WITH TEXT".into(),
text_size: 64,
color: vec4(1., 0., 1., 1.),
..Default::default()
});
}
}),
..Default::default()
}, resolution);
kui.end();
backend.update(&kui);
backend.draw(&mut frame, resolution);
frame.finish().unwrap();
}
_ => (),
}
}).unwrap();
}

View file

@ -6,16 +6,7 @@ precision highp sampler2D;
out vec4 out_color; out vec4 out_color;
in vec4 vtx_color; in vec4 vtx_color;
in vec2 vtx_uv; in vec2 vtx_uv;
uniform bool use_tex;
uniform sampler2D tex;
void main() { void main() {
//if (vtx_color.w <= 0.) discard; out_color = vtx_color;
vec4 tex_color;
if (use_tex) {
tex_color = texture(tex, vtx_uv);
} else {
tex_color = vec4(1.);
}
out_color = tex_color * vtx_color;
} }

View file

@ -0,0 +1,13 @@
#version 300 es
precision highp float;
precision highp sampler2D;
out vec4 out_color;
in vec4 vtx_color;
in vec2 vtx_uv;
uniform sampler2D tex;
void main() {
out_color = texture(tex, vtx_uv) * vtx_color;
}

View file

@ -7,7 +7,7 @@ use glium::{
texture::{SrgbTexture2d, RawImage2d}, texture::{SrgbTexture2d, RawImage2d},
index::PrimitiveType, index::PrimitiveType,
implement_vertex, implement_vertex,
uniform, uniforms::DynamicUniforms, uniform, uniforms::{Sampler, SamplerBehavior, SamplerWrapFunction},
}; };
use kubi_ui::{ use kubi_ui::{
KubiUi, KubiUi,
@ -17,6 +17,7 @@ use kubi_ui::{
const VERTEX_SHADER: &str = include_str!("../shaders/vertex.vert"); const VERTEX_SHADER: &str = include_str!("../shaders/vertex.vert");
const FRAGMENT_SHADER: &str = include_str!("../shaders/fragment.frag"); const FRAGMENT_SHADER: &str = include_str!("../shaders/fragment.frag");
const FRAGMENT_SHADER_TEX: &str = include_str!("../shaders/fragment_tex.frag");
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(C)] #[repr(C)]
@ -114,6 +115,7 @@ struct GlDrawCall {
pub struct GliumUiRenderer { pub struct GliumUiRenderer {
context: Rc<Context>, context: Rc<Context>,
program: glium::Program, program: glium::Program,
program_tex: glium::Program,
font_texture: Option<Rc<SrgbTexture2d>>, font_texture: Option<Rc<SrgbTexture2d>>,
plan: Vec<GlDrawCall>, plan: Vec<GlDrawCall>,
} }
@ -123,6 +125,7 @@ impl GliumUiRenderer {
log::info!("init glium backend for kui"); log::info!("init glium backend for kui");
Self { Self {
program: Program::from_source(facade, VERTEX_SHADER, FRAGMENT_SHADER, None).unwrap(), program: Program::from_source(facade, VERTEX_SHADER, FRAGMENT_SHADER, None).unwrap(),
program_tex: Program::from_source(facade, VERTEX_SHADER, FRAGMENT_SHADER_TEX, None).unwrap(),
context: Rc::clone(facade.get_context()), context: Rc::clone(facade.get_context()),
font_texture: None, font_texture: None,
plan: vec![] plan: vec![]
@ -200,11 +203,13 @@ impl GliumUiRenderer {
frame.draw( frame.draw(
vtx_buffer, vtx_buffer,
idx_buffer, idx_buffer,
&self.program, &self.program_tex,
&uniform! { &uniform! {
resolution: resolution.to_array(), resolution: resolution.to_array(),
tex: bind_texture.as_ref(), tex: Sampler(bind_texture.as_ref(), SamplerBehavior {
use_tex: true, wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp),
..Default::default()
}),
}, },
&params, &params,
).unwrap(); ).unwrap();
@ -215,7 +220,6 @@ impl GliumUiRenderer {
&self.program, &self.program,
&uniform! { &uniform! {
resolution: resolution.to_array(), resolution: resolution.to_array(),
use_tex: false,
}, },
&params, &params,
).unwrap(); ).unwrap();

View file

@ -160,12 +160,15 @@ impl UiDrawPlan {
let mut layout = Layout::new(CoordinateSystem::PositiveYDown); let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
layout.append( layout.append(
&[tr.internal_font(*font)], &[tr.internal_font(*font)],
&TextStyle::new(&text, *size as f32, 0) &TextStyle::new(text, *size as f32, 0)
); );
let glyphs = layout.glyphs(); let glyphs = layout.glyphs();
//let mut rpos_x = 0.; //let mut rpos_x = 0.;
for layout_glyph in glyphs { for layout_glyph in glyphs {
if !layout_glyph.char_data.rasterize() {
continue
}
let vidx = swapper.current().vertices.len() as u32; let vidx = swapper.current().vertices.len() as u32;
let glyph = tr.glyph(*font, layout_glyph.parent, layout_glyph.key.px as u8); let glyph = tr.glyph(*font, layout_glyph.parent, layout_glyph.key.px as u8);
//rpos_x += glyph.metrics.advance_width;//glyph.metrics.advance_width; //rpos_x += glyph.metrics.advance_width;//glyph.metrics.advance_width;

View file

@ -88,10 +88,19 @@ impl Default for Container {
impl Container { impl Container {
pub fn measure_max_inner_size(&self, layout: &LayoutInfo) -> Vec2 { pub fn measure_max_inner_size(&self, layout: &LayoutInfo) -> Vec2 {
//TODO take explicit size into account let outer_size_x = match self.size.0 {
layout.max_size - vec2( UiSize::Auto => layout.max_size.x,
self.padding.left + self.padding.right, UiSize::Percentage(p) => layout.max_size.x * p,
self.padding.top + self.padding.bottom, UiSize::Pixels(p) => p,
};
let outer_size_y = match self.size.1 {
UiSize::Auto => layout.max_size.y,
UiSize::Percentage(p) => layout.max_size.y * p,
UiSize::Pixels(p) => p,
};
vec2(
outer_size_x - (self.padding.left + self.padding.right),
outer_size_y - (self.padding.top + self.padding.bottom),
) )
} }
} }

View file

@ -8,7 +8,7 @@ use crate::{
draw::{UiDrawCommand, UiDrawCommands} draw::{UiDrawCommand, UiDrawCommands}
}; };
pub struct Spacer(f32); pub struct Spacer(pub f32);
impl Default for Spacer { impl Default for Spacer {
fn default() -> Self { fn default() -> Self {

View file

@ -13,16 +13,18 @@ pub struct Text {
pub text: Cow<'static, str>, pub text: Cow<'static, str>,
pub size: (UiSize, UiSize), pub size: (UiSize, UiSize),
pub color: Vec4, pub color: Vec4,
pub font: FontHandle pub font: FontHandle,
pub text_size: u8,
} }
impl Default for Text { impl Default for Text {
fn default() -> Self { fn default() -> Self {
Self { Self {
text: "".into(), text: "".into(),
size: (UiSize::Percentage(1.), UiSize::Pixels(32.)), size: (UiSize::Auto, UiSize::Auto),
color: Vec4::new(1., 1., 1., 1.), color: Vec4::new(1., 1., 1., 1.),
font: FontHandle(0) font: FontHandle(0),
text_size: 16,
} }
} }
} }
@ -37,7 +39,7 @@ impl UiElement for Text {
UiSize::Pixels(pixels) => pixels, UiSize::Pixels(pixels) => pixels,
}, },
match self.size.1 { match self.size.1 {
UiSize::Auto => layout.max_size.y, UiSize::Auto => self.text_size as f32,
UiSize::Percentage(percentage) => layout.max_size.y * percentage, UiSize::Percentage(percentage) => layout.max_size.y * percentage,
UiSize::Pixels(pixels) => pixels, UiSize::Pixels(pixels) => pixels,
}, },
@ -51,7 +53,7 @@ impl UiElement for Text {
draw.add(UiDrawCommand::Text { draw.add(UiDrawCommand::Text {
text: self.text.clone(), text: self.text.clone(),
position: layout.position, position: layout.position,
size: 32, size: self.text_size,
color: self.color, color: self.color,
font: self.font font: self.font
}); });

View file

@ -114,3 +114,16 @@ pub struct LayoutInfo {
pub max_size: Vec2, pub max_size: Vec2,
pub direction: UiDirection, pub direction: UiDirection,
} }
pub struct ElementList(Vec<Box<dyn UiElement>>);
impl ElementList {
pub fn add(&mut self, element: impl UiElement + 'static) {
self.0.push(Box::new(element));
}
}
pub fn elements(f: impl FnOnce(&mut ElementList)) -> Vec<Box<dyn UiElement>> {
let mut elements = ElementList(Vec::new());
f(&mut elements);
elements.0
}