document stuff

This commit is contained in:
griffi-gh 2024-02-20 18:19:10 +01:00
parent 8de7c4673e
commit 9ff9b8356d
4 changed files with 81 additions and 1 deletions

View file

@ -156,6 +156,7 @@ impl GliumUiRenderer {
const NO_FNT_TEX: &str = "Font texture exists in draw plan but not yet inited. Make sure to call update_font_texture() *before* update_draw_plan()";
Some(Rc::clone(self.font_texture.as_ref().expect(NO_FNT_TEX)))
},
Some(BindTexture::UserDefined(_)) => todo!("user defined textures are not implemented yet"),
None => None,
}
}

View file

@ -1,3 +1,5 @@
//! Stuff related to tesselation and UI rendering.
use crate::{IfModified, text::{TextRenderer, FontHandle}};
mod corner_radius;
@ -24,6 +26,7 @@ pub enum UiDrawCommand {
///Rounded corners
rounded_corners: Option<RoundedCorners>,
},
/// Filled, colored circle
Circle {
///Position in pixels
position: Vec2,
@ -32,6 +35,7 @@ pub enum UiDrawCommand {
///Color (RGBA)
color: Vec4,
},
/// Draw text using the specified font, size, color, and position
Text {
///Position in pixels
position: Vec2,
@ -56,12 +60,14 @@ impl UiDrawCommand {
}
}
/// List of draw commands
#[derive(Default)]
pub struct UiDrawCommandList {
pub commands: Vec<UiDrawCommand>,
}
impl UiDrawCommandList {
/// Add a draw command to the list
pub fn add(&mut self, command: UiDrawCommand) {
self.commands.push(command);
}
@ -74,12 +80,20 @@ impl UiDrawCommandList {
// }
// }
/// Texture to bind for a draw call
///
/// - FontTexture: The internally managed font texture
/// - UserDefined: User-defined texture, value is user-defined and usually depends on the render backend
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BindTexture {
/// The internally managed font texture
FontTexture,
//UserDefined(usize),
/// User-defined texture, value is user-defined and usually depends on the render backend
UserDefined(usize),
}
/// A vertex for UI rendering
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct UiVertex {
pub position: Vec2,
@ -87,6 +101,7 @@ pub struct UiVertex {
pub uv: Vec2,
}
/// Represents a single draw call, should be handled by the render backend
#[derive(Default)]
pub struct UiDrawCall {
pub vertices: Vec<UiVertex>,
@ -94,6 +109,7 @@ pub struct UiDrawCall {
pub bind_texture: Option<BindTexture>,
}
/// Represents a complete UI rendering plan (a list of optimized draw calls).
#[derive(Default)]
pub struct UiDrawPlan {
pub calls: Vec<UiDrawCall>
@ -131,6 +147,7 @@ impl CallSwapper {
}
impl UiDrawPlan {
/// Tesselate the UI and build a complete draw plan from a list of draw commands
pub fn build(draw_commands: &UiDrawCommandList, tr: &mut TextRenderer) -> Self {
let mut swapper = CallSwapper::new();
let mut prev_command: Option<&UiDrawCommand> = None;

View file

@ -10,12 +10,14 @@ use crate::{
mod builtin;
pub use builtin::*;
/// Context for the `Element::measure` function
pub struct MeasureContext<'a> {
pub state: &'a StateRepo,
pub layout: &'a LayoutInfo,
pub text_measure: TextMeasure<'a>,
}
/// Context for the `Element::process` function
pub struct ProcessContext<'a> {
pub measure: &'a Response,
pub state: &'a mut StateRepo,
@ -25,11 +27,36 @@ pub struct ProcessContext<'a> {
}
pub trait UiElement {
/// Get the name of the element, for example "Button" or "ProgressBar"
fn name(&self) -> &'static str { "UiElement" }
/// Get the unique id used for internal state management\
/// This value must be unique for each instance of the element
///
/// If the element is stateless, this function should return `None`
fn state_id(&self) -> Option<u64> { None }
/// Check if the element has state
fn is_stateful(&self) -> bool { self.state_id().is_some() }
/// Check if the element has no state
fn is_stateless(&self) -> bool { self.state_id().is_none() }
/// Initialize the state of the element\
/// This function should be called exactly once during the lifetime of the element,
/// or if the state gets reset
///
/// This function will not get called for stateless elements
fn init_state(&self) -> Option<Box<dyn Any>> { None }
/// Measure step, guaranteed to be called before the `process` step\
/// May be called multiple times per single frame, so it should not contain any expensive calls\
/// This function may not mutate any state.\
///
/// This function should return the size of the element along with any hints or layout metadata
fn measure(&self, ctx: MeasureContext) -> Response;
/// Process step, guaranteed to be called after the `measure` step\
/// You should process the user inputs and render the element here.
fn process(&self, ctx: ProcessContext);
}

View file

@ -9,6 +9,8 @@ use crate:: {
text::{TextRenderer, FontTextureInfo, FontHandle},
};
/// The main instance of the UI system.\
/// In most cases, you should only have one instance of this struct.
pub struct UiInstance {
//mouse_position: Vec2,
stateful_state: StateRepo,
@ -22,6 +24,9 @@ pub struct UiInstance {
}
impl UiInstance {
/// Crate and initialize a new instance of the UI
///
/// In most cases, you should only do this *once*, during the initialization of your application
pub fn new() -> Self {
UiInstance {
//mouse_position: Vec2::ZERO,
@ -38,10 +43,16 @@ impl UiInstance {
}
}
/// Parse and add a font from a raw byte slice to the UI\
/// Returns a font handle.
pub fn add_font_from_bytes(&mut self, font: &[u8]) -> FontHandle {
self.text_renderer.add_font_from_bytes(font)
}
/// Add an element or an element tree to the UI
///
/// Use the `max_size` parameter to specify the maximum size of the element\
/// (usually, the size of the window/screen)
pub fn add<T: UiElement>(&mut self, element: T, max_size: Vec2) {
let layout = LayoutInfo {
position: Vec2::ZERO,
@ -62,6 +73,9 @@ impl UiInstance {
});
}
/// Prepare the UI for layout and processing
///
/// You must call this function at the beginning of the frame, before adding any elements
pub fn begin(&mut self) {
std::mem::swap(&mut self.prev_draw_commands, &mut self.draw_commands);
self.draw_plan_modified = false;
@ -69,6 +83,9 @@ impl UiInstance {
self.text_renderer.reset_frame();
}
/// End the frame and prepare the UI for rendering
///
/// You must call this function at the end of the frame, before rendering the UI
pub fn end(&mut self) {
if self.draw_commands.commands == self.prev_draw_commands.commands {
return
@ -77,14 +94,32 @@ impl UiInstance {
self.draw_plan_modified = true;
}
/// Get the draw plan (a list of draw calls) for the current frame
///
/// This function should only be used by the render backend.\
/// You should not call this directly unless you're implementing a custom render backend
///
/// Returns a tuple with a boolean indicating if the draw plan was modified since the last frame
pub fn draw_plan(&self) -> (bool, &UiDrawPlan) {
(self.draw_plan_modified, &self.draw_plan)
}
/// Get the font texture for the current frame
///
/// This function should only be used by the render backend.\
/// You should not call this directly unless you're implementing a custom render backend
///
/// Make sure to check `FontTextureInfo::modified` to see if the texture was modified
/// since the last frame before uploading it to the GPU
pub fn font_texture(&self) -> FontTextureInfo {
self.text_renderer.font_texture()
}
/// Push a platform event to the UI event queue
///
/// This function should only be used by the platform backend.\
/// You should not call this directly unless you're implementing a custom platform backend
/// or have a very specific usecase
pub fn push_event(&mut self, event: UiEvent) {
self.events.push_back(event);
}