Added animations to objects and ui elements
parent
1f154c1a58
commit
8dc040cf08
|
@ -0,0 +1,26 @@
|
||||||
|
// Pick frame of animation from an instance.
|
||||||
|
//
|
||||||
|
// This function assumes that the uniform header has been loaded,
|
||||||
|
// and that `InstanceInput` contains a field `texture_index`
|
||||||
|
fn animate(instance: InstanceInput, age: f32) -> u32 {
|
||||||
|
|
||||||
|
let idx = instance.texture_index;
|
||||||
|
let len = sprites.data[idx].frame_count;
|
||||||
|
let rep = sprites.data[idx].repeatmode;
|
||||||
|
let fps = sprites.data[idx].fps;
|
||||||
|
var frame: u32 = u32(0);
|
||||||
|
|
||||||
|
if rep == u32(1) { // Repeat
|
||||||
|
let x = age / fps;
|
||||||
|
let m = f32(len);
|
||||||
|
// x fmod m
|
||||||
|
frame = u32(x - floor(x / m) * m);
|
||||||
|
} else { // Once
|
||||||
|
frame = u32(min(
|
||||||
|
(age / fps),
|
||||||
|
f32(len) - 1.0
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame + sprites.data[idx].first_frame;
|
||||||
|
}
|
|
@ -26,39 +26,12 @@ var texture_array: binding_array<texture_2d<f32>>;
|
||||||
var sampler_array: binding_array<sampler>;
|
var sampler_array: binding_array<sampler>;
|
||||||
|
|
||||||
|
|
||||||
fn fmod(x: f32, m: f32) -> f32 {
|
// INCLUDE: animate.wgsl
|
||||||
return x - floor(x / m) * m;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns texture index
|
|
||||||
// TODO: random age
|
// TODO: random age
|
||||||
// TODO: preprocessor include function
|
// TODO: configure packed asset location, better error
|
||||||
// TODO: packed location config, better error
|
|
||||||
// TODO: bounce animations
|
// TODO: bounce animations
|
||||||
// TODO: animation randomness?
|
// TODO: animation randomness?
|
||||||
fn animate(instance: InstanceInput) -> u32 {
|
|
||||||
// Age doesn't make sense here, so arbitrarily pick zero.
|
|
||||||
let age = global.current_time.x;
|
|
||||||
let len = sprites.data[instance.texture_index].frame_count;
|
|
||||||
let rep = sprites.data[instance.texture_index].repeatmode;
|
|
||||||
let fps = sprites.data[instance.texture_index].fps;
|
|
||||||
var frame: u32 = u32(0);
|
|
||||||
if rep == u32(1) {
|
|
||||||
// Repeat
|
|
||||||
frame = u32(fmod(
|
|
||||||
(age / fps),
|
|
||||||
f32(len)
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// Once
|
|
||||||
frame = u32(min(
|
|
||||||
(age / fps),
|
|
||||||
f32(len) - 1.0
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return frame + sprites.data[instance.texture_index].first_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vertex_main(
|
fn vertex_main(
|
||||||
|
@ -76,7 +49,7 @@ fn vertex_main(
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.position = transform * vec4<f32>(vertex.position, 1.0);
|
out.position = transform * vec4<f32>(vertex.position, 1.0);
|
||||||
|
|
||||||
let t = atlas.data[animate(instance)];
|
let t = atlas.data[animate(instance, global.current_time.x)];
|
||||||
out.texture_index = u32(0);
|
out.texture_index = u32(0);
|
||||||
out.texture_coords = vec2(t.xpos, t.ypos);
|
out.texture_coords = vec2(t.xpos, t.ypos);
|
||||||
if vertex.texture_coords.x == 1.0 {
|
if vertex.texture_coords.x == 1.0 {
|
||||||
|
|
|
@ -29,33 +29,7 @@ var texture_array: binding_array<texture_2d<f32>>;
|
||||||
var sampler_array: binding_array<sampler>;
|
var sampler_array: binding_array<sampler>;
|
||||||
|
|
||||||
|
|
||||||
// Returns texture index
|
// INCLUDE: animate.wgsl
|
||||||
fn animate(instance: InstanceInput) -> u32 {
|
|
||||||
let age = global.current_time.x - instance.created;
|
|
||||||
let len = sprites.data[instance.texture_index].frame_count;
|
|
||||||
let rep = sprites.data[instance.texture_index].repeatmode;
|
|
||||||
let fps = sprites.data[instance.texture_index].fps;
|
|
||||||
var frame: u32 = u32(0);
|
|
||||||
if rep == u32(1) {
|
|
||||||
// Repeat
|
|
||||||
frame = u32(fmod(
|
|
||||||
(age / fps),
|
|
||||||
f32(len)
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// Once
|
|
||||||
frame = u32(min(
|
|
||||||
(age / fps),
|
|
||||||
f32(len) - 1.0
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return frame + sprites.data[instance.texture_index].first_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fmod(x: f32, m: f32) -> f32 {
|
|
||||||
return x - floor(x / m) * m;
|
|
||||||
}
|
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vertex_main(
|
fn vertex_main(
|
||||||
|
@ -66,51 +40,25 @@ fn vertex_main(
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.texture_coords = vertex.texture_coords;
|
out.texture_coords = vertex.texture_coords;
|
||||||
|
|
||||||
|
// Skip expired particles
|
||||||
if instance.expires < global.current_time.x {
|
if instance.expires < global.current_time.x {
|
||||||
out.texture_index = u32(0);
|
out.texture_index = u32(0);
|
||||||
|
// Draw off screen
|
||||||
out.position = vec4<f32>(2.0, 2.0, 0.0, 1.0);
|
out.position = vec4<f32>(2.0, 2.0, 0.0, 1.0);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
let age = global.current_time.x - instance.created;
|
let age = global.current_time.x - instance.created;
|
||||||
|
|
||||||
let len = sprites.data[instance.texture_index].frame_count;
|
// Apply transformations
|
||||||
let rep = sprites.data[instance.texture_index].repeatmode;
|
|
||||||
let fps = sprites.data[instance.texture_index].fps;
|
|
||||||
var frame: u32 = u32(0);
|
|
||||||
if rep == u32(1) {
|
|
||||||
// Repeat
|
|
||||||
frame = u32(fmod(
|
|
||||||
(age / fps),
|
|
||||||
f32(len)
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// Once
|
|
||||||
frame = u32(min(
|
|
||||||
(age / fps),
|
|
||||||
f32(len) - 1.0
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let t = atlas.data[animate(instance)];
|
|
||||||
out.texture_index = u32(0);
|
|
||||||
out.texture_coords = vec2(t.xpos, t.ypos);
|
|
||||||
if vertex.texture_coords.x == 1.0 {
|
|
||||||
out.texture_coords = vec2(out.texture_coords.x + t.width, out.texture_coords.y);
|
|
||||||
}
|
|
||||||
if vertex.texture_coords.y == 1.0 {
|
|
||||||
out.texture_coords = vec2(out.texture_coords.x, out.texture_coords.y + t.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
let rotation = mat2x2(instance.rotation_0, instance.rotation_1);
|
let rotation = mat2x2(instance.rotation_0, instance.rotation_1);
|
||||||
|
|
||||||
var scale: f32 = instance.size / global.camera_zoom.x;
|
var scale: f32 = instance.size / global.camera_zoom.x;
|
||||||
var pos: vec2<f32> = vec2(vertex.position.x, vertex.position.y);
|
var pos: vec2<f32> = vec2(vertex.position.x, vertex.position.y);
|
||||||
|
|
||||||
pos = pos * vec2<f32>(
|
pos = pos * vec2<f32>(
|
||||||
sprites.data[instance.texture_index].aspect * scale / global.window_aspect.x,
|
sprites.data[instance.texture_index].aspect * scale / global.window_aspect.x,
|
||||||
scale
|
scale
|
||||||
);
|
);
|
||||||
|
|
||||||
pos = rotation * pos;
|
pos = rotation * pos;
|
||||||
|
|
||||||
var ipos: vec2<f32> = (
|
var ipos: vec2<f32> = (
|
||||||
|
@ -125,6 +73,19 @@ fn vertex_main(
|
||||||
);
|
);
|
||||||
|
|
||||||
out.position = vec4<f32>(pos, 0.0, 1.0);
|
out.position = vec4<f32>(pos, 0.0, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
// Compute texture coordinates
|
||||||
|
let t = atlas.data[animate(instance, age)];
|
||||||
|
out.texture_index = u32(0);
|
||||||
|
out.texture_coords = vec2(t.xpos, t.ypos);
|
||||||
|
if vertex.texture_coords.x == 1.0 {
|
||||||
|
out.texture_coords = vec2(out.texture_coords.x + t.width, out.texture_coords.y);
|
||||||
|
}
|
||||||
|
if vertex.texture_coords.y == 1.0 {
|
||||||
|
out.texture_coords = vec2(out.texture_coords.x, out.texture_coords.y + t.height);
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ var sampler_array: binding_array<sampler>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn fmod(x: vec2<f32>, m: f32) -> vec2<f32> {
|
fn fmod(x: vec2<f32>, m: f32) -> vec2<f32> {
|
||||||
return x - floor(x / m) * m;
|
return x - floor(x / m) * m;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +107,8 @@ fn vertex_main(
|
||||||
|
|
||||||
out.position = vec4<f32>(pos, 0.0, 1.0) * instance.position.z;
|
out.position = vec4<f32>(pos, 0.0, 1.0) * instance.position.z;
|
||||||
|
|
||||||
|
|
||||||
|
// Starfield sprites may not be animated
|
||||||
let i = sprites.data[global.starfield_sprite.x].first_frame;
|
let i = sprites.data[global.starfield_sprite.x].first_frame;
|
||||||
let t = atlas.data[i];
|
let t = atlas.data[i];
|
||||||
out.texture_index = u32(0);
|
out.texture_index = u32(0);
|
||||||
|
|
|
@ -27,6 +27,7 @@ var texture_array: binding_array<texture_2d<f32>>;
|
||||||
var sampler_array: binding_array<sampler>;
|
var sampler_array: binding_array<sampler>;
|
||||||
|
|
||||||
|
|
||||||
|
// INCLUDE: animate.wgsl
|
||||||
|
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
|
@ -46,8 +47,8 @@ fn vertex_main(
|
||||||
out.position = transform * vec4<f32>(vertex.position, 1.0);
|
out.position = transform * vec4<f32>(vertex.position, 1.0);
|
||||||
out.color_transform = instance.color_transform;
|
out.color_transform = instance.color_transform;
|
||||||
|
|
||||||
let i = sprites.data[instance.texture_index].first_frame;
|
// Pick texture frame
|
||||||
let t = atlas.data[i];
|
let t = atlas.data[animate(instance, global.current_time.x)];
|
||||||
out.texture_index = u32(0);
|
out.texture_index = u32(0);
|
||||||
out.texture_coords = vec2(t.xpos, t.ypos);
|
out.texture_coords = vec2(t.xpos, t.ypos);
|
||||||
if vertex.texture_coords.x == 1.0 {
|
if vertex.texture_coords.x == 1.0 {
|
||||||
|
|
|
@ -60,17 +60,29 @@ struct VertexBuffers {
|
||||||
particle: Rc<VertexBuffer>,
|
particle: Rc<VertexBuffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preprocess shader files
|
/// Basic wgsl preprocesser
|
||||||
fn preprocess_shader(
|
fn preprocess_shader(
|
||||||
shader: &str,
|
shader: &str,
|
||||||
global_uniform: &GlobalUniform,
|
global_uniform: &GlobalUniform,
|
||||||
global_uniform_group: u32,
|
global_uniform_group: u32,
|
||||||
) -> String {
|
) -> String {
|
||||||
// Insert common headers
|
// Insert dynamically-generated global definitions
|
||||||
shader.replace(
|
let shader = shader.replace(
|
||||||
"// INCLUDE: global uniform header",
|
"// INCLUDE: global uniform header",
|
||||||
&global_uniform.shader_header(global_uniform_group),
|
&global_uniform.shader_header(global_uniform_group),
|
||||||
)
|
);
|
||||||
|
|
||||||
|
// Insert common functions
|
||||||
|
let shader = shader.replace(
|
||||||
|
"// INCLUDE: animate.wgsl",
|
||||||
|
&include_str!(concat!(
|
||||||
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
|
"/shaders/include/",
|
||||||
|
"animate.wgsl"
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUState {
|
impl GPUState {
|
||||||
|
|
Loading…
Reference in New Issue