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