summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/Cargo.toml7
-rw-r--r--engine/src/ui/dear_imgui.rs337
-rw-r--r--engine/src/ui/view/world.rs47
3 files changed, 197 insertions, 194 deletions
diff --git a/engine/Cargo.toml b/engine/Cargo.toml
index 0c1f5c3..31fa6eb 100644
--- a/engine/Cargo.toml
+++ b/engine/Cargo.toml
@@ -42,10 +42,9 @@ git = "https://github.com/HampusMat/slang-rs"
branch = "prebuilt-and-artifacts"
[dependencies.dear-imgui-rs]
-git = "https://github.com/Latias94/dear-imgui-rs"
-# This commit has a fix for linking with libstdc++ on non-msvc Windows targets. When a
-# release with this fix is available, it should be used instead
-rev = "cd2425b699e746852757e9290257bbf09129cfa7"
+# This alpha release has a fix for linking with libstdc++ on non-msvc Windows targets.
+# When a stable release with this fix is available, it should be used instead
+version = "=0.16.0-alpha.1"
features = ["freetype"]
[build-dependencies]
diff --git a/engine/src/ui/dear_imgui.rs b/engine/src/ui/dear_imgui.rs
index 60067e1..212f24c 100644
--- a/engine/src/ui/dear_imgui.rs
+++ b/engine/src/ui/dear_imgui.rs
@@ -1,3 +1,5 @@
+use std::collections::HashMap;
+use std::hint::cold_path;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::LazyLock;
@@ -9,6 +11,7 @@ use dear_imgui_rs::{
};
use ecs::component::local::Local;
use ecs::component::Component;
+use ecs::error::Context as _;
use ecs::event::component::{Changed, EventMatchExt};
use ecs::pair::Pair;
use ecs::query::term::With;
@@ -99,6 +102,8 @@ pub struct Context
pub enabled: bool,
ctx: inner_context_wrapper::InnerContextWrapper,
texture_lookup: MapVec<TextureLookupId, RenderingObjectId>,
+ texture_id_lookup:
+ HashMap<dear_imgui_rs::SnapshotTextureId, dear_imgui_rs::TextureId>,
}
impl Context
@@ -112,9 +117,12 @@ impl Context
self.ctx.get_frame()
}
- pub fn register_texture(&mut self, texture_data: &mut bindings::OwnedTextureData)
+ pub fn register_texture(
+ &mut self,
+ texture_data: bindings::OwnedTextureData,
+ ) -> bindings::ManagedTextureId
{
- self.ctx.register_texture(texture_data);
+ self.ctx.register_texture(texture_data)
}
}
@@ -152,6 +160,7 @@ impl ecs::extension::Extension for Extension
enabled: self.start_enabled,
ctx: inner_context_wrapper::InnerContextWrapper::new(),
texture_lookup: MapVec::with_capacity(8),
+ texture_id_lookup: HashMap::with_capacity(8),
};
if let Err(err) = context
@@ -166,19 +175,21 @@ impl ecs::extension::Extension for Extension
"Freetype font rasterizer support is not enabled"
);
- context.ctx.font_atlas_mut().add_font_from_memory_ttf(
- include_bytes!("../../res/FiraMono-Regular.ttf"),
- 14.0,
- Some(
- &dear_imgui_rs::FontConfig::default()
- .name("FiraMono-Regular.ttf")
- .font_loader_flags(
- dear_imgui_rs::FontLoaderFlags::BITMAP
- | dear_imgui_rs::FontLoaderFlags::FORCE_AUTOHINT,
- ),
- ),
- None,
- );
+ unsafe {
+ context.ctx.font_atlas().add_font_from_memory_ttf(
+ include_bytes!("../../res/FiraMono-Regular.ttf"),
+ 14.0,
+ Some(
+ &dear_imgui_rs::FontConfig::default()
+ .name("FiraMono-Regular.ttf")
+ .font_loader_flags(
+ dear_imgui_rs::FontLoaderFlags::BITMAP
+ | dear_imgui_rs::FontLoaderFlags::FORCE_AUTOHINT,
+ ),
+ ),
+ None,
+ );
+ }
collector.add_sole(context).ok();
@@ -504,32 +515,42 @@ fn add_drawing_render_pass(
.unwrap(),
);
- let Context { enabled: _, ctx, texture_lookup } = context;
-
- let draw_data = ctx.render();
-
- let mut textures = draw_data.textures_mut();
-
- while let Some(mut texture_data) = textures.next() {
- match texture_data.status() {
- dear_imgui_rs::TextureStatus::WantCreate => {
- let Some(texture_pixels) = texture_data.pixels() else {
- texture_data.set_status(dear_imgui_rs::TextureStatus::OK);
- continue;
- };
-
- if !matches!(texture_data.format(), dear_imgui_rs::TextureFormat::RGBA32)
- {
+ let Context {
+ enabled: _,
+ ctx,
+ texture_lookup,
+ texture_id_lookup,
+ } = context;
+
+ let mut render_frame = ctx.render();
+
+ let mut tex_feedbacks = Vec::with_capacity(render_frame.texture_requests().len());
+
+ for texture_request in render_frame.texture_requests() {
+ match texture_request.operation() {
+ dear_imgui_rs::TextureOp::Create {
+ format,
+ width,
+ height,
+ row_pitch: _,
+ pixels,
+ } => {
+ if !matches!(format, dear_imgui_rs::TextureFormat::RGBA32) {
unimplemented!();
}
+ let texture_lookup_id = TextureLookupId::new();
+
+ tracing::trace!(
+ snapshot_tex_id = ?texture_request.texture(),
+ tex_lookup_id = ?texture_lookup_id,
+ "Performing texture operation: Create"
+ );
+
let image =
match Image::from_pixels(ImagePixelBuffer::<Rgba<u8>, _>::new(
- texture_pixels,
- Dimens {
- width: texture_data.width(),
- height: texture_data.height(),
- },
+ pixels.as_slice(),
+ Dimens { width: *width, height: *height },
)) {
Ok(image) => image,
Err(ImagePixelBufferLenIncorrectForSize) => {
@@ -548,90 +569,127 @@ fn add_drawing_render_pass(
})),
));
- let texture_lookup_id = TextureLookupId::new();
-
- texture_data.set_tex_id(texture_lookup_id.into());
-
texture_lookup.insert(texture_lookup_id, texture_object_id);
- texture_data.set_status(dear_imgui_rs::TextureStatus::OK);
- }
- dear_imgui_rs::TextureStatus::WantUpdates => {
- if texture_data.tex_id().is_null() {
- tracing::error!(concat!(
- "Update was requested for texture with a null ID. Did you forget ",
- "to set the texture status to TextureStatus::WantCreate?"));
+ texture_id_lookup
+ .insert(texture_request.texture(), texture_lookup_id.into());
- continue;
- }
+ let texture_feedback =
+ match texture_request.uploaded(texture_lookup_id.into()) {
+ Ok(texture_feedback) => texture_feedback,
+ Err(
+ dear_imgui_rs::TextureFeedbackError::UploadForDestroy
+ | dear_imgui_rs::TextureFeedbackError::DestroyForUpload,
+ ) => unreachable!(),
+ };
- if texture_data.pixels().is_none() {
- texture_data.set_status(dear_imgui_rs::TextureStatus::OK);
- continue;
+ tex_feedbacks.push(texture_feedback);
+ }
+ dear_imgui_rs::TextureOp::Update { format, width: _, height: _, rects } => {
+ if !matches!(format, dear_imgui_rs::TextureFormat::RGBA32) {
+ unimplemented!();
}
- let mut rects: Vec<dear_imgui_rs::texture::TextureRect> =
- texture_data.updates().collect();
+ let texture_lookup_id =
+ TextureLookupId::from(texture_id_lookup[&texture_request.texture()]);
- if rects.is_empty() {
- let rect = texture_data.update_rect();
- if rect.w > 0 && rect.h > 0 {
- rects.push(rect);
- }
- }
+ tracing::trace!(
+ snapshot_tex_id = ?texture_request.texture(),
+ tex_lookup_id = ?texture_lookup_id,
+ "Performing texture operation: Update"
+ );
- if rects.is_empty() {
- texture_data.set_status(dear_imgui_rs::TextureStatus::OK);
- continue;
- }
-
- let Some(texture_object_id) =
- texture_lookup.get(&TextureLookupId::from(texture_data.tex_id()))
+ let Some(texture_object_id) = texture_lookup.get(&texture_lookup_id)
else {
tracing::error!(
- "Unknown texture {}. Skipping update",
- texture_data.tex_id().id()
+ snapshot_tex_id = ?texture_request.texture(),
+ tex_lookup_id = ?texture_lookup_id,
+ "Unknown texture. Skipping update",
);
- texture_data.set_status(dear_imgui_rs::TextureStatus::OK);
continue;
};
- render_pass.commands.extend(rects.iter().filter_map(|rect| {
- let Some(rect_image) = get_texture_rect_image(&texture_data, rect)
+ render_pass.commands.reserve(rects.len());
+
+ for rect in rects {
+ let Ok(rect_image) =
+ Image::from_pixels(ImagePixelBuffer::<Rgba<u8>, _>::new(
+ rect.data.as_slice(),
+ Dimens::<u32> {
+ width: rect.rect.w.into(),
+ height: rect.rect.h.into(),
+ },
+ ))
else {
- return None;
+ cold_path();
+ tracing::error!("Texture update rect size is incorrect");
+ continue;
};
- Some(RenderingCommand::UpdateTexture {
- obj_id: texture_object_id.clone(),
+ render_pass.commands.push(RenderingCommand::UpdateTexture {
+ obj_id: *texture_object_id,
image: rect_image,
- offset: Vec2 { x: rect.x as u32, y: rect.y as u32 },
- })
- }));
+ offset: Vec2 {
+ x: rect.rect.x as u32,
+ y: rect.rect.y as u32,
+ },
+ });
+ }
+
+ let texture_feedback =
+ match texture_request.uploaded(texture_lookup_id.into()) {
+ Ok(texture_feedback) => texture_feedback,
+ Err(
+ dear_imgui_rs::TextureFeedbackError::UploadForDestroy
+ | dear_imgui_rs::TextureFeedbackError::DestroyForUpload,
+ ) => unreachable!(),
+ };
- texture_data.set_status(dear_imgui_rs::TextureStatus::OK);
+ tex_feedbacks.push(texture_feedback);
}
- dear_imgui_rs::TextureStatus::WantDestroy => {
- let Some(texture_object_id) =
- texture_lookup.remove(TextureLookupId::from(texture_data.tex_id()))
+ dear_imgui_rs::TextureOp::Destroy => {
+ let texture_lookup_id =
+ TextureLookupId::from(texture_id_lookup[&texture_request.texture()]);
+
+ tracing::trace!(
+ snapshot_tex_id = ?texture_request.texture(),
+ tex_lookup_id = ?texture_lookup_id,
+ "Performing texture operation: Destroy"
+ );
+
+ let Some(texture_object_id) = texture_lookup.remove(texture_lookup_id)
else {
tracing::error!(
- "Unknown texture {}. Skipping destroyal",
- texture_data.tex_id().id()
+ texture = ?texture_lookup_id,
+ "Unknown texture. Skipping destroyal",
);
- texture_data.set_status(dear_imgui_rs::TextureStatus::OK);
continue;
};
render_pass
.commands
.push(RenderingCommand::RemoveTexture(texture_object_id));
+
+ let texture_feedback = match texture_request.destroyed() {
+ Ok(texture_feedback) => texture_feedback,
+ Err(
+ dear_imgui_rs::TextureFeedbackError::UploadForDestroy
+ | dear_imgui_rs::TextureFeedbackError::DestroyForUpload,
+ ) => unreachable!(),
+ };
+
+ tex_feedbacks.push(texture_feedback);
}
- _ => {}
}
}
- let [display_width, display_height] = draw_data.display_size;
+ render_frame
+ .reconcile_texture_feedback(tex_feedbacks)
+ .with_context(|| "Failed to reconcile texture feedback")?;
+
+ let draw_data = render_frame.draw_data();
+
+ let [display_width, display_height] = draw_data.display_size();
// let [scale_width, scale_height] = draw_data.framebuffer_scale;
@@ -691,18 +749,14 @@ fn add_drawing_render_pass(
for command in draw_list.commands() {
match command {
- ImguiDrawCmd::Elements { count, cmd_params, raw_cmd } => {
+ ImguiDrawCmd::Elements { count, cmd_params } => {
let Some(scissor_box) =
calc_draw_cmd_scissor_box(draw_data, &cmd_params)
else {
continue;
};
- let tex_id = dear_imgui_rs::TextureId::new(u64::from(unsafe {
- let mut cmd_copy = *raw_cmd;
-
- dear_imgui_rs::sys::ImDrawCmd_GetTexID(&mut cmd_copy)
- }));
+ let tex_id = cmd_params.texture_id;
let Some(texture_object_id) =
texture_lookup.get(&TextureLookupId::from(tex_id))
@@ -745,59 +799,6 @@ fn add_drawing_render_pass(
Ok(())
}
-fn get_texture_rect_image(
- texture_data: &dear_imgui_rs::TextureData,
- rect: &dear_imgui_rs::TextureRect,
-) -> Option<Image>
-{
- let texture_pixels = texture_data.pixels()?;
-
- let tex_width = texture_data.width();
- let tex_height = texture_data.height();
-
- if tex_width == 0 || tex_height == 0 {
- return None;
- }
-
- let rect_pos = Vec2::<u32> { x: rect.x.into(), y: rect.y.into() };
-
- let rect_size = Dimens::<u32> {
- width: rect.w.into(),
- height: rect.h.into(),
- };
-
- if rect_size.width == 0
- || rect_size.height == 0
- || rect_pos.x >= tex_width
- || rect_pos.y >= tex_height
- {
- return None;
- }
-
- let rect_size = Dimens {
- width: rect_size.width.min(tex_width.saturating_sub(rect_pos.x)),
- height: rect_size.height.min(tex_height.saturating_sub(rect_pos.y)),
- };
-
- match texture_data.format() {
- dear_imgui_rs::TextureFormat::RGBA32 => {
- let Ok(texture_image) =
- Image::from_pixels(ImagePixelBuffer::<Rgba<u8>, _>::new(
- texture_pixels,
- Dimens { width: tex_width, height: tex_height },
- ))
- else {
- return None;
- };
-
- Some(texture_image.sub_view(rect_pos, rect_size).to_image())
- }
- dear_imgui_rs::TextureFormat::Alpha8 => {
- unimplemented!();
- }
- }
-}
-
fn calc_draw_cmd_scissor_box(
draw_data: &dear_imgui_rs::DrawData,
cmd_params: &dear_imgui_rs::DrawCmdParams,
@@ -805,23 +806,23 @@ fn calc_draw_cmd_scissor_box(
{
let clip_rect = cmd_params.clip_rect;
- let clip_min_x =
- (clip_rect[0] - draw_data.display_pos[0]) * draw_data.framebuffer_scale[0];
+ let display_size = draw_data.display_size();
+ let display_pos = draw_data.display_pos();
+ let framebuffer_scale = draw_data.framebuffer_scale();
- let clip_min_y =
- (clip_rect[1] - draw_data.display_pos[1]) * draw_data.framebuffer_scale[1];
+ let clip_min_x = (clip_rect[0] - display_pos[0]) * framebuffer_scale[0];
- let clip_max_x =
- (clip_rect[2] - draw_data.display_pos[0]) * draw_data.framebuffer_scale[0];
+ let clip_min_y = (clip_rect[1] - display_pos[1]) * framebuffer_scale[1];
- let clip_max_y =
- (clip_rect[3] - draw_data.display_pos[1]) * draw_data.framebuffer_scale[1];
+ let clip_max_x = (clip_rect[2] - display_pos[0]) * framebuffer_scale[0];
+
+ let clip_max_y = (clip_rect[3] - display_pos[1]) * framebuffer_scale[1];
if clip_max_x <= clip_min_x || clip_max_y <= clip_min_y {
return None;
}
- let fb_height = draw_data.display_size[1] * draw_data.framebuffer_scale[1];
+ let fb_height = display_size[1] * framebuffer_scale[1];
Some(ScissorBox {
size: Some(Dimens {
@@ -971,6 +972,7 @@ mod inner_context_wrapper
{
ctx: Pin<Box<dear_imgui_rs::Context>>,
frame: *mut dear_imgui_rs::Ui,
+ _renderer_consumer: dear_imgui_rs::RendererConsumer,
}
impl InnerContextWrapper
@@ -985,7 +987,13 @@ mod inner_context_wrapper
ctx.io_mut()
.set_backend_flags(dear_imgui_rs::BackendFlags::RENDERER_HAS_TEXTURES);
- Self { ctx, frame: null_mut() }
+ let _renderer_consumer = ctx.create_renderer_consumer().unwrap();
+
+ Self {
+ ctx,
+ frame: null_mut(),
+ _renderer_consumer,
+ }
}
pub fn set_settings_ini_file_path(
@@ -998,10 +1006,10 @@ mod inner_context_wrapper
pub fn register_texture(
&mut self,
- texture_data: &mut dear_imgui_rs::texture::OwnedTextureData,
- )
+ texture_data: dear_imgui_rs::texture::OwnedTextureData,
+ ) -> dear_imgui_rs::ManagedTextureId
{
- self.ctx.register_user_texture(texture_data);
+ self.ctx.register_texture(texture_data)
}
pub fn get_io_mut(&mut self) -> &mut dear_imgui_rs::Io
@@ -1009,12 +1017,17 @@ mod inner_context_wrapper
self.ctx.io_mut()
}
- pub fn font_atlas_mut(&mut self) -> dear_imgui_rs::FontAtlas
+ pub fn font_atlas(&self) -> &dear_imgui_rs::FontAtlas
{
- self.ctx.font_atlas_mut()
+ self.ctx.font_atlas()
}
- pub fn render(&mut self) -> &mut dear_imgui_rs::DrawData
+ // pub fn create_renderer_consumer(&mut self) -> dear_imgui_rs::RendererConsumer
+ // {
+ // self.ctx.create_renderer_consumer().unwrap()
+ // }
+
+ pub fn render(&mut self) -> dear_imgui_rs::RenderedFrame<'_>
{
self.ctx.render()
}
diff --git a/engine/src/ui/view/world.rs b/engine/src/ui/view/world.rs
index 2bf3ca5..3ea0611 100644
--- a/engine/src/ui/view/world.rs
+++ b/engine/src/ui/view/world.rs
@@ -38,8 +38,8 @@ pub struct State
{
spawning_entity: Option<Uid>,
add_component_popup_state: Option<AddComponentPopupState>,
- despawn_icon_tex: Option<dear_imgui_bindings::OwnedTextureData>,
- warning_icon_tex: Option<dear_imgui_bindings::OwnedTextureData>,
+ despawn_icon_tex_id: Option<dear_imgui_bindings::ManagedTextureId>,
+ warning_icon_tex_id: Option<dear_imgui_bindings::ManagedTextureId>,
}
impl Default for State
@@ -49,8 +49,8 @@ impl Default for State
Self {
spawning_entity: None,
add_component_popup_state: None,
- despawn_icon_tex: None,
- warning_icon_tex: None,
+ despawn_icon_tex_id: None,
+ warning_icon_tex_id: None,
}
}
}
@@ -80,11 +80,11 @@ pub fn show(
let State {
spawning_entity,
add_component_popup_state,
- despawn_icon_tex,
- warning_icon_tex,
+ despawn_icon_tex_id,
+ warning_icon_tex_id,
} = &mut *state;
- let despawn_icon_tex = despawn_icon_tex.get_or_insert_with(|| {
+ let despawn_icon_tex_id = *despawn_icon_tex_id.get_or_insert_with(|| {
create_texture(
dear_imgui_context,
Image::from_reader(
@@ -95,7 +95,7 @@ pub fn show(
)
});
- let warning_icon_tex = warning_icon_tex.get_or_insert_with(|| {
+ let warning_icon_tex_id = *warning_icon_tex_id.get_or_insert_with(|| {
create_texture(
dear_imgui_context,
Image::from_reader(
@@ -129,8 +129,8 @@ pub fn show(
create_entity_widgets(
frame,
add_component_popup_state,
- despawn_icon_tex,
- warning_icon_tex,
+ despawn_icon_tex_id,
+ warning_icon_tex_id,
&ent_handle,
world,
&mut actions,
@@ -150,7 +150,7 @@ pub fn show(
fn create_texture(
dear_imgui_context: &mut DearImguiContext,
image: Image,
-) -> dear_imgui_bindings::OwnedTextureData
+) -> dear_imgui_bindings::ManagedTextureId
{
let image = image.into_rgba8();
@@ -164,11 +164,7 @@ fn create_texture(
texture_data.set_data(image.as_bytes());
- texture_data.set_status(dear_imgui_bindings::TextureStatus::WantCreate);
-
- dear_imgui_context.register_texture(&mut texture_data);
-
- texture_data
+ dear_imgui_context.register_texture(texture_data)
}
fn create_spawn_button_widgets(
@@ -206,8 +202,8 @@ fn create_spawn_button_widgets(
fn create_entity_widgets(
frame: &dear_imgui_bindings::Ui,
add_component_popup_state: &mut Option<AddComponentPopupState>,
- despawn_icon_tex: &mut dear_imgui_bindings::OwnedTextureData,
- warning_icon_tex: &mut dear_imgui_bindings::OwnedTextureData,
+ despawn_icon_tex: dear_imgui_bindings::ManagedTextureId,
+ warning_icon_tex: dear_imgui_bindings::ManagedTextureId,
ent_handle: &EntityHandle,
world: &World,
actions: &mut Actions,
@@ -370,7 +366,7 @@ fn create_component_widgets(
fn create_pair_component_widgets(
frame: &dear_imgui_bindings::Ui,
- warning_icon_tex: &mut dear_imgui_bindings::OwnedTextureData,
+ warning_icon_tex_id: dear_imgui_bindings::ManagedTextureId,
ent_handle: &EntityHandle,
pair_id: Uid,
world: &World,
@@ -446,7 +442,7 @@ fn create_pair_component_widgets(
let Some(pair_data_ty) = pair_data_comp_info.type_reflection else {
frame.same_line();
- frame.image(&mut **warning_icon_tex, [16.0, 16.0]);
+ frame.image(warning_icon_tex_id, [16.0, 16.0]);
if frame.is_item_hovered() {
frame.tooltip_text(format!(
@@ -559,7 +555,7 @@ fn create_add_component_button_widget(
fn create_despawn_button_widget(
frame: &dear_imgui_bindings::Ui,
- despawn_icon_tex: &mut dear_imgui_bindings::OwnedTextureData,
+ despawn_icon_tex: dear_imgui_bindings::ManagedTextureId,
ent_handle: &EntityHandle,
actions: &mut Actions,
)
@@ -582,7 +578,7 @@ fn create_despawn_button_widget(
if frame
.image_button_config(
&format!("ent_{}_despawn_button", ent_handle.uid()),
- despawn_icon_tex.as_mut(),
+ despawn_icon_tex,
[14.0, 14.0],
)
.build()
@@ -777,12 +773,7 @@ fn show_add_component_popup(
add_component_popup_state.new_component.is_none(),
);
- let add_text_size = frame.current_font().calc_text_size(
- frame.clone_style().font_size_base(),
- frame.content_region_avail_width(),
- 0.0,
- "Add",
- );
+ let add_text_size = frame.calc_text_size("Add");
if frame.button_with_size(
"Add##add_component_popup_add_button",