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
46struct RenderQueue;
51
52#[non_exhaustive]
55#[must_use]
56pub struct Instance {
57 queue: Rc<RenderQueue>,
58}
59
60impl fmt::Debug for Instance {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.debug_struct("Instance").finish_non_exhaustive()
63 }
64}
65
66impl Instance {
67 pub fn new() -> Result<Self> {
73 Self::with_cmdbuf_size(citro3d_sys::C3D_DEFAULT_CMDBUF_SIZE.try_into().unwrap())
74 }
75
76 #[doc(alias = "C3D_Init")]
82 pub fn with_cmdbuf_size(size: usize) -> Result<Self> {
83 if unsafe { citro3d_sys::C3D_Init(size) } {
84 Ok(Self {
85 queue: Rc::new(RenderQueue),
86 })
87 } else {
88 Err(Error::FailedToInitialize)
89 }
90 }
91
92 #[doc(alias = "C3D_RenderTargetCreate")]
99 #[doc(alias = "C3D_RenderTargetSetOutput")]
100 pub fn render_target<'screen>(
101 &self,
102 width: usize,
103 height: usize,
104 screen: RefMut<'screen, dyn Screen>,
105 depth_format: Option<render::DepthFormat>,
106 ) -> Result<render::ScreenTarget<'screen>> {
107 render::ScreenTarget::new(width, height, screen, depth_format, Rc::clone(&self.queue))
108 }
109
110 pub fn render_target_texture(
117 &self,
118 texture: texture::Texture,
119 face: texture::Face,
120 depth_format: Option<render::DepthFormat>,
121 ) -> Result<render::TextureTarget> {
122 render::TextureTarget::new(texture, face, depth_format, Rc::clone(&self.queue))
123 }
124
125 #[doc(alias = "C3D_FrameBegin")]
129 #[doc(alias = "C3D_FrameEnd")]
130 pub fn render_frame_with<'istance: 'frame, 'frame>(
131 &'istance mut self,
132 f: impl FnOnce(Frame<'frame>) -> Frame<'frame>,
133 ) {
134 let frame = f(Frame::new(self));
135
136 drop(frame);
138 }
139}
140
141impl Drop for Instance {
144 #[doc(alias = "C3D_Fini")]
145 fn drop(&mut self) {}
146}
147
148impl Drop for RenderQueue {
149 fn drop(&mut self) {
150 unsafe {
151 citro3d_sys::C3D_Fini();
152 }
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use ctru::services::gfx::Gfx;
159
160 use super::*;
161
162 #[test]
163 fn select_render_target() {
164 let gfx = Gfx::new().unwrap();
165 let screen = gfx.top_screen.borrow_mut();
166
167 let mut instance = Instance::new().unwrap();
168 let target = instance.render_target(10, 10, screen, None).unwrap();
169
170 instance.render_frame_with(|mut frame| {
171 frame.select_render_target(&target).unwrap();
172
173 frame
174 });
175
176 drop(instance);
179 drop(target);
180 }
181}