dear_imgui_bevy/
texture.rs1use bevy_ecs::resource::Resource;
9use dear_imgui_rs as imgui;
10use std::sync::{Arc, Mutex};
11
12#[derive(Resource, Debug, Clone, Default)]
14pub struct ImguiTextureFeedbackQueue {
15 feedback: Arc<Mutex<Vec<imgui::render::snapshot::TextureFeedback>>>,
16 last_applied: usize,
17}
18
19impl ImguiTextureFeedbackQueue {
20 pub fn push(&self, feedback: imgui::render::snapshot::TextureFeedback) {
22 self.feedback
23 .lock()
24 .expect("ImguiTextureFeedbackQueue mutex poisoned")
25 .push(feedback);
26 }
27
28 #[must_use]
30 pub fn len(&self) -> usize {
31 self.feedback
32 .lock()
33 .expect("ImguiTextureFeedbackQueue mutex poisoned")
34 .len()
35 }
36
37 #[must_use]
39 pub fn is_empty(&self) -> bool {
40 self.len() == 0
41 }
42
43 #[must_use]
45 pub fn last_applied(&self) -> usize {
46 self.last_applied
47 }
48
49 pub(crate) fn drain(&self) -> Vec<imgui::render::snapshot::TextureFeedback> {
50 std::mem::take(
51 &mut *self
52 .feedback
53 .lock()
54 .expect("ImguiTextureFeedbackQueue mutex poisoned"),
55 )
56 }
57
58 pub(crate) fn set_last_applied(&mut self, applied: usize) {
59 self.last_applied = applied;
60 }
61}
62
63#[cfg(feature = "render")]
64mod render {
65 use super::*;
66 use bevy_asset::{AssetId, Handle};
67 use bevy_image::Image;
68 use std::collections::HashMap;
69
70 const BEVY_IMAGE_TEXTURE_NAMESPACE: u64 = 0x8000_0000_0000_0000;
71
72 #[derive(Resource, Debug)]
74 pub struct ImguiBevyTextures {
75 by_asset: HashMap<AssetId<Image>, imgui::TextureId>,
76 by_texture: HashMap<imgui::TextureId, AssetId<Image>>,
77 next_texture_id: u64,
78 }
79
80 impl Default for ImguiBevyTextures {
81 fn default() -> Self {
82 Self {
83 by_asset: HashMap::new(),
84 by_texture: HashMap::new(),
85 next_texture_id: BEVY_IMAGE_TEXTURE_NAMESPACE,
86 }
87 }
88 }
89
90 impl ImguiBevyTextures {
91 pub fn register(&mut self, image: &Handle<Image>) -> imgui::TextureId {
95 let asset_id = image.id();
96 if let Some(texture_id) = self.by_asset.get(&asset_id) {
97 return *texture_id;
98 }
99
100 let texture_id = self.allocate_texture_id();
101 self.by_asset.insert(asset_id, texture_id);
102 self.by_texture.insert(texture_id, asset_id);
103 texture_id
104 }
105
106 pub fn unregister(&mut self, image: &Handle<Image>) -> Option<imgui::TextureId> {
108 let texture_id = self.by_asset.remove(&image.id())?;
109 self.by_texture.remove(&texture_id);
110 Some(texture_id)
111 }
112
113 #[must_use]
115 pub fn asset_id(&self, texture_id: imgui::TextureId) -> Option<AssetId<Image>> {
116 self.by_texture.get(&texture_id).copied()
117 }
118
119 pub fn iter(&self) -> impl Iterator<Item = (imgui::TextureId, AssetId<Image>)> + '_ {
121 self.by_texture
122 .iter()
123 .map(|(texture_id, asset_id)| (*texture_id, *asset_id))
124 }
125
126 #[must_use]
128 pub fn len(&self) -> usize {
129 self.by_texture.len()
130 }
131
132 #[must_use]
134 pub fn is_empty(&self) -> bool {
135 self.by_texture.is_empty()
136 }
137
138 fn allocate_texture_id(&mut self) -> imgui::TextureId {
139 if self.next_texture_id < BEVY_IMAGE_TEXTURE_NAMESPACE {
140 self.next_texture_id = BEVY_IMAGE_TEXTURE_NAMESPACE;
141 }
142
143 loop {
144 let texture_id = imgui::TextureId::new(self.next_texture_id);
145 self.next_texture_id = self.next_texture_id.wrapping_add(1);
146 if self.next_texture_id < BEVY_IMAGE_TEXTURE_NAMESPACE {
147 self.next_texture_id = BEVY_IMAGE_TEXTURE_NAMESPACE;
148 }
149 if !texture_id.is_null() && !self.by_texture.contains_key(&texture_id) {
150 return texture_id;
151 }
152 }
153 }
154 }
155}
156
157#[cfg(feature = "render")]
158pub use render::ImguiBevyTextures;