rlbot/
render.rs

1//! Rendering is RLBot's ability to draw directly inside the game window.
2
3use crate::{flat, rlbot::RLBot};
4use flatbuffers::{FlatBufferBuilder, WIPOffset};
5use std::error::Error;
6
7/// A render group in the process of being built.
8///
9/// The drawing methods in this class simply collect a list of items to be
10/// drawn later. Nothing will actually be drawn to screen until
11/// [`render`](RenderGroup::render) is called.
12///
13/// # Examples
14///
15/// ## Basic rendering
16///
17/// ```no_run
18/// # use rlbot::flat::ColorArgs;
19/// # use std::error::Error;
20/// #
21/// # fn main() -> Result<(), Box<Error>> {
22/// let rlbot = rlbot::init()?;
23/// let mut group = rlbot.begin_render_group(1234);
24/// let green = group.color_rgb(0, 255, 0);
25/// group.draw_string_2d((10.0, 10.0), (2, 2), "I am text!", green);
26/// group.render()?;
27/// # Ok(())
28/// # }
29/// ```
30///
31/// ## Clearing the screen
32///
33/// ```no_run
34/// # use std::error::Error;
35/// #
36/// # fn main() -> Result<(), Box<Error>> {
37/// let rlbot = rlbot::init()?;
38/// let group = rlbot.begin_render_group(1234);
39/// group.render()?;
40/// # Ok(())
41/// # }
42/// ```
43pub struct RenderGroup<'a> {
44    rlbot: &'a RLBot,
45    id: i32,
46    builder: FlatBufferBuilder<'a>,
47    messages: Vec<WIPOffset<flat::RenderMessage<'a>>>,
48}
49
50impl<'a> RenderGroup<'a> {
51    pub(crate) fn new(rlbot: &'a RLBot, id: i32) -> Self {
52        Self {
53            rlbot,
54            id,
55            builder: FlatBufferBuilder::new_with_capacity(1024),
56            messages: Vec::new(),
57        }
58    }
59}
60
61/// A color that can be used to draw in a [`RenderGroup`].
62#[derive(Copy, Clone)]
63pub struct Color<'a>(WIPOffset<flat::Color<'a>>);
64
65impl<'a> RenderGroup<'a> {
66    /// Send the collected drawings to RLBot to be rendered to screen.
67    pub fn render(mut self) -> Result<(), Box<dyn Error>> {
68        let messages = self.builder.create_vector(&self.messages);
69
70        let render_group = {
71            let mut rg = flat::RenderGroupBuilder::new(&mut self.builder);
72            rg.add_renderMessages(messages);
73            rg.add_id(self.id);
74            rg.finish()
75        };
76
77        self.builder.finish(render_group, None);
78        let data = self.builder.finished_data();
79        self.rlbot.interface().render_group(data)?;
80        Ok(())
81    }
82
83    /// Create a color with the given **a**lpha, **r**ed, **g**reen, and
84    /// **b**lue. An alpha of 255 is fully opaque, and 0 is fully transparent.
85    ///
86    /// A color can only be used with the `RenderGroup` that created it.
87    ///
88    /// # Example
89    ///
90    /// ```no_run
91    /// # use rlbot::RenderGroup;
92    /// # let mut group: RenderGroup = unsafe { ::std::mem::uninitialized() };
93    /// let transbluecent = group.color_argb(127, 0, 0, 255);
94    /// ```
95    pub fn color_argb(&mut self, a: u8, r: u8, g: u8, b: u8) -> Color<'a> {
96        let args = flat::ColorArgs { a, r, g, b };
97        Color(flat::Color::create(&mut self.builder, &args))
98    }
99
100    /// Create an opaque color with the given, **r**ed, **g**reen, and **b**lue.
101    ///
102    /// A color can only be used with the `RenderGroup` that created it.
103    ///
104    /// # Example
105    ///
106    /// ```no_run
107    /// # use rlbot::RenderGroup;
108    /// # let mut group: RenderGroup = unsafe { ::std::mem::uninitialized() };
109    /// let green = group.color_rgb(0, 255, 0);
110    /// ```
111    pub fn color_rgb(&mut self, r: u8, g: u8, b: u8) -> Color<'a> {
112        let args = flat::ColorArgs { a: 255, r, g, b };
113        Color(flat::Color::create(&mut self.builder, &args))
114    }
115
116    /// Draw a line using screen coordinates.
117    ///
118    /// # Example
119    ///
120    /// ```no_run
121    /// # use rlbot::RenderGroup;
122    /// # let mut group: RenderGroup = unsafe { ::std::mem::uninitialized() };
123    /// # let green = group.color_rgb(0, 255, 0);
124    /// group.draw_line_2d((10.0, 10.0), (100.0, 100.0), green);
125    /// ```
126    pub fn draw_line_2d(
127        &mut self,
128        (x1, y1): (f32, f32),
129        (x2, y2): (f32, f32),
130        Color(color): Color<'_>,
131    ) {
132        let start = flat::Vector3::new(x1, y1, 0.0);
133        let end = flat::Vector3::new(x2, y2, 0.0);
134
135        let mut rm = flat::RenderMessageBuilder::new(&mut self.builder);
136        rm.add_renderType(flat::RenderType::DrawLine2D);
137        rm.add_color(color);
138        rm.add_start(&start);
139        rm.add_end(&end);
140        self.messages.push(rm.finish());
141    }
142
143    /// Draw a line using world coordinates.
144    ///
145    /// # Example
146    ///
147    /// ```no_run
148    /// # use rlbot::RenderGroup;
149    /// # let mut group: RenderGroup = unsafe { ::std::mem::uninitialized() };
150    /// # let green = group.color_rgb(0, 255, 0);
151    /// group.draw_line_3d((10.0, 10.0, 10.0), (100.0, 100.0, 100.0), green);
152    /// ```
153    pub fn draw_line_3d(
154        &mut self,
155        (x1, y1, z1): (f32, f32, f32),
156        (x2, y2, z2): (f32, f32, f32),
157        Color(color): Color<'_>,
158    ) {
159        let start = flat::Vector3::new(x1, y1, z1);
160        let end = flat::Vector3::new(x2, y2, z2);
161
162        let mut rm = flat::RenderMessageBuilder::new(&mut self.builder);
163        rm.add_renderType(flat::RenderType::DrawLine3D);
164        rm.add_color(color);
165        rm.add_start(&start);
166        rm.add_end(&end);
167        self.messages.push(rm.finish());
168    }
169
170    /// Draw a line with one endpoint in screen coordinates and the other at a
171    /// point projected from world coordinates to screen coordinates.
172    ///
173    /// # Example
174    ///
175    /// ```no_run
176    /// # use rlbot::RenderGroup;
177    /// # let mut group: RenderGroup = unsafe { ::std::mem::uninitialized() };
178    /// # let green = group.color_rgb(0, 255, 0);
179    /// group.draw_line_2d_3d((10.0, 10.0), (100.0, 100.0, 100.0), green);
180    /// ```
181    pub fn draw_line_2d_3d(
182        &mut self,
183        (x1, y1): (f32, f32),
184        (x2, y2, z2): (f32, f32, f32),
185        Color(color): Color<'_>,
186    ) {
187        let start = flat::Vector3::new(x1, y1, 0.0);
188        let end = flat::Vector3::new(x2, y2, z2);
189
190        let mut rm = flat::RenderMessageBuilder::new(&mut self.builder);
191        rm.add_renderType(flat::RenderType::DrawLine2D_3D);
192        rm.add_color(color);
193        rm.add_start(&start);
194        rm.add_end(&end);
195        self.messages.push(rm.finish());
196    }
197
198    /// Draw text using screen coordinates.
199    ///
200    /// # Example
201    ///
202    /// ```no_run
203    /// # use rlbot::RenderGroup;
204    /// # let mut group: RenderGroup = unsafe { ::std::mem::uninitialized() };
205    /// # let green = group.color_rgb(0, 255, 0);
206    /// group.draw_string_2d((10.0, 10.0), (2, 2), "I am text!", green);
207    /// ```
208    pub fn draw_string_2d(
209        &mut self,
210        (x, y): (f32, f32),
211        (scale_x, scale_y): (i32, i32),
212        text: impl AsRef<str>,
213        Color(color): Color<'_>,
214    ) {
215        let start = flat::Vector3::new(x, y, 0.0);
216        let text = self.builder.create_string(text.as_ref());
217
218        let mut rm = flat::RenderMessageBuilder::new(&mut self.builder);
219        rm.add_renderType(flat::RenderType::DrawString2D);
220        rm.add_color(color);
221        rm.add_start(&start);
222        rm.add_scaleX(scale_x);
223        rm.add_scaleY(scale_y);
224        rm.add_text(text);
225        self.messages.push(rm.finish());
226    }
227
228    /// Draw text at a point projected from world coordinates to screen
229    /// coordinates.
230    ///
231    /// # Example
232    ///
233    /// ```no_run
234    /// # use rlbot::RenderGroup;
235    /// # let mut group: RenderGroup = unsafe { ::std::mem::uninitialized() };
236    /// # let green = group.color_rgb(0, 255, 0);
237    /// group.draw_string_3d((10.0, 10.0, 10.0), (2, 2), "I am text!", green);
238    /// ```
239    pub fn draw_string_3d(
240        &mut self,
241        (x, y, z): (f32, f32, f32),
242        (scale_x, scale_y): (i32, i32),
243        text: impl AsRef<str>,
244        Color(color): Color<'_>,
245    ) {
246        let start = flat::Vector3::new(x, y, z);
247        let text = self.builder.create_string(text.as_ref());
248
249        let mut rm = flat::RenderMessageBuilder::new(&mut self.builder);
250        rm.add_renderType(flat::RenderType::DrawString2D);
251        rm.add_color(color);
252        rm.add_start(&start);
253        rm.add_scaleX(scale_x);
254        rm.add_scaleY(scale_y);
255        rm.add_text(text);
256        self.messages.push(rm.finish());
257    }
258}