#![cfg_attr(not(debug_assertions), deny(warnings))]
#![deny(clippy::all, rust_2018_idioms)]
#![warn(
missing_docs,
missing_debug_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
use bytemuck::{Pod, Zeroable};
use derive_more::*;
use std::sync::Arc;
use truck_base::cgmath64::*;
pub use wgpu;
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use wgpu::*;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant as TimeInstant;
#[cfg(target_arch = "wasm32")]
use web_time::Instant as TimeInstant;
pub const LIGHT_MAX: usize = 255;
#[repr(C)]
#[derive(Clone, Copy, Debug, Zeroable, Pod)]
struct CameraInfo {
camera_matrix: [[f32; 4]; 4],
camera_projection: [[f32; 4]; 4],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Zeroable, Pod)]
struct LightInfo {
light_position: [f32; 4],
light_color: [f32; 4],
light_type: [u32; 4],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Zeroable, Pod)]
struct SceneInfo {
background_color: [f32; 4],
resolution: [u32; 2],
time: f32,
num_of_lights: u32,
}
#[derive(Debug)]
pub struct BufferHandler {
buffer: Buffer,
size: u64,
stride: u64,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct PreBindGroupLayoutEntry {
pub visibility: ShaderStages,
pub ty: BindingType,
pub count: Option<std::num::NonZeroU32>,
}
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct RenderObject {
vertex_buffer: Arc<BufferHandler>,
index_buffer: Option<Arc<BufferHandler>>,
pipeline: Arc<RenderPipeline>,
bind_group_layout: Arc<BindGroupLayout>,
bind_group: Arc<BindGroup>,
visible: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProjectionType {
Perspective,
Parallel,
}
#[derive(Debug, Clone, Copy)]
pub struct Camera {
pub matrix: Matrix4,
projection: Matrix4,
projection_type: ProjectionType,
}
#[derive(Clone, Copy, Debug)]
pub struct Ray {
origin: Point3,
direction: Vector3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LightType {
Point,
Uniform,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Light {
pub position: Point3,
pub color: Vector3,
pub light_type: LightType,
}
#[derive(Debug, Clone)]
pub struct DeviceHandler {
adapter: Arc<Adapter>,
device: Arc<Device>,
queue: Arc<Queue>,
}
#[derive(Debug)]
struct WindowHandler {
window: Arc<winit::window::Window>,
surface: Arc<Surface<'static>>,
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
pub struct RenderID(usize);
#[derive(Debug, Clone)]
pub struct StudioConfig {
pub camera: Camera,
pub lights: Vec<Light>,
pub background: Color,
}
#[derive(Clone, Debug, Copy)]
pub struct BackendBufferConfig {
pub depth_test: bool,
pub sample_count: u32,
}
#[derive(Clone, Debug, Copy)]
pub struct RenderTextureConfig {
pub canvas_size: (u32, u32),
pub format: TextureFormat,
}
#[derive(Debug, Clone, Default)]
pub struct SceneDescriptor {
pub studio: StudioConfig,
pub backend_buffer: BackendBufferConfig,
pub render_texture: RenderTextureConfig,
}
#[derive(Debug, Clone, Default)]
pub struct WindowSceneDescriptor {
pub studio: StudioConfig,
pub backend_buffer: BackendBufferConfig,
}
#[derive(Debug)]
pub struct Scene {
device_handler: DeviceHandler,
objects: SliceHashMap<RenderID, RenderObject>,
bind_group_layout: BindGroupLayout,
foward_depth: Option<Texture>,
sampling_buffer: Option<Texture>,
scene_desc: SceneDescriptor,
clock: TimeInstant,
}
#[derive(Debug, Deref, DerefMut)]
pub struct WindowScene {
#[deref]
#[deref_mut]
scene: Scene,
window_handler: WindowHandler,
}
pub trait Rendered {
fn render_id(&self) -> RenderID;
fn vertex_buffer(
&self,
device_handler: &DeviceHandler,
) -> (Arc<BufferHandler>, Option<Arc<BufferHandler>>);
fn bind_group_layout(&self, device_handler: &DeviceHandler) -> Arc<BindGroupLayout>;
fn bind_group(
&self,
device_handler: &DeviceHandler,
layout: &BindGroupLayout,
) -> Arc<BindGroup>;
fn pipeline(
&self,
device_handler: &DeviceHandler,
layout: &PipelineLayout,
scene_descriptor: &SceneDescriptor,
) -> Arc<RenderPipeline>;
#[doc(hidden)]
fn render_object(&self, scene: &Scene) -> RenderObject {
let (vertex_buffer, index_buffer) = self.vertex_buffer(scene.device_handler());
let bind_group_layout = self.bind_group_layout(scene.device_handler());
let bind_group = self.bind_group(scene.device_handler(), &bind_group_layout);
let pipeline_layout = scene
.device()
.create_pipeline_layout(&PipelineLayoutDescriptor {
bind_group_layouts: &[&scene.bind_group_layout, &bind_group_layout],
push_constant_ranges: &[],
label: None,
});
let pipeline = self.pipeline(scene.device_handler(), &pipeline_layout, &scene.scene_desc);
RenderObject {
vertex_buffer,
index_buffer,
bind_group_layout,
bind_group,
pipeline,
visible: true,
}
}
}
mod buffer_handler;
mod camera;
mod light;
#[doc(hidden)]
pub mod rendered_macros;
mod scene;
mod slice_hashmap;
use slice_hashmap::SliceHashMap;
#[doc(hidden)]
pub mod bind_group_util {
use crate::*;
#[doc(hidden)]
pub fn create_bind_group<'a, T: IntoIterator<Item = BindingResource<'a>>>(
device: &Device,
layout: &BindGroupLayout,
resources: T,
) -> BindGroup {
let entries: &Vec<BindGroupEntry<'_>> = &resources
.into_iter()
.enumerate()
.map(move |(i, resource)| BindGroupEntry {
binding: i as u32,
resource,
})
.collect();
device.create_bind_group(&BindGroupDescriptor {
layout,
entries,
label: None,
})
}
#[doc(hidden)]
pub fn create_bind_group_layout<'a, T: IntoIterator<Item = &'a PreBindGroupLayoutEntry>>(
device: &Device,
entries: T,
) -> BindGroupLayout {
let vec: Vec<_> = entries
.into_iter()
.enumerate()
.map(|(i, e)| BindGroupLayoutEntry {
binding: i as u32,
visibility: e.visibility,
ty: e.ty,
count: e.count,
})
.collect();
device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: None,
entries: &vec,
})
}
}