daily update
This commit is contained in:
165
src/render.rs
165
src/render.rs
@@ -40,6 +40,43 @@ pub struct HandGatewayMode {
|
||||
pub range: Range<u32>,
|
||||
}
|
||||
|
||||
const HAND_TIP_MATRICES: [HandTipMatrix; 5] = [
|
||||
HandTipMatrix {
|
||||
center_px: [260.0, 490.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: -0.45,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [360.0, 255.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: -0.05,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [485.0, 225.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: 0.0,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [595.0, 260.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: 0.12,
|
||||
},
|
||||
HandTipMatrix {
|
||||
center_px: [705.0, 385.0],
|
||||
size_px: [70.0, 120.0],
|
||||
angle_rad: 0.28,
|
||||
},
|
||||
];
|
||||
|
||||
// Each entry pins one miniature matrix to a fingertip in hand.png.
|
||||
// Coordinates are authored in source-image pixels so they are easy to tune by eye.
|
||||
// size_px keeps the same 7:12 aspect as the Finger-mode 7 columns x 12 rows matrix.
|
||||
struct HandTipMatrix {
|
||||
center_px: [f32; 2],
|
||||
size_px: [f32; 2],
|
||||
angle_rad: f32,
|
||||
}
|
||||
|
||||
impl egui_wgpu::CallbackTrait for WgpuBackgroundCallback {
|
||||
fn prepare(
|
||||
&self,
|
||||
@@ -78,12 +115,15 @@ pub struct BackgroundRenderResources {
|
||||
hand_image_pipeline: wgpu::RenderPipeline,
|
||||
glyph_pipeline: wgpu::RenderPipeline,
|
||||
dot_pipeline: wgpu::RenderPipeline,
|
||||
hand_dot_pipeline: wgpu::RenderPipeline,
|
||||
hand_image_bind_group: wgpu::BindGroup,
|
||||
hand_image_texture: texture::Texture,
|
||||
|
||||
glyph_vertex_buffer: wgpu::Buffer,
|
||||
glyph_instance_buffer: wgpu::Buffer,
|
||||
glyph_instances: Vec<GlyphInstance>,
|
||||
hand_dot_instance_buffer: wgpu::Buffer,
|
||||
hand_dot_instances: Vec<GlyphInstance>,
|
||||
render_options: RenderOptions,
|
||||
}
|
||||
|
||||
@@ -405,6 +445,8 @@ impl BackgroundRenderResources {
|
||||
let glyph_pipeline =
|
||||
create_glyph_pipeline(device, target_format, &shader, &pipeline_layout);
|
||||
let dot_pipeline = create_dot_pipeline(device, target_format, &shader, &pipeline_layout);
|
||||
let hand_dot_pipeline =
|
||||
create_hand_dot_pipeline(device, target_format, &shader, &pipeline_layout);
|
||||
|
||||
let _model_pipelines =
|
||||
create_model_pipelines(device, target_format, &shader, &model_pipeline_layout);
|
||||
@@ -432,6 +474,19 @@ impl BackgroundRenderResources {
|
||||
contents: bytemuck::cast_slice(&glyph_instances),
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
let hand_dot_instances = build_hand_dot_instances(
|
||||
rows,
|
||||
cols,
|
||||
hand_image_texture.width as f32,
|
||||
hand_image_texture.height as f32,
|
||||
&[[0.0, 0.0]; PRESSURE_CELL_COUNT],
|
||||
);
|
||||
let hand_dot_instance_buffer =
|
||||
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Hand Fingertip Dot Matrix Instance Buffer"),
|
||||
contents: bytemuck::cast_slice(&hand_dot_instances),
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
Self {
|
||||
layout,
|
||||
@@ -445,11 +500,14 @@ impl BackgroundRenderResources {
|
||||
hand_image_pipeline,
|
||||
glyph_pipeline,
|
||||
dot_pipeline,
|
||||
hand_dot_pipeline,
|
||||
hand_image_bind_group,
|
||||
hand_image_texture,
|
||||
glyph_vertex_buffer,
|
||||
glyph_instance_buffer,
|
||||
glyph_instances,
|
||||
hand_dot_instance_buffer,
|
||||
hand_dot_instances,
|
||||
render_options,
|
||||
}
|
||||
}
|
||||
@@ -485,6 +543,21 @@ impl BackgroundRenderResources {
|
||||
0,
|
||||
bytemuck::cast_slice(&self.glyph_instances),
|
||||
);
|
||||
|
||||
// Hand mode uses five UV-anchored fingertip matrices over hand.png.
|
||||
// Rebuild their instance positions here so pressure colors update every frame.
|
||||
self.hand_dot_instances = build_hand_dot_instances(
|
||||
self.rows,
|
||||
self.cols,
|
||||
self.hand_image_texture.width as f32,
|
||||
self.hand_image_texture.height as f32,
|
||||
pressure,
|
||||
);
|
||||
queue.write_buffer(
|
||||
&self.hand_dot_instance_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&self.hand_dot_instances),
|
||||
);
|
||||
}
|
||||
|
||||
fn paint(&self, render_pass: &mut wgpu::RenderPass<'_>, active_mode: &ActiveMode) {
|
||||
@@ -493,13 +566,14 @@ impl BackgroundRenderResources {
|
||||
render_pass.set_pipeline(&self.background_pipeline);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
|
||||
render_pass.set_pipeline(&self.hand_image_pipeline);
|
||||
render_pass.set_bind_group(1, &self.hand_image_bind_group, &[]);
|
||||
render_pass.draw(0..6, 0..1);
|
||||
|
||||
match active_mode {
|
||||
ActiveMode::Finger(mode) => self.paint_finger(render_pass, mode),
|
||||
ActiveMode::Hand(mode) => self.paint_hand(render_pass, mode),
|
||||
ActiveMode::Hand(mode) => {
|
||||
render_pass.set_pipeline(&self.hand_image_pipeline);
|
||||
render_pass.set_bind_group(1, &self.hand_image_bind_group, &[]);
|
||||
render_pass.draw(0..6, 0..1);
|
||||
self.paint_hand(render_pass, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +594,12 @@ impl BackgroundRenderResources {
|
||||
|
||||
fn paint_hand(&self, render_pass: &mut wgpu::RenderPass<'_>, mode: &HandGatewayMode) {
|
||||
let _range = mode.range.clone();
|
||||
let _ = render_pass;
|
||||
|
||||
// Draw the five fingertip dot matrices after hand.png, so they sit on top of the texture.
|
||||
render_pass.set_pipeline(&self.hand_dot_pipeline);
|
||||
render_pass.set_vertex_buffer(0, self.glyph_vertex_buffer.slice(..));
|
||||
render_pass.set_vertex_buffer(1, self.hand_dot_instance_buffer.slice(..));
|
||||
render_pass.draw(0..6, 0..self.hand_dot_instances.len() as u32);
|
||||
}
|
||||
|
||||
fn visible_instance_count(&self, rows: u32, cols: u32) -> u32 {
|
||||
@@ -788,6 +867,80 @@ fn create_dot_pipeline(
|
||||
})
|
||||
}
|
||||
|
||||
fn create_hand_dot_pipeline(
|
||||
device: &wgpu::Device,
|
||||
target_format: &wgpu::TextureFormat,
|
||||
shader: &wgpu::ShaderModule,
|
||||
layout: &wgpu::PipelineLayout,
|
||||
) -> wgpu::RenderPipeline {
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Hand Fingertip Dot Matrix Pipeline"),
|
||||
layout: Some(layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: shader,
|
||||
entry_point: Some("vs_hand_dot"),
|
||||
compilation_options: Default::default(),
|
||||
buffers: &[GlyphVertex::desc(), GlyphInstance::desc()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: shader,
|
||||
entry_point: Some("fs_hand_dot"),
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: *target_format,
|
||||
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_hand_dot_instances(
|
||||
rows: u32,
|
||||
cols: u32,
|
||||
image_width: f32,
|
||||
image_height: f32,
|
||||
pressure: &PressureFrame,
|
||||
) -> Vec<GlyphInstance> {
|
||||
let mut instances = Vec::with_capacity(HAND_TIP_MATRICES.len() * rows as usize * cols as usize);
|
||||
|
||||
for tip in HAND_TIP_MATRICES {
|
||||
let cos = tip.angle_rad.cos();
|
||||
let sin = tip.angle_rad.sin();
|
||||
|
||||
for row in 0..rows {
|
||||
for col in 0..cols {
|
||||
let index = (row * cols + col) as usize;
|
||||
let [normalized, display_value] =
|
||||
pressure.get(index).copied().unwrap_or([0.0, 0.0]);
|
||||
|
||||
// Lay out a rows x cols matrix in fingertip-local pixel space.
|
||||
let local_x = (col as f32 - cols as f32 / 2.0 + 0.5) / cols as f32 * tip.size_px[0];
|
||||
let local_y = (row as f32 - rows as f32 / 2.0 + 0.5) / rows as f32 * tip.size_px[1];
|
||||
|
||||
// Rotate the local matrix so it follows the direction of the finger.
|
||||
let x = tip.center_px[0] + local_x * cos - local_y * sin;
|
||||
let y = tip.center_px[1] + local_x * sin + local_y * cos;
|
||||
|
||||
let uv_x = x / image_width.max(1.0);
|
||||
let uv_y = y / image_height.max(1.0);
|
||||
|
||||
instances.push(GlyphInstance {
|
||||
world_position: [uv_x, uv_y, 0.0, 1.0],
|
||||
style: [normalized, display_value, 0.0, 0.0],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instances
|
||||
}
|
||||
|
||||
fn build_glyph_instances(
|
||||
rows: u32,
|
||||
cols: u32,
|
||||
|
||||
Reference in New Issue
Block a user