Skip to content

Commit

Permalink
Experiment with glow
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Dec 16, 2023
1 parent 5f3f330 commit a8b8663
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 4 deletions.
36 changes: 36 additions & 0 deletions neothesia-core/src/render/glow/instance_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use wgpu::vertex_attr_array;
use wgpu_jumpstart::wgpu;

use bytemuck::{Pod, Zeroable};

#[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable, PartialEq)]
pub struct GlowInstance {
pub position: [f32; 2],
pub size: [f32; 2],
pub color: [f32; 4],
}

impl Default for GlowInstance {
fn default() -> Self {
Self {
position: [0.0, 0.0],
size: [0.0, 0.0],
color: [0.0, 0.0, 0.0, 1.0],
}
}
}

impl GlowInstance {
pub fn attributes() -> [wgpu::VertexAttribute; 4] {
vertex_attr_array!(1 => Float32x2, 2 => Float32x2, 3 => Float32x4, 4 => Float32x4)
}

pub fn layout(attributes: &[wgpu::VertexAttribute]) -> wgpu::VertexBufferLayout {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<GlowInstance>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance,
attributes,
}
}
}
96 changes: 96 additions & 0 deletions neothesia-core/src/render/glow/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
mod instance_data;
pub use instance_data::GlowInstance;

use wgpu_jumpstart::{
wgpu, Gpu, Instances, RenderPipelineBuilder, Shape, TransformUniform, Uniform,
};

pub struct GlowPipeline {
render_pipeline: wgpu::RenderPipeline,
quad: Shape,
instances: Instances<GlowInstance>,
}

impl<'a> GlowPipeline {
pub fn new(gpu: &Gpu, transform_uniform: &Uniform<TransformUniform>) -> Self {
let shader = gpu
.device
.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("RectanglePipeline::shader"),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(
"./shader.wgsl"
))),
});

let render_pipeline_layout =
gpu.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[&transform_uniform.bind_group_layout],
push_constant_ranges: &[],
});

let ri_attrs = GlowInstance::attributes();

let target = wgpu_jumpstart::default_color_target_state(gpu.texture_format);

let render_pipeline =
RenderPipelineBuilder::new(&render_pipeline_layout, "vs_main", &shader)
.fragment("fs_main", &shader, &[Some(target)])
.vertex_buffers(&[Shape::layout(), GlowInstance::layout(&ri_attrs)])
.build(&gpu.device);

let quad = Shape::new_quad(&gpu.device);
let instances = Instances::new(&gpu.device, 100_000);

Self {
render_pipeline,

quad,

instances,
}
}

pub fn render(
&'a self,
transform_uniform: &'a Uniform<TransformUniform>,
render_pass: &mut wgpu::RenderPass<'a>,
) {
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(0, &transform_uniform.bind_group, &[]);

render_pass.set_vertex_buffer(0, self.quad.vertex_buffer.slice(..));
render_pass.set_vertex_buffer(1, self.instances.buffer.slice(..));

render_pass.set_index_buffer(self.quad.index_buffer.slice(..), wgpu::IndexFormat::Uint16);

render_pass.draw_indexed(0..self.quad.indices_len, 0, 0..self.instances.len());
}

pub fn clear(&mut self) {
self.instances.data.clear();
}

pub fn instances(&mut self) -> &mut Vec<GlowInstance> {
&mut self.instances.data
}

pub fn prepare(&self, queue: &wgpu::Queue) {
self.instances.update(queue);
}

pub fn update_instance_buffer(&mut self, queue: &wgpu::Queue, instances: Vec<GlowInstance>) {
self.instances.data = instances;
self.instances.update(queue);
}

pub fn with_instances_mut<F: FnOnce(&mut Vec<GlowInstance>)>(
&mut self,
queue: &wgpu::Queue,
cb: F,
) {
cb(&mut self.instances.data);
self.instances.update(queue);
}
}
46 changes: 46 additions & 0 deletions neothesia-core/src/render/glow/shader.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
struct ViewUniform {
transform: mat4x4<f32>,
size: vec2<f32>,
}

@group(0) @binding(0)
var<uniform> view_uniform: ViewUniform;

struct Vertex {
@location(0) position: vec2<f32>,
}

struct QuadInstance {
@location(1) q_position: vec2<f32>,
@location(2) size: vec2<f32>,
@location(3) color: vec4<f32>,
}

struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) uv: vec2<f32>,
@location(1) quad_color: vec4<f32>,
}

@vertex
fn vs_main(vertex: Vertex, quad: QuadInstance) -> VertexOutput {
var i_transform: mat4x4<f32> = mat4x4<f32>(
vec4<f32>(quad.size.x, 0.0, 0.0, 0.0),
vec4<f32>(0.0, quad.size.y, 0.0, 0.0),
vec4<f32>(0.0, 0.0, 1.0, 0.0),
vec4<f32>(quad.q_position, 0.0, 1.0)
);

var out: VertexOutput;
out.position = view_uniform.transform * i_transform * vec4<f32>(vertex.position, 0.0, 1.0);
out.uv = vertex.position;
out.quad_color = quad.color;
return out;
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let m = distance(in.uv, vec2(0.5, 0.5)) * 2.0;
return mix(in.quad_color, vec4<f32>(0.0), m);

}
2 changes: 1 addition & 1 deletion neothesia-core/src/render/keyboard/key_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use wgpu_jumpstart::Color;
pub struct KeyState {
is_sharp: bool,

pressed_by_file: Option<Color>,
pub pressed_by_file: Option<Color>,
pressed_by_user: bool,
}

