hUI/hui-glium/src/lib.rs

197 lines
6.4 KiB
Rust
Raw Normal View History

2024-02-17 14:43:46 -06:00
use std::rc::Rc;
use glam::Vec2;
use glium::{
2024-03-25 09:37:32 -05:00
backend::{Context, Facade}, implement_vertex, index::PrimitiveType, texture::{RawImage2d, Texture2d}, uniform, uniforms::{MagnifySamplerFilter, MinifySamplerFilter, Sampler, SamplerBehavior, SamplerWrapFunction}, Api, Blend, DrawParameters, IndexBuffer, Program, Surface, VertexBuffer
2024-02-17 14:43:46 -06:00
};
use hui::{
2024-02-24 21:02:10 -06:00
draw::{TextureAtlasMeta, UiDrawCall, UiVertex}, UiInstance
2024-02-17 14:43:46 -06:00
};
2024-03-25 09:37:32 -05:00
const VERTEX_SHADER_GLES3: &str = include_str!("../shaders/vertex.es.vert");
const FRAGMENT_SHADER_GLES3: &str = include_str!("../shaders/fragment.es.frag");
const VERTEX_SHADER_150: &str = include_str!("../shaders/vertex.150.vert");
const FRAGMENT_SHADER_150: &str = include_str!("../shaders/fragment.150.frag");
2024-02-17 14:43:46 -06:00
#[derive(Clone, Copy)]
#[repr(C)]
struct Vertex {
position: [f32; 2],
color: [f32; 4],
uv: [f32; 2],
}
impl From<UiVertex> for Vertex {
fn from(v: UiVertex) -> Self {
Self {
position: v.position.to_array(),
color: v.color.to_array(),
uv: v.uv.to_array(),
}
}
}
implement_vertex!(Vertex, position, color, uv);
struct BufferPair {
pub vertex_buffer: glium::VertexBuffer<Vertex>,
pub index_buffer: glium::IndexBuffer<u32>,
pub vertex_count: usize,
pub index_count: usize,
}
impl BufferPair {
pub fn new<F: Facade>(facade: &F) -> Self {
2024-02-21 13:13:58 -06:00
log::debug!("init ui buffers (empty)...");
2024-02-17 14:43:46 -06:00
Self {
vertex_buffer: VertexBuffer::empty_dynamic(facade, 1024).unwrap(),
index_buffer: IndexBuffer::empty_dynamic(facade, PrimitiveType::TrianglesList, 1024).unwrap(),
vertex_count: 0,
index_count: 0,
}
}
2024-02-21 13:13:58 -06:00
pub fn new_with_data<F: Facade>(facade: &F, vtx: &[Vertex], idx: &[u32]) -> Self {
log::debug!("init ui buffers (data)...");
Self {
vertex_buffer: VertexBuffer::dynamic(facade, vtx).unwrap(),
index_buffer: IndexBuffer::dynamic(facade, PrimitiveType::TrianglesList, idx).unwrap(),
vertex_count: vtx.len(),
index_count: idx.len(),
2024-02-21 13:13:58 -06:00
}
}
2024-02-17 14:43:46 -06:00
pub fn ensure_buffer_size(&mut self, need_vtx: usize, need_idx: usize) {
let current_vtx_size = self.vertex_buffer.get_size() / std::mem::size_of::<Vertex>();
let current_idx_size = self.index_buffer.get_size() / std::mem::size_of::<u32>();
//log::debug!("current vtx size: {}, current idx size: {}", current_vtx_size, current_idx_size);
if current_vtx_size >= need_vtx && current_idx_size >= need_idx {
return
}
let new_vtx_size = (need_vtx + 1).next_power_of_two();
let new_idx_size = (need_idx + 1).next_power_of_two();
log::debug!("resizing buffers: vtx {} -> {}, idx {} -> {}", current_vtx_size, new_vtx_size, current_idx_size, new_idx_size);
if current_vtx_size != new_vtx_size {
self.vertex_buffer = VertexBuffer::empty_dynamic(
self.vertex_buffer.get_context(),
new_vtx_size
).unwrap();
}
if current_idx_size != new_idx_size {
self.index_buffer = IndexBuffer::empty_dynamic(
self.index_buffer.get_context(),
PrimitiveType::TrianglesList,
new_idx_size
).unwrap();
}
}
pub fn write_data(&mut self, vtx: &[Vertex], idx: &[u32]) {
//log::trace!("uploading {} vertices and {} indices", vtx.len(), idx.len());
self.vertex_count = vtx.len();
self.index_count = idx.len();
if self.vertex_count == 0 || self.index_count == 0 {
2024-03-06 13:58:50 -06:00
self.vertex_buffer.invalidate();
self.index_buffer.invalidate();
2024-02-17 14:43:46 -06:00
return
}
self.ensure_buffer_size(self.vertex_count, self.index_count);
self.vertex_buffer.slice_mut(0..self.vertex_count).unwrap().write(vtx);
self.index_buffer.slice_mut(0..self.index_count).unwrap().write(idx);
}
pub fn is_empty(&self) -> bool {
self.vertex_count == 0 || self.index_count == 0
}
}
pub struct GliumUiRenderer {
context: Rc<Context>,
program: glium::Program,
2024-03-06 19:47:10 -06:00
ui_texture: Option<Texture2d>,
2024-02-21 13:13:58 -06:00
buffer_pair: Option<BufferPair>,
2024-02-17 14:43:46 -06:00
}
impl GliumUiRenderer {
pub fn new<F: Facade>(facade: &F) -> Self {
log::info!("initializing hui-glium");
2024-02-17 14:43:46 -06:00
Self {
2024-03-25 09:37:32 -05:00
program: match facade.get_context().get_supported_glsl_version().0 {
Api::Gl => Program::from_source(facade, VERTEX_SHADER_150, FRAGMENT_SHADER_150, None).unwrap(),
Api::GlEs => Program::from_source(facade, VERTEX_SHADER_GLES3, FRAGMENT_SHADER_GLES3, None).unwrap(),
},
2024-02-17 14:43:46 -06:00
context: Rc::clone(facade.get_context()),
2024-02-21 13:13:58 -06:00
ui_texture: None,
buffer_pair: None,
2024-02-17 14:43:46 -06:00
}
}
fn update_buffers(&mut self, call: &UiDrawCall) {
2024-03-01 11:45:56 -06:00
log::trace!("updating ui buffers (tris: {})", call.indices.len() / 3);
2024-02-21 13:13:58 -06:00
let data_vtx = &call.vertices.iter().copied().map(Vertex::from).collect::<Vec<_>>()[..];
let data_idx = &call.indices[..];
if let Some(buffer) = &mut self.buffer_pair {
buffer.write_data(data_vtx, data_idx);
} else if !call.indices.is_empty() {
self.buffer_pair = Some(BufferPair::new_with_data(&self.context, data_vtx, data_idx));
2024-02-17 14:43:46 -06:00
}
}
fn update_texture_atlas(&mut self, atlas: &TextureAtlasMeta) {
2024-02-24 21:02:10 -06:00
log::trace!("updating ui atlas texture");
2024-03-06 19:47:10 -06:00
self.ui_texture = Some(Texture2d::new(
2024-02-17 14:43:46 -06:00
&self.context,
RawImage2d::from_raw_rgba(
2024-02-24 21:02:10 -06:00
atlas.data.to_owned(),
(atlas.size.x, atlas.size.y)
2024-02-17 14:43:46 -06:00
)
2024-02-25 08:43:38 -06:00
).unwrap());
2024-02-17 14:43:46 -06:00
}
pub fn update(&mut self, instance: &UiInstance) {
if self.ui_texture.is_none() || instance.atlas().modified {
self.update_texture_atlas(&instance.atlas());
}
if self.buffer_pair.is_none() || instance.draw_call().0 {
self.update_buffers(instance.draw_call().1);
2024-02-17 14:43:46 -06:00
}
}
pub fn draw(&self, frame: &mut glium::Frame, resolution: Vec2) {
let params = DrawParameters {
blend: Blend::alpha_blending(),
..Default::default()
};
2024-02-21 13:13:58 -06:00
if let Some(buffer) = &self.buffer_pair {
if buffer.is_empty() {
return
2024-02-17 14:43:46 -06:00
}
2024-02-21 13:13:58 -06:00
let vtx_buffer = buffer.vertex_buffer.slice(0..buffer.vertex_count).unwrap();
let idx_buffer = buffer.index_buffer.slice(0..buffer.index_count).unwrap();
frame.draw(
vtx_buffer,
idx_buffer,
2024-02-24 21:02:10 -06:00
&self.program,
2024-02-21 13:13:58 -06:00
&uniform! {
resolution: resolution.to_array(),
2024-02-25 08:43:38 -06:00
tex: Sampler(self.ui_texture.as_ref().unwrap(), SamplerBehavior {
2024-03-12 12:19:04 -05:00
max_anisotropy: 1,
magnify_filter: MagnifySamplerFilter::Nearest,
2024-03-24 20:25:46 -05:00
minify_filter: MinifySamplerFilter::Linear,
2024-02-21 13:13:58 -06:00
wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp),
..Default::default()
}),
},
&params,
).unwrap();
2024-02-17 14:43:46 -06:00
}
}
}