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