Skip to main content

yog_gfx/
draw2d.rs

1//! 2D drawing helpers — thin wrappers over the `draw2d_*` ABI functions.
2//!
3//! These use Minecraft's own rendering infrastructure (text renderer, texture
4//! manager) and are therefore only valid during `on_hud_render`.
5
6use yog_abi::YogStr;
7
8use crate::GfxContext;
9
10/// 2D drawing helpers, valid only within `on_hud_render`.
11///
12/// Obtain via [`GfxContext::draw2d`].
13pub struct Draw2D<'ctx>(&'ctx GfxContext);
14
15impl<'ctx> Draw2D<'ctx> {
16    pub(crate) fn new(ctx: &'ctx GfxContext) -> Self {
17        Self(ctx)
18    }
19
20    /// Draw a text string at GUI position `(x, y)`.
21    /// `color` is `0xAARRGGBB`. `shadow` adds a drop-shadow.
22    pub fn text(&self, text: &str, x: f32, y: f32, color: u32, shadow: bool) {
23        let a = self.0.api();
24        unsafe { (a.draw2d_text)(YogStr::from_str(text), x, y, color, shadow) }
25    }
26
27    /// [`Self::text`] in the font `font` (`"minecraft:uniform"`, a
28    /// resource-pack font id, ...; empty or `"minecraft:default"` = the
29    /// default font).
30    pub fn text_font(&self, text: &str, font: &str, x: f32, y: f32, color: u32, shadow: bool) {
31        let a = self.0.api();
32        unsafe {
33            (a.draw2d_text_font)(
34                YogStr::from_str(text),
35                YogStr::from_str(font),
36                x,
37                y,
38                color,
39                shadow,
40            )
41        }
42    }
43
44    /// Width in GUI pixels of `text` in `font` (empty = default), measured by
45    /// the host's text renderer.
46    pub fn text_width(&self, text: &str, font: &str) -> f32 {
47        let a = self.0.api();
48        unsafe { (a.text_width)(YogStr::from_str(text), YogStr::from_str(font)) }
49    }
50
51    /// Fill a rectangle with a flat color (`0xAARRGGBB`).
52    pub fn rect(&self, x1: f32, y1: f32, x2: f32, y2: f32, color: u32) {
53        let a = self.0.api();
54        unsafe { (a.draw2d_rect)(x1, y1, x2, y2, color) }
55    }
56
57    /// Fill a rectangle with a vertical gradient (top → bottom, `0xAARRGGBB`).
58    pub fn gradient(&self, x1: f32, y1: f32, x2: f32, y2: f32, top: u32, bottom: u32) {
59        let a = self.0.api();
60        unsafe { (a.draw2d_gradient)(x1, y1, x2, y2, top, bottom) }
61    }
62
63    /// Blit a region from a Minecraft texture identified by namespace + path.
64    ///
65    /// - `id`: e.g. `"minecraft:textures/gui/icons.png"`
66    /// - `(x, y)`: screen position
67    /// - `(u0, v0)`: top-left UV in texels
68    /// - `(w, h)`: region size in pixels
69    /// - `(tw, th)`: full texture size in pixels
70    pub fn mc_texture(
71        &self,
72        id: &str,
73        x: f32,
74        y: f32,
75        u0: f32,
76        v0: f32,
77        w: f32,
78        h: f32,
79        tw: f32,
80        th: f32,
81    ) {
82        let a = self.0.api();
83        unsafe { (a.draw2d_mc_tex)(YogStr::from_str(id), x, y, u0, v0, w, h, tw, th) }
84    }
85
86    /// Render an item stack (3D block models included) via Minecraft's item
87    /// renderer — like inventory slots or Patchouli's item icons.
88    ///
89    /// - `id`: item registry id, e.g. `"minecraft:crafting_table"`
90    /// - `(x, y)`: screen position in GUI pixels
91    /// - `size`: on-screen size in GUI pixels (16 = inventory icon size)
92    pub fn item(&self, id: &str, x: f32, y: f32, size: f32) {
93        let a = self.0.api();
94        unsafe { (a.draw2d_item)(YogStr::from_str(id), x, y, size) }
95    }
96
97    /// Draw the image `source` — a Yog image source such as `"item:apple"`,
98    /// `"block:stone"`, `"sprite:button"` or `"mymod:gui/logo"` (see
99    /// [`crate::image`]) — scaled into `(x, y, w, h)`. The host resolves it
100    /// for its Minecraft version; prefer this over [`Self::mc_texture`].
101    pub fn image(&self, source: &str, x: f32, y: f32, w: f32, h: f32) {
102        self.image_region(source, x, y, w, h, [0.0; 4], 0xFFFF_FFFF);
103    }
104
105    /// [`Self::image`] drawing only `region` (`[u, v, w, h]` in the image's
106    /// own pixels; all zero = the whole image) multiplied by `tint`
107    /// (`0xAARRGGBB`, `0xFFFFFFFF` = none). Items and sprites are always
108    /// drawn whole, and items ignore the tint.
109    #[allow(clippy::too_many_arguments)]
110    pub fn image_region(
111        &self,
112        source: &str,
113        x: f32,
114        y: f32,
115        w: f32,
116        h: f32,
117        region: [f32; 4],
118        tint: u32,
119    ) {
120        let a = self.0.api();
121        let [u, v, uw, vh] = region;
122        unsafe { (a.draw2d_image)(YogStr::from_str(source), x, y, w, h, u, v, uw, vh, tint) }
123    }
124
125    /// Natural size in GUI pixels of the image `source` (`None` if the host
126    /// can't resolve it).
127    pub fn image_size(&self, source: &str) -> Option<(f32, f32)> {
128        image_size_with(self.0.image_size_fn(), source)
129    }
130}
131
132/// Calls an [`ImageSizeFn`](crate::ImageSizeFn).
133pub fn image_size_with(f: crate::ImageSizeFn, source: &str) -> Option<(f32, f32)> {
134    let (mut w, mut h) = (0.0f32, 0.0f32);
135    unsafe { f(YogStr::from_str(source), &mut w, &mut h) }.then_some((w, h))
136}