1#![feature(custom_test_frameworks)]
2#![test_runner(test_runner::run_gdb)]
3#![feature(allocator_api)]
4#![feature(doc_cfg)]
5#![doc(html_root_url = "https://rust3ds.github.io/citro3d-rs/crates")]
6#![doc(
7 html_favicon_url = "https://user-images.githubusercontent.com/11131775/225929072-2fa1741c-93ae-4b47-9bdf-af70f3d59910.png"
8)]
9#![doc(
10 html_logo_url = "https://user-images.githubusercontent.com/11131775/225929072-2fa1741c-93ae-4b47-9bdf-af70f3d59910.png"
11)]
12
13#![doc = document_features::document_features!()]
18
19pub mod attrib;
20pub mod buffer;
21pub mod color;
22pub mod error;
23pub mod fog;
24pub mod light;
25pub mod math;
26pub mod render;
27pub mod shader;
28pub mod texenv;
29pub mod texture;
30pub mod uniform;
31
32use std::cell::RefMut;
33use std::fmt;
34use std::rc::Rc;
35
36use ctru::services::gfx::Screen;
37pub use error::{Error, Result};
38
39use crate::render::Frame;
40
41pub mod macros {
42 pub use citro3d_macros::*;
44}
45
46mod private {
47 pub trait Sealed {}
48 impl Sealed for u8 {}
49 impl Sealed for u16 {}
50}
51
52struct RenderQueue;
57
58#[non_exhaustive]
61#[must_use]
62pub struct Instance {
63 queue: Rc<RenderQueue>,
64}
65
66impl fmt::Debug for Instance {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 f.debug_struct("Instance").finish_non_exhaustive()
69 }
70}
71
72impl Instance {
73 pub fn new() -> Result<Self> {
79 Self::with_cmdbuf_size(citro3d_sys::C3D_DEFAULT_CMDBUF_SIZE.try_into().unwrap())
80 }
81
82 #[doc(alias = "C3D_Init")]
88 pub fn with_cmdbuf_size(size: usize) -> Result<Self> {
89 if unsafe { citro3d_sys::C3D_Init(size) } {
90 Ok(Self {
91 queue: Rc::new(RenderQueue),
92 })
93 } else {
94 Err(Error::FailedToInitialize)
95 }
96 }
97
98 #[doc(alias = "C3D_RenderTargetCreate")]
105 #[doc(alias = "C3D_RenderTargetSetOutput")]
106 pub fn render_target<'screen>(
107 &self,
108 width: usize,
109 height: usize,
110 screen: RefMut<'screen, dyn Screen>,
111 depth_format: Option<render::DepthFormat>,
112 ) -> Result<render::ScreenTarget<'screen>> {
113 render::ScreenTarget::new(width, height, screen, depth_format, Rc::clone(&self.queue))
114 }
115
116 pub fn render_target_texture(
123 &self,
124 texture: texture::Texture,
125 face: texture::Face,
126 depth_format: Option<render::DepthFormat>,
127 ) -> Result<render::TextureTarget> {
128 render::TextureTarget::new(texture, face, depth_format, Rc::clone(&self.queue))
129 }
130
131 #[doc(alias = "C3D_FrameBegin")]
135 #[doc(alias = "C3D_FrameEnd")]
136 pub fn render_frame_with<'istance: 'frame, 'frame>(
137 &'istance mut self,
138 f: impl FnOnce(Frame<'frame>) -> Frame<'frame>,
139 ) {
140 let frame = f(Frame::new(self));
141
142 drop(frame);
144 }
145}
146
147impl Drop for Instance {
150 #[doc(alias = "C3D_Fini")]
151 fn drop(&mut self) {}
152}
153
154impl Drop for RenderQueue {
155 fn drop(&mut self) {
156 unsafe {
157 citro3d_sys::C3D_Fini();
158 }
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use ctru::services::gfx::Gfx;
165
166 use super::*;
167
168 #[test]
169 fn select_render_target() {
170 let gfx = Gfx::new().unwrap();
171 let screen = gfx.top_screen.borrow_mut();
172
173 let mut instance = Instance::new().unwrap();
174 let target = instance.render_target(10, 10, screen, None).unwrap();
175
176 instance.render_frame_with(|mut frame| {
177 frame.select_render_target(&target).unwrap();
178
179 frame
180 });
181
182 drop(instance);
185 drop(target);
186 }
187}