api and doc stuff, add bg image prop to container

This commit is contained in:
griffi-gh 2024-03-07 01:11:53 +01:00
parent 1c55b1217b
commit 806e0ce8d1
4 changed files with 61 additions and 12 deletions

View file

@ -9,7 +9,7 @@ use crate::{
pub(crate) mod atlas; pub(crate) mod atlas;
use atlas::TextureAtlasManager; use atlas::TextureAtlasManager;
pub use atlas::{TextureHandle, TextureAtlasMeta}; pub use atlas::{TextureHandle, TextureAtlasMeta, TextureFormat};
mod corner_radius; mod corner_radius;
pub use corner_radius::RoundedCorners; pub use corner_radius::RoundedCorners;
@ -85,7 +85,7 @@ pub struct UiVertex {
pub uv: Vec2, pub uv: Vec2,
} }
/// Represents a single draw call, should be handled by the render backend /// Represents a single draw call (vertices + indices), should be handled by the render backend
#[derive(Default)] #[derive(Default)]
pub struct UiDrawCall { pub struct UiDrawCall {
pub vertices: Vec<UiVertex>, pub vertices: Vec<UiVertex>,

View file

@ -5,8 +5,25 @@ use rect_packer::DensePacker;
use crate::rectangle::Corners; use crate::rectangle::Corners;
const RGBA_CHANNEL_COUNT: u32 = 4; const RGBA_CHANNEL_COUNT: u32 = 4;
//TODO make this work
const ALLOW_ROTATION: bool = false; const ALLOW_ROTATION: bool = false;
/// Texture format of the source texture data
#[derive(Default, Clone, Copy, PartialEq, Eq)]
pub enum TextureFormat {
/// The data is stored in RGBA format, with 1 byte (8 bits) per channel
#[default]
Rgba,
/// The data is copied into the Alpha channel, with 1 byte (8 bits) per channel\
/// Remaining channels are set to 255 (which can be easily shaded to any color)
///
/// This format is useful for storing grayscale textures such as icons\
/// (Please note that the internal representation is still RGBA, this is just a convenience feature)
Grayscale,
}
/// Contains a reference to the texture data, and metadata associated with it
pub struct TextureAtlasMeta<'a> { pub struct TextureAtlasMeta<'a> {
/// Texture data\ /// Texture data\
/// The data is stored in RGBA format, with 1 byte (8 bits) per channel /// The data is stored in RGBA format, with 1 byte (8 bits) per channel
@ -157,7 +174,7 @@ impl TextureAtlasManager {
/// Allocate a new texture region in the atlas and copy the data into it\ /// Allocate a new texture region in the atlas and copy the data into it\
/// This function may resize the atlas as needed, and should never fail under normal circumstances. /// This function may resize the atlas as needed, and should never fail under normal circumstances.
pub fn add(&mut self, width: usize, data: &[u8]) -> TextureHandle { pub(crate) fn add_rgba(&mut self, width: usize, data: &[u8]) -> TextureHandle {
let size = uvec2(width as u32, (data.len() / (width * RGBA_CHANNEL_COUNT as usize)) as u32); let size = uvec2(width as u32, (data.len() / (width * RGBA_CHANNEL_COUNT as usize)) as u32);
let handle: TextureHandle = self.allocate(size); let handle: TextureHandle = self.allocate(size);
let allocation = self.allocations.get(&handle.index).unwrap(); let allocation = self.allocations.get(&handle.index).unwrap();
@ -178,7 +195,7 @@ impl TextureAtlasManager {
/// Works the same way as [`TextureAtlasManager::add`], but the input data is assumed to be grayscale (1 channel per pixel)\ /// Works the same way as [`TextureAtlasManager::add`], but the input data is assumed to be grayscale (1 channel per pixel)\
/// The data is copied into the alpha channel of the texture, while all the other channels are set to 255\ /// The data is copied into the alpha channel of the texture, while all the other channels are set to 255\
/// May resize the atlas as needed, and should never fail under normal circumstances. /// May resize the atlas as needed, and should never fail under normal circumstances.
pub fn add_grayscale(&mut self, width: usize, data: &[u8]) -> TextureHandle { pub(crate) fn add_grayscale(&mut self, width: usize, data: &[u8]) -> TextureHandle {
let size = uvec2(width as u32, (data.len() / width) as u32); let size = uvec2(width as u32, (data.len() / width) as u32);
let handle = self.allocate(size); let handle = self.allocate(size);
let allocation = self.allocations.get(&handle.index).unwrap(); let allocation = self.allocations.get(&handle.index).unwrap();
@ -194,6 +211,13 @@ impl TextureAtlasManager {
handle handle
} }
pub fn add(&mut self, width: usize, data: &[u8], format: TextureFormat) -> TextureHandle {
match format {
TextureFormat::Rgba => self.add_rgba(width, data),
TextureFormat::Grayscale => self.add_grayscale(width, data),
}
}
pub fn modify(&mut self, handle: TextureHandle) { pub fn modify(&mut self, handle: TextureHandle) {
todo!() todo!()
} }

View file

@ -4,9 +4,9 @@ use derive_setters::Setters;
use glam::{Vec2, vec2}; use glam::{Vec2, vec2};
use crate::{ use crate::{
background::BackgroundColor, background::BackgroundColor,
draw::{RoundedCorners, UiDrawCommand}, draw::{RoundedCorners, TextureHandle, UiDrawCommand},
element::{ElementList, MeasureContext, ProcessContext, UiElement}, element::{ElementList, MeasureContext, ProcessContext, UiElement},
layout::{Alignment, Alignment2d, LayoutInfo, UiDirection, Size, Size2d}, layout::{Alignment, Alignment2d, LayoutInfo, Size, Size2d, UiDirection},
measure::{Hints, Response}, measure::{Hints, Response},
rectangle::{Corners, Sides} rectangle::{Corners, Sides}
}; };
@ -55,10 +55,19 @@ pub struct Container {
#[setters(into)] #[setters(into)]
pub align: Alignment2d, pub align: Alignment2d,
/// Background color of the container /// Background color of the container\
///
/// If the container has a background texture, it will be multiplied by this color
#[setters(into)] #[setters(into)]
pub background: BackgroundColor, pub background: BackgroundColor,
/// Background texture of the container
///
/// Can be used in conjunction with the background color\
/// In this case, the texture will be shaded by the color
#[setters(into)]
pub background_image: Option<TextureHandle>,
/// Corner radius of the background rectangle /// Corner radius of the background rectangle
#[setters(into)] #[setters(into)]
pub corner_radius: Corners<f32>, pub corner_radius: Corners<f32>,
@ -88,6 +97,7 @@ impl Default for Container {
padding: Sides::all(0.), padding: Sides::all(0.),
align: Alignment2d::default(), align: Alignment2d::default(),
background: Default::default(), background: Default::default(),
background_image: None,
children: ElementList(Vec::new()), children: ElementList(Vec::new()),
wrap: false, wrap: false,
corner_radius: Corners::all(0.), corner_radius: Corners::all(0.),

View file

@ -1,8 +1,7 @@
use glam::Vec2; use glam::Vec2;
use crate::{ use crate::{
draw::{ draw::{
atlas::{TextureAtlasManager, TextureAtlasMeta}, atlas::{TextureAtlasManager, TextureAtlasMeta}, TextureFormat, TextureHandle, UiDrawCall, UiDrawCommandList
UiDrawCall, UiDrawCommandList,
}, element::{MeasureContext, ProcessContext, UiElement}, event::{EventQueue, UiEvent}, input::UiInputState, layout::{LayoutInfo, UiDirection}, state::StateRepo, text::{FontHandle, TextRenderer} }, element::{MeasureContext, ProcessContext, UiElement}, event::{EventQueue, UiEvent}, input::UiInputState, layout::{LayoutInfo, UiDirection}, state::StateRepo, text::{FontHandle, TextRenderer}
}; };
@ -45,7 +44,7 @@ impl UiInstance {
atlas: { atlas: {
let mut atlas = TextureAtlasManager::default(); let mut atlas = TextureAtlasManager::default();
//HACK: Ensure that vec(0, 0) uv is white square //HACK: Ensure that vec(0, 0) uv is white square
atlas.add(1, &[255, 255, 255, 255]); atlas.add_rgba(1, &[255, 255, 255, 255]);
atlas atlas
}, },
events: EventQueue::new(), events: EventQueue::new(),
@ -58,10 +57,23 @@ impl UiInstance {
/// TrueType (`.ttf`/`.ttc`) and OpenType (`.otf`) fonts are supported\ /// TrueType (`.ttf`/`.ttc`) and OpenType (`.otf`) fonts are supported\
/// ///
/// Returns a font handle ([`FontHandle`]). /// Returns a font handle ([`FontHandle`]).
///
/// ## Panics:
/// If the font data is invalid or corrupt
pub fn add_font(&mut self, font: &[u8]) -> FontHandle { pub fn add_font(&mut self, font: &[u8]) -> FontHandle {
self.text_renderer.add_font_from_bytes(font) self.text_renderer.add_font_from_bytes(font)
} }
/// Add an image to the texture atlas\
/// Accepted texture formats are `Rgba` and `Grayscale`
///
/// Returns a texture handle ([`TextureHandle`])\
/// This handle can be used to reference the texture in draw commands\
/// It's a light reference and can be cloned/copied freely, but will not be cleaned up even when dropped
pub fn add_image(&mut self, format: TextureFormat, data: &[u8], width: usize) -> TextureHandle {
self.atlas.add(width, data, format)
}
/// Push a font to the font stack\ /// Push a font to the font stack\
/// The font will be used for all text rendering until it is popped /// The font will be used for all text rendering until it is popped
/// ///
@ -88,6 +100,9 @@ impl UiInstance {
/// ///
/// Use the `max_size` parameter to specify the maximum size of the element\ /// Use the `max_size` parameter to specify the maximum size of the element\
/// (usually, the size of the window/screen) /// (usually, the size of the window/screen)
///
/// ## Panics:
/// If called while the UI is not active (call [`UiInstance::begin`] first)
pub fn add<T: UiElement>(&mut self, element: T, max_size: Vec2) { pub fn add<T: UiElement>(&mut self, element: T, max_size: Vec2) {
assert!(self.state, "must call UiInstance::begin before adding elements"); assert!(self.state, "must call UiInstance::begin before adding elements");
let layout = LayoutInfo { let layout = LayoutInfo {
@ -114,7 +129,7 @@ impl UiInstance {
/// Prepare the UI for layout and processing\ /// Prepare the UI for layout and processing\
/// You must call this function at the beginning of the frame, before adding any elements\ /// You must call this function at the beginning of the frame, before adding any elements\
/// ///
/// # Panics /// ## Panics:
/// If called twice in a row (for example, if you forget to call [`UiInstance::end`])\ /// If called twice in a row (for example, if you forget to call [`UiInstance::end`])\
/// This is an indication of a bug in your code and should be fixed. /// This is an indication of a bug in your code and should be fixed.
pub fn begin(&mut self) { pub fn begin(&mut self) {
@ -137,7 +152,7 @@ impl UiInstance {
/// End the frame and prepare the UI for rendering\ /// End the frame and prepare the UI for rendering\
/// You must call this function at the end of the frame, before rendering the UI /// You must call this function at the end of the frame, before rendering the UI
/// ///
/// # Panics /// ## Panics:
/// If called without calling [`UiInstance::begin`] first. (or if called twice)\ /// If called without calling [`UiInstance::begin`] first. (or if called twice)\
/// This is an indication of a bug in your code and should be fixed. /// This is an indication of a bug in your code and should be fixed.
pub fn end(&mut self) { pub fn end(&mut self) {