1mod clear_state;
6#[doc(inline)]
7pub use clear_state::*;
8
9mod color_target;
10#[doc(inline)]
11pub use color_target::*;
12
13mod depth_target;
14#[doc(inline)]
15pub use depth_target::*;
16
17mod multisample;
18#[doc(inline)]
19pub use multisample::*;
20
21mod color_target_multisample;
22#[doc(inline)]
23pub use color_target_multisample::*;
24
25mod depth_target_multisample;
26#[doc(inline)]
27pub use depth_target_multisample::*;
28
29use crate::core::*;
30
31use crate::context::Framebuffer;
32pub struct RenderTarget<'a> {
39 id: Option<Framebuffer>,
40 color: Option<ColorTarget<'a>>,
41 depth: Option<DepthTarget<'a>>,
42 pub(crate) context: Context,
43 width: u32,
44 height: u32,
45}
46
47impl<'a> RenderTarget<'a> {
48 pub fn screen(context: &Context, width: u32, height: u32) -> Self {
53 Self {
54 context: context.clone(),
55 id: None,
56 color: None,
57 depth: None,
58 width,
59 height,
60 }
61 }
62
63 pub fn new(color: ColorTarget<'a>, depth: DepthTarget<'a>) -> Self {
67 let width = color.width();
68 let height = color.height();
69 Self {
70 context: color.context.clone(),
71 id: Some(new_framebuffer(&color.context)),
72 color: Some(color),
73 depth: Some(depth),
74 width,
75 height,
76 }
77 }
78
79 pub fn width(&self) -> u32 {
81 self.width
82 }
83
84 pub fn height(&self) -> u32 {
86 self.height
87 }
88
89 pub fn clear(&self, clear_state: ClearState) -> &Self {
93 self.clear_partially(self.scissor_box(), clear_state)
94 }
95
96 pub fn clear_partially(&self, scissor_box: ScissorBox, clear_state: ClearState) -> &Self {
100 self.context.set_scissor(scissor_box);
101 self.bind(crate::context::DRAW_FRAMEBUFFER);
102 clear_state.apply(&self.context);
103 self
104 }
105
106 pub fn write<E: std::error::Error>(
110 &self,
111 render: impl FnOnce() -> Result<(), E>,
112 ) -> Result<&Self, E> {
113 self.write_partially(self.scissor_box(), render)
114 }
115
116 pub fn write_partially<E: std::error::Error>(
120 &self,
121 scissor_box: ScissorBox,
122 render: impl FnOnce() -> Result<(), E>,
123 ) -> Result<&Self, E> {
124 self.context.set_scissor(scissor_box);
125 self.bind(crate::context::DRAW_FRAMEBUFFER);
126 render()?;
127 if let Some(ref color) = self.color {
128 color.generate_mip_maps();
129 }
130 Ok(self)
131 }
132
133 pub fn read_color<T: TextureDataType>(&self) -> Vec<T> {
146 self.read_color_partially(self.scissor_box())
147 }
148
149 pub fn read_color_partially<T: TextureDataType>(&self, scissor_box: ScissorBox) -> Vec<T> {
162 if self.id.is_some() && self.color.is_none() {
163 panic!("Cannot read color from a render target without a color target");
164 }
165 let format = format_from_data_type::<T>();
166 let data_type = T::data_type();
167
168 #[cfg(target_arch = "wasm32")]
170 if format != crate::context::RGBA
171 || !(data_type == crate::context::UNSIGNED_BYTE || data_type == crate::context::FLOAT)
172 {
173 panic!("Only the texture data types `Vec4<T>` and `[T; 4]` where `T` is either `u8` or `f32` are supported when reading color from a render target on web.");
174 }
175
176 self.bind(crate::context::DRAW_FRAMEBUFFER);
177 self.bind(crate::context::READ_FRAMEBUFFER);
178 let data_size = std::mem::size_of::<T>();
179 let mut bytes =
180 vec![0u8; scissor_box.width as usize * scissor_box.height as usize * data_size];
181 unsafe {
182 self.context.read_pixels(
183 scissor_box.x,
184 scissor_box.y,
185 scissor_box.width as i32,
186 scissor_box.height as i32,
187 format,
188 data_type,
189 crate::context::PixelPackData::Slice(&mut bytes),
190 );
191 }
192 let mut pixels = from_byte_slice(&bytes).to_vec();
193 flip_y(
194 &mut pixels,
195 scissor_box.width as usize,
196 scissor_box.height as usize,
197 );
198 pixels
199 }
200
201 #[cfg(not(target_arch = "wasm32"))]
205 pub fn read_depth(&self) -> Vec<f32> {
206 self.read_depth_partially(self.scissor_box())
207 }
208
209 #[cfg(not(target_arch = "wasm32"))]
213 pub fn read_depth_partially(&self, scissor_box: ScissorBox) -> Vec<f32> {
214 if self.id.is_some() && self.depth.is_none() {
215 panic!("cannot read depth from a render target without a depth target");
216 }
217 self.bind(crate::context::DRAW_FRAMEBUFFER);
218 self.bind(crate::context::READ_FRAMEBUFFER);
219 let mut pixels = vec![0u8; scissor_box.width as usize * scissor_box.height as usize * 4];
220 unsafe {
221 self.context.read_pixels(
222 scissor_box.x,
223 scissor_box.y,
224 scissor_box.width as i32,
225 scissor_box.height as i32,
226 crate::context::DEPTH_COMPONENT,
227 crate::context::FLOAT,
228 crate::context::PixelPackData::Slice(&mut pixels),
229 );
230 }
231 from_byte_slice(&pixels).to_vec()
232 }
233
234 pub fn from_framebuffer(
239 context: &Context,
240 width: u32,
241 height: u32,
242 framebuffer: Framebuffer,
243 ) -> Self {
244 Self {
245 id: Some(framebuffer),
246 color: None,
247 depth: None,
248 context: context.clone(),
249 width,
250 height,
251 }
252 }
253
254 pub fn into_framebuffer(mut self) -> Option<Framebuffer> {
259 self.id.take()
260 }
261
262 pub(in crate::core) fn blit_to(&self, target: &RenderTarget) {
263 self.bind(crate::context::DRAW_FRAMEBUFFER);
264 target.bind(crate::context::DRAW_FRAMEBUFFER);
265 let target_is_screen = target.color.is_none() && target.depth.is_none();
266 let mask = if self.color.is_some() && (target.color.is_some() || target_is_screen) {
267 let mut mask = crate::context::COLOR_BUFFER_BIT;
268 if self.depth.is_some() && (target.depth.is_some() || target_is_screen) {
269 mask |= crate::context::DEPTH_BUFFER_BIT;
270 }
271 mask
272 } else if self.depth.is_some() && (target.depth.is_some() || target_is_screen) {
273 crate::context::DEPTH_BUFFER_BIT
274 } else {
275 unreachable!()
276 };
277 self.context
278 .set_scissor(ScissorBox::new_at_origo(target.width, target.height));
279 unsafe {
280 self.context
281 .bind_framebuffer(crate::context::READ_FRAMEBUFFER, self.id);
282
283 self.context.blit_framebuffer(
284 0,
285 0,
286 self.width as i32,
287 self.height as i32,
288 0,
289 0,
290 target.width as i32,
291 target.height as i32,
292 mask,
293 crate::context::NEAREST,
294 );
295 }
296 }
297
298 fn new_color(color: ColorTarget<'a>) -> Self {
299 let width = color.width();
300 let height = color.height();
301 Self {
302 context: color.context.clone(),
303 id: Some(new_framebuffer(&color.context)),
304 color: Some(color),
305 depth: None,
306 width,
307 height,
308 }
309 }
310
311 fn new_depth(depth: DepthTarget<'a>) -> Self {
312 let width = depth.width();
313 let height = depth.height();
314 Self {
315 context: depth.context.clone(),
316 id: Some(new_framebuffer(&depth.context)),
317 depth: Some(depth),
318 color: None,
319 width,
320 height,
321 }
322 }
323
324 fn bind(&self, target: u32) {
325 unsafe {
326 self.context.bind_framebuffer(target, self.id);
327 }
328 if let Some(ref color) = self.color {
329 color.bind(&self.context);
330 }
331 if let Some(ref depth) = self.depth {
332 depth.bind();
333 }
334 }
335}
336
337impl Drop for RenderTarget<'_> {
338 fn drop(&mut self) {
339 unsafe {
340 if let Some(id) = self.id {
341 self.context.delete_framebuffer(id);
342 }
343 }
344 }
345}
346
347fn size_with_mip(size: u32, mip: Option<u32>) -> u32 {
348 if let Some(mip) = mip {
349 size / 2u32.pow(mip)
350 } else {
351 size
352 }
353}
354
355fn new_framebuffer(context: &Context) -> crate::context::Framebuffer {
356 unsafe {
357 context
358 .create_framebuffer()
359 .expect("Failed creating frame buffer")
360 }
361}
362
363#[cfg(debug_assertions)]
364fn multisample_sanity_check(context: &Context, number_of_samples: u32) {
365 let max_samples: u32 = unsafe {
366 context
367 .get_parameter_i32(crate::context::MAX_SAMPLES)
368 .try_into()
369 .unwrap()
370 };
371 if number_of_samples > max_samples {
372 panic!("number_of_samples ({}) for multisample target is larger than supported number of samples: {}", number_of_samples, max_samples);
373 }
374 if (number_of_samples != 0) && number_of_samples & (number_of_samples - 1) != 0 {
375 panic!("number_of_samples ({}) for multisample target must be a power of 2 (and larger than 0).", number_of_samples);
376 }
377}
378
379macro_rules! impl_render_target_core_extensions_body {
380 () => {
381 pub fn scissor_box(&self) -> ScissorBox {
385 ScissorBox::new_at_origo(self.width(), self.height())
386 }
387
388 pub fn viewport(&self) -> Viewport {
392 Viewport::new_at_origo(self.width(), self.height())
393 }
394 };
395}
396
397macro_rules! impl_render_target_core_extensions {
398 ($name:ident < $a:ident : $ta:tt , $b:ident : $tb:tt >) => {
400 impl<$a: $ta, $b: $tb> $name<$a, $b> {
401 impl_render_target_core_extensions_body!();
402 }
403 };
404 ($name:ident < $a:ident : $ta:tt >) => {
406 impl<$a: $ta> $name<$a> {
407 impl_render_target_core_extensions_body!();
408 }
409 };
410 ($name:ident < $lt:lifetime >) => {
412 impl<$lt> $name<$lt> {
413 impl_render_target_core_extensions_body!();
414 }
415 };
416 ($name:ty) => {
418 impl $name {
419 impl_render_target_core_extensions_body!();
420 }
421 };
422}
423
424impl_render_target_core_extensions!(RenderTarget<'a>);
425impl_render_target_core_extensions!(ColorTarget<'a>);
426impl_render_target_core_extensions!(DepthTarget<'a>);
427impl_render_target_core_extensions!(
428 RenderTargetMultisample<C: TextureDataType, D: DepthTextureDataType>
429);
430impl_render_target_core_extensions!(ColorTargetMultisample<C: TextureDataType>);
431impl_render_target_core_extensions!(DepthTargetMultisample<D: DepthTextureDataType>);