use crate::builtin::AovKind;
use crate::camera::{Camera2d, Camera3d};
use crate::color::Color;
use crate::post_processing::{PostProcessingEffect, Tonemap};
use crate::renderer::{RayTracer, Renderer3d};
use crate::scene::{SceneNode2d, SceneNode3d};
use crate::window::{CanvasSetup, Window};
use glamx::UVec2;
#[cfg(not(target_arch = "wasm32"))]
use image::{ImageBuffer, Luma, Rgb};
pub struct OffscreenSurface {
window: Window,
}
impl OffscreenSurface {
pub async fn new(width: u32, height: u32) -> OffscreenSurface {
OffscreenSurface {
window: Window::do_new_headless(width, height, None).await,
}
}
pub async fn with_setup(width: u32, height: u32, setup: CanvasSetup) -> OffscreenSurface {
OffscreenSurface {
window: Window::do_new_headless(width, height, Some(setup)).await,
}
}
pub async fn render_3d(&mut self, scene: &mut SceneNode3d, camera: &mut impl Camera3d) {
let _ = self.window.render_3d(scene, camera).await;
}
pub async fn render_2d(&mut self, scene: &mut SceneNode2d, camera: &mut impl Camera2d) {
let _ = self.window.render_2d(scene, camera).await;
}
#[allow(clippy::too_many_arguments)]
pub async fn render(
&mut self,
scene: Option<&mut SceneNode3d>,
scene_2d: Option<&mut SceneNode2d>,
camera: Option<&mut dyn Camera3d>,
camera_2d: Option<&mut dyn Camera2d>,
renderer: Option<&mut dyn Renderer3d>,
post_processing: Option<&mut dyn PostProcessingEffect>,
) {
let _ = self
.window
.render(
scene,
scene_2d,
camera,
camera_2d,
renderer,
post_processing,
)
.await;
}
#[allow(clippy::too_many_arguments)]
pub async fn render_chain(
&mut self,
scene: Option<&mut SceneNode3d>,
scene_2d: Option<&mut SceneNode2d>,
camera: Option<&mut dyn Camera3d>,
camera_2d: Option<&mut dyn Camera2d>,
renderer: Option<&mut dyn Renderer3d>,
post_processing: &mut [&mut dyn PostProcessingEffect],
) {
let _ = self
.window
.render_chain(
scene,
scene_2d,
camera,
camera_2d,
renderer,
post_processing,
)
.await;
}
pub async fn raytrace_3d(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
raytracer: &mut RayTracer,
) {
let _ = self.window.raytrace_3d(scene, camera, raytracer).await;
}
#[cfg(not(target_arch = "wasm32"))]
pub async fn render_image_raytraced(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
raytracer: &mut RayTracer,
samples: u32,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
for _ in 0..samples.max(1) {
self.raytrace_3d(scene, camera, raytracer).await;
}
self.snap_image()
}
#[cfg(not(target_arch = "wasm32"))]
pub async fn render_image_3d(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
self.render_3d(scene, camera).await;
self.snap_image()
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap(&self, out: &mut Vec<u8>) {
self.window.snap(out)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_rect(&self, out: &mut Vec<u8>, x: usize, y: usize, width: usize, height: usize) {
self.window.snap_rect(out, x, y, width, height)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_image(&self) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
self.window.snap_image()
}
pub fn output_view(&mut self) -> wgpu::TextureView {
self.window.offscreen_output_view()
}
pub fn render_aov_3d(
&mut self,
kind: AovKind,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
depth_range: f32,
) {
self.window.render_aov_3d(kind, scene, camera, depth_range)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_depth_raw(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
) -> Vec<f32> {
self.window.snap_depth_raw(scene, camera)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_depth(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
) -> ImageBuffer<Luma<u8>, Vec<u8>> {
self.window.snap_depth(scene, camera)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_normals(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
self.window.snap_normals(scene, camera)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_camera_normals(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
self.window.snap_camera_normals(scene, camera)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_segmentation(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
) -> Vec<u32> {
self.window.snap_segmentation(scene, camera)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn snap_segmentation_colored(
&mut self,
scene: &mut SceneNode3d,
camera: &mut impl Camera3d,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
self.window.snap_segmentation_colored(scene, camera)
}
pub fn window(&self) -> &Window {
&self.window
}
pub fn window_mut(&mut self) -> &mut Window {
&mut self.window
}
pub fn resize(&mut self, width: u32, height: u32) {
self.window.canvas_mut().resize(width, height);
}
pub fn size(&self) -> UVec2 {
self.window.size()
}
pub fn width(&self) -> u32 {
self.window.width()
}
pub fn height(&self) -> u32 {
self.window.height()
}
pub fn set_background_color(&mut self, color: Color) {
self.window.set_background_color(color);
}
pub fn set_ambient(&mut self, ambient: f32) {
self.window.set_ambient(ambient);
}
pub fn set_exposure(&mut self, exposure: f32) {
self.window.set_exposure(exposure);
}
pub fn set_shadow_resolution(&mut self, resolution: u32) {
self.window.set_shadow_resolution(resolution);
}
pub fn set_tonemap(&mut self, tonemap: Tonemap) {
self.window.set_tonemap(tonemap);
}
pub fn set_bloom_enabled(&mut self, enabled: bool) {
self.window.set_bloom_enabled(enabled);
}
pub fn set_bloom(&mut self, threshold: f32, intensity: f32) {
self.window.set_bloom(threshold, intensity);
}
#[cfg(feature = "egui")]
pub fn draw_ui<F>(&mut self, ui_fn: F)
where
F: FnOnce(&egui::Context),
{
self.window.draw_ui(ui_fn);
}
}