Expand Down
4 changes: 4 additions & 0 deletions neothesia-core/src/render/keyboard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ impl KeyboardRenderer {
&self.layout.range
}

pub fn key_states(&self) -> &[KeyState] {
&self.key_states
}

pub fn key_states_mut(&mut self) -> &mut [KeyState] {
&mut self.key_states
}
Expand Down
2 changes: 2 additions & 0 deletions neothesia-core/src/render/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod background_animation;
mod glow;
mod keyboard;
mod quad;
mod text;
mod waterfall;

pub use background_animation::BgPipeline;
pub use glow::{GlowInstance, GlowPipeline};
pub use keyboard::{KeyState as KeyboardKeyState, KeyboardRenderer};
pub use quad::{QuadInstance, QuadPipeline};
pub use text::TextRenderer;
Expand Down
13 changes: 12 additions & 1 deletion neothesia/src/scene/playing_scene/keyboard.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use midi_file::midly::MidiMessage;
use neothesia_core::render::{QuadPipeline, TextRenderer};
use neothesia_core::{
render::{KeyboardKeyState, QuadPipeline, TextRenderer},
utils::Point,
};
use piano_math::KeyboardRange;

use crate::{config::Config, render::KeyboardRenderer, song::SongConfig, target::Target};
Expand Down Expand Up @@ -34,6 +37,14 @@ impl Keyboard {
}
}

pub fn pos(&self) -> &Point<f32> {
self.renderer.pos()
}

pub fn key_states(&self) -> &[KeyboardKeyState] {
self.renderer.key_states()
}

pub fn layout(&self) -> &piano_math::KeyboardLayout {
self.renderer.layout()
}
Expand Down
48 changes: 46 additions & 2 deletions neothesia/src/scene/playing_scene/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use midi_file::midly::MidiMessage;
use neothesia_core::render::{QuadInstance, QuadPipeline};
use neothesia_core::render::{GlowInstance, GlowPipeline, QuadInstance, QuadPipeline};
use std::time::Duration;
use wgpu_jumpstart::{Color, TransformUniform, Uniform};
use winit::event::{KeyboardInput, WindowEvent};
Expand All @@ -22,13 +22,19 @@ use rewind_controller::RewindController;
mod toast_manager;
use toast_manager::ToastManager;

struct GlowState {
time: f32,
}

pub struct PlayingScene {
keyboard: Keyboard,
notes: WaterfallRenderer,

player: MidiPlayer,
rewind_controler: RewindController,
quad_pipeline: QuadPipeline,
glow_pipeline: GlowPipeline,
glow_states: Vec<GlowState>,
toast_manager: ToastManager,
}

Expand Down Expand Up @@ -58,13 +64,22 @@ impl PlayingScene {
let player = MidiPlayer::new(target, song, keyboard_layout.range.clone());
notes.update(&target.gpu.queue, player.time_without_lead_in());

let glow_states: Vec<GlowState> = keyboard
.layout()
.range
.iter()
.map(|_| GlowState { time: 0.0 })
.collect();

Self {
keyboard,

notes,
player,
rewind_controler: RewindController::new(),
quad_pipeline: QuadPipeline::new(&target.gpu, &target.transform),
glow_pipeline: GlowPipeline::new(&target.gpu, &target.transform),
glow_states,
toast_manager: ToastManager::default(),
}
}
Expand All @@ -78,6 +93,32 @@ impl PlayingScene {
..Default::default()
});
}

fn update_glow(&mut self) {
self.glow_pipeline.clear();

let key_states = self.keyboard.key_states();
for key in self.keyboard.layout().keys.iter() {
let glow_state = &mut self.glow_states[key.id()];
let glow_w = 200.0 + glow_state.time.sin() * 50.0;
let glow_h = 200.0 + glow_state.time.sin() * 50.0;

let y = self.keyboard.pos().y;
if let Some(color) = &key_states[key.id()].pressed_by_file {
glow_state.time += 0.1;
let mut color = color.into_linear_rgba();
color[0] += 0.1;
color[1] += 0.1;
color[2] += 0.1;
color[3] = 0.3;
self.glow_pipeline.instances().push(GlowInstance {
position: [key.x() - glow_w / 2.0 + key.width() / 2.0, y - glow_w / 2.0],
size: [glow_w, glow_h],
color,
});
}
}
}
}

impl Scene for PlayingScene {
Expand Down Expand Up @@ -111,8 +152,10 @@ impl Scene for PlayingScene {
.update(&mut self.quad_pipeline, &mut target.text_renderer);

self.update_progresbar(&target.window_state);
self.update_glow();

self.quad_pipeline.prepare(&target.gpu.queue);
self.glow_pipeline.prepare(&target.gpu.queue);
}

fn render<'pass>(
Expand All @@ -121,7 +164,8 @@ impl Scene for PlayingScene {
rpass: &mut wgpu::RenderPass<'pass>,
) {
self.notes.render(transform, rpass);
self.quad_pipeline.render(transform, rpass)
self.quad_pipeline.render(transform, rpass);
self.glow_pipeline.render(transform, rpass);
}

fn window_event(&mut self, target: &mut Target, event: &WindowEvent) {
Expand Down

0 comments on commit a8b8663

Please sign in to comment.