ranim_render/primitives/
viewport.rs1use glam::{Mat4, Vec2};
2use ranim_core::prelude::CameraFrame;
3
4use crate::utils::{WgpuBuffer, WgpuContext};
5
6pub const DEPTH_ORDER_SPAN: f32 = 1e-4;
14
15#[repr(C, align(16))]
17#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
18pub struct ViewportUniform {
19 proj_mat: Mat4,
20 view_mat: Mat4,
21 half_frame_size: Vec2,
22 bias_epsilon: f32,
24 _padding: u32,
25}
26impl ViewportUniform {
27 pub fn from_camera_frame(
28 camera_frame: &CameraFrame,
29 width: u32,
30 height: u32,
31 bias_epsilon: f32,
32 ) -> Self {
33 let ratio = width as f64 / height as f64;
34 Self {
35 proj_mat: camera_frame.projection_matrix(ratio).as_mat4(),
36 view_mat: camera_frame.view_matrix().as_mat4(),
37 half_frame_size: Vec2::new(
38 (camera_frame.frame_height * ratio) as f32 / 2.0,
39 camera_frame.frame_height as f32 / 2.0,
40 ),
41 bias_epsilon,
42 _padding: 0,
43 }
44 }
45 pub(crate) fn as_bind_group_layout_entry(binding: u32) -> wgpu::BindGroupLayoutEntry {
46 wgpu::BindGroupLayoutEntry {
47 binding,
48 visibility: wgpu::ShaderStages::COMPUTE | wgpu::ShaderStages::VERTEX_FRAGMENT,
49 ty: wgpu::BindingType::Buffer {
50 ty: wgpu::BufferBindingType::Uniform,
51 has_dynamic_offset: false,
52 min_binding_size: None,
53 },
54 count: None,
55 }
56 }
57}
58
59pub struct ViewportBindGroup {
60 pub bind_group: wgpu::BindGroup,
61}
62
63impl AsRef<wgpu::BindGroup> for ViewportBindGroup {
64 fn as_ref(&self) -> &wgpu::BindGroup {
65 &self.bind_group
66 }
67}
68
69impl ViewportBindGroup {
70 pub(crate) fn bind_group_layout(ctx: &WgpuContext) -> wgpu::BindGroupLayout {
71 ctx.device
72 .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
73 label: Some("Viewport Bind Group Layout"),
74 entries: &[ViewportUniform::as_bind_group_layout_entry(0)],
75 })
76 }
77
78 pub(crate) fn new(ctx: &WgpuContext, uniforms_buffer: &WgpuBuffer<ViewportUniform>) -> Self {
79 let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
80 label: Some("Camera Uniforms"),
81 layout: &Self::bind_group_layout(ctx),
82 entries: &[wgpu::BindGroupEntry {
83 binding: 0,
84 resource: wgpu::BindingResource::Buffer(
85 uniforms_buffer.as_ref().as_entire_buffer_binding(),
86 ),
87 }],
88 });
89 Self { bind_group }
90 }
91}
92
93#[derive(bevy_ecs::prelude::Resource)]
94pub struct ViewportGpuPacket {
95 pub(crate) uniforms_buffer: WgpuBuffer<ViewportUniform>,
96 pub(crate) uniforms_bind_group: ViewportBindGroup,
97}
98
99impl ViewportGpuPacket {
100 pub(crate) fn new(ctx: &WgpuContext, data: &ViewportUniform) -> Self {
101 let uniforms_buffer = WgpuBuffer::new_init(
102 ctx,
103 Some("Uniforms Buffer"),
104 wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
105 *data,
106 );
107 let uniforms_bind_group = ViewportBindGroup::new(ctx, &uniforms_buffer);
108
109 Self {
110 uniforms_buffer,
111 uniforms_bind_group,
112 }
113 }
114
115 pub(crate) fn update(&mut self, ctx: &WgpuContext, data: &ViewportUniform) {
116 self.uniforms_buffer.set(ctx, *data);
117 }
118}