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