mirror of
https://github.com/griffi-gh/hUI.git
synced 2024-12-22 12:28:19 -06:00
WIP single draw call architecture
This commit is contained in:
parent
3bcbe0ae6e
commit
f54b218cbb
|
@ -11,7 +11,7 @@ use glium::{
|
|||
};
|
||||
use hui::{
|
||||
UiInstance,
|
||||
draw::{UiDrawPlan, UiVertex, BindTexture},
|
||||
draw::{UiDrawCall, UiVertex, BindTexture},
|
||||
text::FontTextureInfo, IfModified,
|
||||
};
|
||||
|
||||
|
@ -48,7 +48,7 @@ struct BufferPair {
|
|||
|
||||
impl BufferPair {
|
||||
pub fn new<F: Facade>(facade: &F) -> Self {
|
||||
log::debug!("init ui buffers...");
|
||||
log::debug!("init ui buffers (empty)...");
|
||||
Self {
|
||||
vertex_buffer: VertexBuffer::empty_dynamic(facade, 1024).unwrap(),
|
||||
index_buffer: IndexBuffer::empty_dynamic(facade, PrimitiveType::TrianglesList, 1024).unwrap(),
|
||||
|
@ -57,6 +57,16 @@ impl BufferPair {
|
|||
}
|
||||
}
|
||||
|
||||
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: 0,
|
||||
index_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
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>();
|
||||
|
@ -106,18 +116,12 @@ impl BufferPair {
|
|||
}
|
||||
}
|
||||
|
||||
struct GlDrawCall {
|
||||
active: bool,
|
||||
buffer: BufferPair,
|
||||
bind_texture: Option<Rc<SrgbTexture2d>>,
|
||||
}
|
||||
|
||||
pub struct GliumUiRenderer {
|
||||
context: Rc<Context>,
|
||||
program: glium::Program,
|
||||
program_tex: glium::Program,
|
||||
font_texture: Option<Rc<SrgbTexture2d>>,
|
||||
plan: Vec<GlDrawCall>,
|
||||
ui_texture: Option<Rc<SrgbTexture2d>>,
|
||||
buffer_pair: Option<BufferPair>,
|
||||
}
|
||||
|
||||
impl GliumUiRenderer {
|
||||
|
@ -127,44 +131,33 @@ impl GliumUiRenderer {
|
|||
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()),
|
||||
font_texture: None,
|
||||
plan: vec![]
|
||||
ui_texture: None,
|
||||
buffer_pair: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_draw_plan(&mut self, plan: &UiDrawPlan) {
|
||||
if plan.calls.len() > self.plan.len() {
|
||||
self.plan.resize_with(plan.calls.len(), || {
|
||||
GlDrawCall {
|
||||
buffer: BufferPair::new(&self.context),
|
||||
bind_texture: None,
|
||||
active: false,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
for step in &mut self.plan[plan.calls.len()..] {
|
||||
step.active = false;
|
||||
}
|
||||
}
|
||||
for (idx, call) in plan.calls.iter().enumerate() {
|
||||
let data_vtx = &call.vertices.iter().copied().map(Vertex::from).collect::<Vec<_>>()[..];
|
||||
let data_idx = &call.indices[..];
|
||||
self.plan[idx].active = true;
|
||||
self.plan[idx].buffer.write_data(data_vtx, data_idx);
|
||||
self.plan[idx].bind_texture = match call.bind_texture {
|
||||
Some(BindTexture::FontTexture) => {
|
||||
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,
|
||||
}
|
||||
pub fn update_draw_plan(&mut self, call: &UiDrawCall) {
|
||||
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));
|
||||
}
|
||||
|
||||
// self.plan[0].bind_texture = match call.bind_texture {
|
||||
// Some(BindTexture::FontTexture) => {
|
||||
// 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,
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn update_font_texture(&mut self, font_texture: &FontTextureInfo) {
|
||||
pub fn update_ui_texture(&mut self, font_texture: &FontTextureInfo) {
|
||||
log::debug!("updating font texture");
|
||||
self.font_texture = Some(Rc::new(SrgbTexture2d::new(
|
||||
self.ui_texture = Some(Rc::new(SrgbTexture2d::new(
|
||||
&self.context,
|
||||
RawImage2d::from_raw_rgba(
|
||||
font_texture.data.to_owned(),
|
||||
|
@ -175,9 +168,9 @@ impl GliumUiRenderer {
|
|||
|
||||
pub fn update(&mut self, hui: &UiInstance) {
|
||||
if let Some(texture) = hui.font_texture().if_modified() {
|
||||
self.update_font_texture(texture);
|
||||
self.update_ui_texture(texture);
|
||||
}
|
||||
if let Some(plan) = hui.draw_plan().if_modified() {
|
||||
if let Some(plan) = hui.draw_call().if_modified() {
|
||||
self.update_draw_plan(plan);
|
||||
}
|
||||
}
|
||||
|
@ -188,43 +181,41 @@ impl GliumUiRenderer {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
for step in &self.plan {
|
||||
if !step.active {
|
||||
continue
|
||||
if let Some(buffer) = &self.buffer_pair {
|
||||
if buffer.is_empty() {
|
||||
return
|
||||
}
|
||||
|
||||
if step.buffer.is_empty() {
|
||||
continue
|
||||
}
|
||||
let vtx_buffer = buffer.vertex_buffer.slice(0..buffer.vertex_count).unwrap();
|
||||
let idx_buffer = buffer.index_buffer.slice(0..buffer.index_count).unwrap();
|
||||
|
||||
let vtx_buffer = step.buffer.vertex_buffer.slice(0..step.buffer.vertex_count).unwrap();
|
||||
let idx_buffer = step.buffer.index_buffer.slice(0..step.buffer.index_count).unwrap();
|
||||
frame.draw(
|
||||
vtx_buffer,
|
||||
idx_buffer,
|
||||
&self.program_tex,
|
||||
&uniform! {
|
||||
resolution: resolution.to_array(),
|
||||
tex: Sampler(self.ui_texture.as_ref().unwrap().as_ref(), SamplerBehavior {
|
||||
wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp),
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
¶ms,
|
||||
).unwrap();
|
||||
|
||||
if let Some(bind_texture) = step.bind_texture.as_ref() {
|
||||
frame.draw(
|
||||
vtx_buffer,
|
||||
idx_buffer,
|
||||
&self.program_tex,
|
||||
&uniform! {
|
||||
resolution: resolution.to_array(),
|
||||
tex: Sampler(bind_texture.as_ref(), SamplerBehavior {
|
||||
wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp),
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
¶ms,
|
||||
).unwrap();
|
||||
} else {
|
||||
frame.draw(
|
||||
vtx_buffer,
|
||||
idx_buffer,
|
||||
&self.program,
|
||||
&uniform! {
|
||||
resolution: resolution.to_array(),
|
||||
},
|
||||
¶ms,
|
||||
).unwrap();
|
||||
}
|
||||
// if let Some(bind_texture) = call.bind_texture.as_ref() {
|
||||
|
||||
// } else {
|
||||
// frame.draw(
|
||||
// vtx_buffer,
|
||||
// idx_buffer,
|
||||
// &self.program,
|
||||
// &uniform! {
|
||||
// resolution: resolution.to_array(),
|
||||
// },
|
||||
// ¶ms,
|
||||
// ).unwrap();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
118
hui/src/draw.rs
118
hui/src/draw.rs
|
@ -6,6 +6,7 @@ use crate::{
|
|||
IfModified
|
||||
};
|
||||
|
||||
mod atlas;
|
||||
mod corner_radius;
|
||||
|
||||
pub use corner_radius::RoundedCorners;
|
||||
|
@ -54,16 +55,6 @@ pub enum UiDrawCommand {
|
|||
},
|
||||
}
|
||||
|
||||
impl UiDrawCommand {
|
||||
fn texture_eq_index(&self) -> u64 {
|
||||
match self {
|
||||
UiDrawCommand::Rectangle { .. } |
|
||||
UiDrawCommand::Circle { .. } => u64::MAX - 1,
|
||||
UiDrawCommand::Text { .. } => u64::MAX - 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// List of draw commands
|
||||
#[derive(Default)]
|
||||
pub struct UiDrawCommandList {
|
||||
|
@ -110,80 +101,22 @@ pub struct UiVertex {
|
|||
pub struct UiDrawCall {
|
||||
pub vertices: Vec<UiVertex>,
|
||||
pub indices: Vec<u32>,
|
||||
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>
|
||||
}
|
||||
|
||||
struct CallSwapper {
|
||||
calls: Vec<UiDrawCall>,
|
||||
call: UiDrawCall,
|
||||
}
|
||||
|
||||
impl CallSwapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
calls: vec![],
|
||||
call: UiDrawCall::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current(&self) -> &UiDrawCall {
|
||||
&self.call
|
||||
}
|
||||
|
||||
pub fn current_mut(&mut self) -> &mut UiDrawCall {
|
||||
&mut self.call
|
||||
}
|
||||
|
||||
pub fn swap(&mut self) {
|
||||
self.calls.push(std::mem::take(&mut self.call));
|
||||
}
|
||||
|
||||
pub fn finish(mut self) -> Vec<UiDrawCall> {
|
||||
self.calls.push(self.call);
|
||||
self.calls
|
||||
}
|
||||
}
|
||||
|
||||
impl UiDrawPlan {
|
||||
impl UiDrawCall {
|
||||
/// 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;
|
||||
let mut draw_call = UiDrawCall::default();
|
||||
for command in &draw_commands.commands {
|
||||
let do_swap = if let Some(prev_command) = prev_command {
|
||||
//std::mem::discriminant(prev_command) != std::mem::discriminant(command)
|
||||
prev_command.texture_eq_index() != command.texture_eq_index()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if do_swap {
|
||||
swapper.swap();
|
||||
}
|
||||
|
||||
if do_swap || prev_command.is_none() {
|
||||
swapper.current_mut().bind_texture = match command {
|
||||
UiDrawCommand::Rectangle { .. } |
|
||||
UiDrawCommand::Circle { .. } => None,
|
||||
UiDrawCommand::Text { .. } => Some(BindTexture::FontTexture),
|
||||
}
|
||||
}
|
||||
|
||||
match command {
|
||||
UiDrawCommand::Rectangle { position, size, color, rounded_corners } => {
|
||||
let vidx = swapper.current().vertices.len() as u32;
|
||||
let vidx = draw_call.vertices.len() as u32;
|
||||
if let Some(corner) = rounded_corners.filter(|x| x.radius.max_f32() > 0.0) {
|
||||
//this code is stupid as fuck
|
||||
|
||||
//Random vert in the center for no reason
|
||||
//lol
|
||||
swapper.current_mut().vertices.push(UiVertex {
|
||||
draw_call.vertices.push(UiVertex {
|
||||
position: *position + *size * vec2(0.5, 0.5),
|
||||
color: (color.bottom_left + color.bottom_right + color.top_left + color.top_right) / 4.,
|
||||
uv: vec2(0., 0.),
|
||||
|
@ -197,32 +130,32 @@ impl UiDrawPlan {
|
|||
let x = angle.sin();
|
||||
let y = angle.cos();
|
||||
//Top-right corner
|
||||
swapper.current_mut().vertices.push(UiVertex {
|
||||
draw_call.vertices.push(UiVertex {
|
||||
position: *position + vec2(x, 1. - y) * corner.radius.top_right + vec2(size.x - corner.radius.top_right, 0.),
|
||||
color: color.top_right,
|
||||
uv: vec2(0.0, 0.0),
|
||||
});
|
||||
//Bottom-right corner
|
||||
swapper.current_mut().vertices.push(UiVertex {
|
||||
draw_call.vertices.push(UiVertex {
|
||||
position: *position + vec2(x - 1., y) * corner.radius.bottom_right + vec2(size.x, size.y - corner.radius.bottom_right),
|
||||
color: color.bottom_right,
|
||||
uv: vec2(0.0, 0.0),
|
||||
});
|
||||
//Bottom-left corner
|
||||
swapper.current_mut().vertices.push(UiVertex {
|
||||
draw_call.vertices.push(UiVertex {
|
||||
position: *position + vec2(1. - x, y) * corner.radius.bottom_left + vec2(0., size.y - corner.radius.bottom_left),
|
||||
color: color.bottom_left,
|
||||
uv: vec2(0.0, 0.0),
|
||||
});
|
||||
//Top-left corner
|
||||
swapper.current_mut().vertices.push(UiVertex {
|
||||
draw_call.vertices.push(UiVertex {
|
||||
position: *position + vec2(1. - x, 1. - y) * corner.radius.top_left,
|
||||
color: color.top_left,
|
||||
uv: vec2(0.0, 0.0),
|
||||
});
|
||||
// mental illness:
|
||||
if i > 0 {
|
||||
swapper.current_mut().indices.extend([
|
||||
draw_call.indices.extend([
|
||||
//Top-right corner
|
||||
vidx,
|
||||
vidx + 1 + (i - 1) * 4,
|
||||
|
@ -244,7 +177,7 @@ impl UiDrawPlan {
|
|||
}
|
||||
//Fill in the rest
|
||||
//mental illness 2:
|
||||
swapper.current_mut().indices.extend([
|
||||
draw_call.indices.extend([
|
||||
//Top
|
||||
vidx,
|
||||
vidx + 4,
|
||||
|
@ -263,8 +196,8 @@ impl UiDrawPlan {
|
|||
vidx + 2,
|
||||
]);
|
||||
} else {
|
||||
swapper.current_mut().indices.extend([vidx, vidx + 1, vidx + 2, vidx, vidx + 2, vidx + 3]);
|
||||
swapper.current_mut().vertices.extend([
|
||||
draw_call.indices.extend([vidx, vidx + 1, vidx + 2, vidx, vidx + 2, vidx + 3]);
|
||||
draw_call.vertices.extend([
|
||||
UiVertex {
|
||||
position: *position,
|
||||
color: color.top_left,
|
||||
|
@ -313,15 +246,15 @@ impl UiDrawPlan {
|
|||
tr.font_texture().size.x as f32,
|
||||
tr.font_texture().size.y as f32
|
||||
);
|
||||
let vidx = swapper.current().vertices.len() as u32;
|
||||
let vidx = draw_call.vertices.len() as u32;
|
||||
let glyph = tr.glyph(*font, layout_glyph.parent, layout_glyph.key.px as u8);
|
||||
//rpos_x += glyph.metrics.advance_width;//glyph.metrics.advance_width;
|
||||
swapper.current_mut().indices.extend([vidx, vidx + 1, vidx + 2, vidx, vidx + 2, vidx + 3]);
|
||||
draw_call.indices.extend([vidx, vidx + 1, vidx + 2, vidx, vidx + 2, vidx + 3]);
|
||||
let p0x = glyph.position.x as f32 / font_texture_size.0;
|
||||
let p1x = (glyph.position.x + glyph.size.x as i32) as f32 / font_texture_size.0;
|
||||
let p0y = glyph.position.y as f32 / font_texture_size.1;
|
||||
let p1y = (glyph.position.y + glyph.size.y as i32) as f32 / font_texture_size.1;
|
||||
swapper.current_mut().vertices.extend([
|
||||
draw_call.vertices.extend([
|
||||
UiVertex {
|
||||
position: *position + vec2(layout_glyph.x, layout_glyph.y),
|
||||
color: *color,
|
||||
|
@ -347,27 +280,24 @@ impl UiDrawPlan {
|
|||
feature = "pixel_perfect_text",
|
||||
not(feature = "pixel_perfect")
|
||||
))] {
|
||||
for vtx in &mut swapper.current_mut().vertices[(vidx as usize)..] {
|
||||
for vtx in &mut draw_call.vertices[(vidx as usize)..] {
|
||||
vtx.position = vtx.position.round()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "pixel_perfect")]
|
||||
swapper.current_mut().vertices.iter_mut().for_each(|v| {
|
||||
v.position = v.position.round()
|
||||
});
|
||||
prev_command = Some(command);
|
||||
}
|
||||
Self {
|
||||
calls: swapper.finish()
|
||||
}
|
||||
#[cfg(feature = "pixel_perfect")]
|
||||
draw_call.vertices.iter_mut().for_each(|v| {
|
||||
v.position = v.position.round()
|
||||
});
|
||||
draw_call
|
||||
}
|
||||
}
|
||||
|
||||
impl IfModified<UiDrawPlan> for (bool, &UiDrawPlan) {
|
||||
fn if_modified(&self) -> Option<&UiDrawPlan> {
|
||||
impl IfModified<UiDrawCall> for (bool, &UiDrawCall) {
|
||||
fn if_modified(&self) -> Option<&UiDrawCall> {
|
||||
match self.0 {
|
||||
true => Some(self.1),
|
||||
false => None,
|
||||
|
|
106
hui/src/draw/atlas.rs
Normal file
106
hui/src/draw/atlas.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use glam::UVec2;
|
||||
use hashbrown::HashMap;
|
||||
use nohash_hasher::BuildNoHashHasher;
|
||||
use rect_packer::DensePacker;
|
||||
|
||||
const CHANNEL_COUNT: u32 = 4;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct TextureHandle {
|
||||
//TODO automatic cleanup when handle is dropped
|
||||
//man: Weak<RefCell<TextureAtlasManager>>,
|
||||
pub(crate) index: u32
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct TextureAllocation {
|
||||
/// Index of the texture allocation
|
||||
pub index: u32,
|
||||
|
||||
/// Position in the texture atlas
|
||||
pub position: UVec2,
|
||||
|
||||
/// Requested texture size
|
||||
pub size: UVec2,
|
||||
|
||||
/// True if the texture was rotated by 90 degrees
|
||||
pub rotated: bool,
|
||||
}
|
||||
|
||||
pub(crate) struct TextureAtlasManager {
|
||||
packer: DensePacker,
|
||||
count: u32,
|
||||
size: UVec2,
|
||||
data: Vec<u8>,
|
||||
allocations: HashMap<u32, TextureAllocation, BuildNoHashHasher<u32>>,
|
||||
}
|
||||
|
||||
impl TextureAtlasManager {
|
||||
pub fn new(size: UVec2) -> Self {
|
||||
Self {
|
||||
packer: DensePacker::new(size.x as i32, size.y as i32),
|
||||
count: 0,
|
||||
size: UVec2::new(0, 0),
|
||||
data: Vec::new(),
|
||||
allocations: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, new_size: UVec2) {
|
||||
if new_size.x > self.size.x && new_size.y > self.size.y{
|
||||
self.packer.resize(new_size.x as i32, new_size.y as i32);
|
||||
//Resize the data array in-place
|
||||
self.data.resize((new_size.x * new_size.y * CHANNEL_COUNT) as usize, 0);
|
||||
for y in (1..self.size.y).rev() {
|
||||
for x in (0..self.size.x).rev() {
|
||||
let idx = (y * self.size.x + x) as usize;
|
||||
let new_idx = (y * new_size.x + x) as usize;
|
||||
self.data[new_idx] = self.data[idx];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//If scaling down, just recreate the atlas from scratch (since we need to re-pack everything anyway)
|
||||
todo!("Atlas downscaling is not implemented yet");
|
||||
}
|
||||
self.size = new_size;
|
||||
}
|
||||
|
||||
/// Allocate a new texture region in the atlas
|
||||
pub fn allocate(&mut self, size: UVec2) -> Option<TextureHandle> {
|
||||
let result = self.packer.pack(size.x as i32, size.y as i32, true)?;
|
||||
let index = self.count;
|
||||
self.count += 1;
|
||||
let allocation = TextureAllocation {
|
||||
index,
|
||||
position: UVec2::new(result.x as u32, result.y as u32),
|
||||
size,
|
||||
//If the size does not match the requested size, the texture was rotated
|
||||
rotated: result.width != size.x as i32,
|
||||
};
|
||||
self.allocations.insert_unique_unchecked(index, allocation);
|
||||
Some(TextureHandle { index })
|
||||
}
|
||||
|
||||
/// Allocate a new texture region in the atlas and copy the data into it
|
||||
pub fn add(&mut self, width: u32, data: &[u8]) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn modify(&mut self, handle: TextureHandle) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, handle: TextureHandle) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn get(&self, handle: TextureHandle) -> Option<&TextureAllocation> {
|
||||
self.allocations.get(&handle.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TextureAtlasManager {
|
||||
fn default() -> Self {
|
||||
Self::new(UVec2::new(512, 512))
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ use crate:: {
|
|||
element::{MeasureContext, ProcessContext, UiElement},
|
||||
event::UiEvent,
|
||||
state::StateRepo,
|
||||
draw::{UiDrawCommandList, UiDrawPlan},
|
||||
draw::{UiDrawCommandList, UiDrawCall},
|
||||
text::{TextRenderer, FontTextureInfo, FontHandle},
|
||||
};
|
||||
|
||||
|
@ -17,8 +17,8 @@ pub struct UiInstance {
|
|||
//event_queue: VecDeque<UiEvent>,
|
||||
prev_draw_commands: UiDrawCommandList,
|
||||
draw_commands: UiDrawCommandList,
|
||||
draw_plan: UiDrawPlan,
|
||||
draw_plan_modified: bool,
|
||||
draw_call: UiDrawCall,
|
||||
draw_call_modified: bool,
|
||||
text_renderer: TextRenderer,
|
||||
events: VecDeque<UiEvent>,
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ impl UiInstance {
|
|||
// root_elements: Vec::new(),
|
||||
prev_draw_commands: UiDrawCommandList::default(),
|
||||
draw_commands: UiDrawCommandList::default(),
|
||||
draw_plan: UiDrawPlan::default(),
|
||||
draw_plan_modified: false,
|
||||
draw_call: UiDrawCall::default(),
|
||||
draw_call_modified: false,
|
||||
// ftm: FontTextureManager::default(),
|
||||
text_renderer: TextRenderer::new(),
|
||||
events: VecDeque::new(),
|
||||
|
@ -78,7 +78,7 @@ impl UiInstance {
|
|||
/// 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;
|
||||
self.draw_call_modified = false;
|
||||
self.draw_commands.commands.clear();
|
||||
self.text_renderer.reset_frame();
|
||||
}
|
||||
|
@ -90,18 +90,18 @@ impl UiInstance {
|
|||
if self.draw_commands.commands == self.prev_draw_commands.commands {
|
||||
return
|
||||
}
|
||||
self.draw_plan = UiDrawPlan::build(&self.draw_commands, &mut self.text_renderer);
|
||||
self.draw_plan_modified = true;
|
||||
self.draw_call = UiDrawCall::build(&self.draw_commands, &mut self.text_renderer);
|
||||
self.draw_call_modified = true;
|
||||
}
|
||||
|
||||
/// Get the draw plan (a list of draw calls) for the current frame
|
||||
/// Get the draw call 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)
|
||||
pub fn draw_call(&self) -> (bool, &UiDrawCall) {
|
||||
(self.draw_call_modified, &self.draw_call)
|
||||
}
|
||||
|
||||
/// Get the font texture for the current frame
|
||||
|
|
Loading…
Reference in a new issue