Skip to main content

dear_imgui_rs/texture/
reference.rs

1use super::{TextureData, TextureId};
2use crate::sys;
3use std::marker::PhantomData;
4
5/// A convenient, typed wrapper around ImGui's ImTextureRef (v1.92+)
6///
7/// Can reference either a plain `TextureId` (legacy path) or a managed `TextureData`.
8/// Managed texture references carry the lifetime of the referenced texture data; legacy
9/// `TextureId` references can be converted into any texture-reference lifetime because they do not
10/// borrow Rust texture data.
11///
12/// Examples
13/// - With a plain GPU handle (legacy path):
14/// ```no_run
15/// # use dear_imgui_rs::{Ui, TextureId};
16/// # fn demo(ui: &Ui) {
17/// let tex_id = TextureId::new(12345);
18/// ui.image(tex_id, [64.0, 64.0]);
19/// # }
20/// ```
21/// - With a managed texture (ImGui 1.92 texture system):
22/// ```no_run
23/// # use dear_imgui_rs::{Ui, texture::{TextureData, TextureFormat}};
24/// # fn demo(ui: &Ui) {
25/// let mut tex = TextureData::new();
26/// tex.create(TextureFormat::RGBA32, 256, 256);
27/// // Fill pixels or schedule updates...
28/// ui.image(&mut *tex, [256.0, 256.0]);
29/// // The renderer backend will honor WantCreate/WantUpdates/WantDestroy
30/// // via DrawData::textures_mut() when rendering this frame.
31/// # }
32/// ```
33///
34/// Managed references cannot be stored beyond the texture data they point at:
35///
36/// ```compile_fail
37/// # use dear_imgui_rs::texture::{TextureData, TextureRef};
38/// let leaked: TextureRef<'static>;
39/// {
40///     let mut tex = TextureData::new();
41///     leaked = (&mut tex).into();
42/// }
43/// let _ = leaked.raw();
44/// ```
45///
46/// Raw `ImTextureRef` values can contain arbitrary managed texture pointers, so constructing this
47/// wrapper from raw data is unsafe:
48///
49/// ```compile_fail
50/// # use dear_imgui_rs::{sys, texture::TextureRef};
51/// let raw = sys::ImTextureRef {
52///     _TexData: std::ptr::null_mut(),
53///     _TexID: 0,
54/// };
55/// let _ = TextureRef::from_raw(raw);
56/// ```
57#[derive(Copy, Clone, Debug)]
58#[repr(transparent)]
59pub struct TextureRef<'tex> {
60    raw: sys::ImTextureRef,
61    _marker: PhantomData<&'tex mut TextureData>,
62}
63
64// Ensure the wrapper stays layout-compatible with the sys bindings.
65const _: [(); std::mem::size_of::<sys::ImTextureRef>()] =
66    [(); std::mem::size_of::<TextureRef<'static>>()];
67const _: [(); std::mem::align_of::<sys::ImTextureRef>()] =
68    [(); std::mem::align_of::<TextureRef<'static>>()];
69
70impl<'tex> TextureRef<'tex> {
71    /// Create a texture reference from a raw ImGui texture ref.
72    ///
73    /// # Safety
74    ///
75    /// If `raw._TexData` is non-null, the caller must guarantee that it points to a valid
76    /// `ImTextureData` for the entire `'tex` lifetime and that using the resulting reference does
77    /// not violate Rust aliasing rules.
78    #[inline]
79    pub unsafe fn from_raw(raw: sys::ImTextureRef) -> Self {
80        Self {
81            raw,
82            _marker: PhantomData,
83        }
84    }
85
86    /// Get the underlying ImGui texture ref (by value)
87    #[inline]
88    pub fn raw(self) -> sys::ImTextureRef {
89        self.raw
90    }
91}
92
93impl<'tex> From<TextureId> for TextureRef<'tex> {
94    #[inline]
95    fn from(id: TextureId) -> Self {
96        TextureRef {
97            raw: sys::ImTextureRef {
98                _TexData: std::ptr::null_mut(),
99                _TexID: id.id() as sys::ImTextureID,
100            },
101            _marker: PhantomData,
102        }
103    }
104}
105
106impl<'tex> From<&TextureData> for TextureRef<'tex> {
107    #[inline]
108    fn from(td: &TextureData) -> Self {
109        // Safety: A shared `&TextureData` must not be used to give Dear ImGui a mutable
110        // `ImTextureData*` because ImGui/backends may mutate fields such as `Status`/`TexID`
111        // during the frame, which would violate Rust aliasing rules.
112        //
113        // We therefore treat `&TextureData` as a legacy reference: only forward the current
114        // `TexID` value (if any). For managed textures, pass `&mut TextureData` instead.
115        TextureRef {
116            raw: sys::ImTextureRef {
117                _TexData: std::ptr::null_mut(),
118                _TexID: td.tex_id().id() as sys::ImTextureID,
119            },
120            _marker: PhantomData,
121        }
122    }
123}
124
125impl<'tex> From<&'tex mut TextureData> for TextureRef<'tex> {
126    #[inline]
127    fn from(td: &'tex mut TextureData) -> Self {
128        TextureRef {
129            raw: sys::ImTextureRef {
130                _TexData: td.as_raw_mut(),
131                _TexID: 0,
132            },
133            _marker: PhantomData,
134        }
135    }
136}
137
138/// Create an ImTextureRef from a texture ID.
139///
140/// This is the safe way to create an ImTextureRef for use with Dear ImGui.
141/// Use this instead of directly constructing the sys::ImTextureRef structure.
142pub fn create_texture_ref(texture_id: TextureId) -> sys::ImTextureRef {
143    sys::ImTextureRef {
144        _TexData: std::ptr::null_mut(),
145        _TexID: texture_id.id() as sys::ImTextureID,
146    }
147}