From d5caf6834353419cbe740d26a88010a78adeef08 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 00:42:22 +0100 Subject: [PATCH 1/8] Bump cargo dependency versions --- Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d158308..e9f5c1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/johanhelsing/bevy_smud" version = "0.6.0" [dependencies] -bevy = { version = "0.11", default-features = false, features = [ +bevy = { version = "0.12", default-features = false, features = [ "bevy_core_pipeline", "bevy_render", "bevy_asset", # needed for handle ids @@ -20,14 +20,14 @@ copyless = "0.1" bitflags = "2.4" [dev-dependencies] -bevy = {version = "0.11", default-features = false, features = [ +bevy = { version = "0.12", default-features = false, features = [ "bevy_winit", "x11", # github actions runners don't have libxkbcommon installed, so can't use wayland - "filesystem_watcher", -]} -bevy_asset_loader = "0.17" -bevy_lospec = "0.5" -bevy_pancam = "0.9" + "file_watcher", +] } +bevy_asset_loader = "0.18" +bevy_lospec = "0.6" +bevy_pancam = "0.10" rand = "0.8" [profile.dev] From c22d5675a2ffecececcea8af21a71f719a57a5e7 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 03:12:47 +0100 Subject: [PATCH 2/8] Minimal port to Bevy 0.12 --- Cargo.toml | 1 + assets/bevy.wgsl | 4 +- assets/gallery/stairs.wgsl | 4 +- assets/smud.wgsl | 207 +++++++++---------- assets/star_bevy.wgsl | 4 +- examples/basic.rs | 6 +- examples/bloom.rs | 2 +- examples/custom_fill.rs | 2 +- examples/hot_reload.rs | 14 +- src/bundle.rs | 6 +- src/components.rs | 2 +- src/lib.rs | 394 +++++++++++++++++++------------------ src/sdf_assets.rs | 8 +- src/shader_loading.rs | 115 ++++++----- src/util.rs | 5 + 15 files changed, 397 insertions(+), 377 deletions(-) create mode 100644 src/util.rs diff --git a/Cargo.toml b/Cargo.toml index e9f5c1a..bca0de8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ bevy = { version = "0.12", default-features = false, features = [ bytemuck = { version = "1.7", features = ["derive"] } copyless = "0.1" bitflags = "2.4" +fixedbitset = "0.4" [dev-dependencies] bevy = { version = "0.12", default-features = false, features = [ diff --git a/assets/bevy.wgsl b/assets/bevy.wgsl index 8b3bc74..f1f11d6 100644 --- a/assets/bevy.wgsl +++ b/assets/bevy.wgsl @@ -9,9 +9,9 @@ fn bevy_head(p: vec2) -> f32 { return min(skull, beak); } -fn sdf(p: vec2) -> f32 { +fn sdf(p_in: vec2) -> f32 { let scale = 300.0; - var p = p / scale; + var p = p_in / scale; let p_upper_wing = p - vec2(-0.3, -0.25); let upper_wing = max( diff --git a/assets/gallery/stairs.wgsl b/assets/gallery/stairs.wgsl index 1ac2cbf..3bc2434 100644 --- a/assets/gallery/stairs.wgsl +++ b/assets/gallery/stairs.wgsl @@ -2,8 +2,8 @@ #import smud -fn sdf(p: vec2) -> f32 { +fn sdf(p_in: vec2) -> f32 { let s = 5.; - let p = p - vec2(-20.); + let p = p_in - vec2(-20.); return smud::sd_stairs(p / s, vec2(1.), 8.) * s; } \ No newline at end of file diff --git a/assets/smud.wgsl b/assets/smud.wgsl index 997e791..7366ccf 100644 --- a/assets/smud.wgsl +++ b/assets/smud.wgsl @@ -6,18 +6,18 @@ fn sd_circle(p: vec2, r: f32) -> f32 { } fn sd_rounded_box(p: vec2, b: vec2, r: vec4) -> f32 { - var r = r; + var r_2 = r; // swizzle assigment isn't supported yet - // r.xy = select(r.zw, r.xy, p.x > 0.); - let tmp = select(r.zw, r.xy, p.x > 0.); - r.x = tmp.x; - r.y = tmp.y; - r.x = select(r.y, r.x, p.y > 0.); - let q = abs(p) - b + r.x; + // r_2.xy = select(r_2.zw, r_2.xy, p.x > 0.); + let tmp = select(r_2.zw, r_2.xy, p.x > 0.); + r_2.x = tmp.x; + r_2.y = tmp.y; + r_2.x = select(r_2.y, r_2.x, p.y > 0.); + let q = abs(p) - b + r_2.x; return min( max(q.x, q.y), 0. - ) + length(max(q, vec2(0.))) - r.x; + ) + length(max(q, vec2(0.))) - r_2.x; } fn sd_box(p: vec2, b: vec2) -> f32 { @@ -50,58 +50,58 @@ fn dot2_(a: vec2) -> f32 { } fn sd_rhombus(p: vec2, b: vec2) -> f32 { - let p = abs(p); - let h = clamp(ndot(b - 2. * p, b) / dot(b, b), -1., 1.); - let d = length(p - 0.5 * b * vec2(1. - h, 1. + h)); - return d * sign(p.x * b.y + p.y * b.x - b.x * b.y); + let p_2 = abs(p); + let h = clamp(ndot(b - 2. * p_2, b) / dot(b, b), -1., 1.); + let d = length(p_2 - 0.5 * b * vec2(1. - h, 1. + h)); + return d * sign(p_2.x * b.y + p_2.y * b.x - b.x * b.y); } fn sd_trapezoid(p: vec2, r1: f32, r2: f32, he: f32) -> f32 { - var p = p; + var p_2 = p; let k1 = vec2(r2, he); let k2 = vec2(r2 - r1, 2. * he); - p.x = abs(p.x); - let r = select(r2, r1, p.y < 0.); - let ca = vec2(p.x - min(p.x, r), abs(p.y) - he); - let cb = p - k1 + k2 * clamp(dot(k1 - p, k2) / dot2_(k2), 0., 1.); + p_2.x = abs(p_2.x); + let r = select(r2, r1, p_2.y < 0.); + let ca = vec2(p_2.x - min(p_2.x, r), abs(p_2.y) - he); + let cb = p_2 - k1 + k2 * clamp(dot(k1 - p_2, k2) / dot2_(k2), 0., 1.); let s = select(1., -1., cb.x < 0. && ca.y < 0.); return s * sqrt(min(dot2_(ca), dot2_(cb))); } fn sd_parallelogram(p: vec2, wi: f32, he: f32, sk: f32) -> f32 { let e = vec2(sk, he); - var p = select(p, -p, p.y < 0.); - var w = p - e; + var p_2 = select(p, -p, p.y < 0.); + var w = p_2 - e; w.x = w.x - clamp(w.x, -wi, wi); var d = vec2(dot(w, w), -w.y); - let s = p.x*e.y - p.y*e.x; - p = select(p, -p, s < 0.); - var v = p - vec2(wi, 0.); + let s = p_2.x*e.y - p_2.y*e.x; + p_2 = select(p_2, -p_2, s < 0.); + var v = p_2 - vec2(wi, 0.); v = v - e * clamp(dot(v, e) / dot(e, e), -1., 1.); d = min(d, vec2(dot(v, v), wi * he - abs(s))); return sqrt(d.x)*sign(-d.y); } fn sd_equilateral_triangle(p: vec2, r: f32) -> f32 { - var p = p; + var p_2 = p; let k = sqrt(3.); - p.x = abs(p.x) - r; - p.y = p.y + r / k; - if (p.x + k * p.y > 0.) { - p = vec2(p.x - k * p.y, -k * p.x - p.y) / 2.; + p_2.x = abs(p_2.x) - r; + p_2.y = p_2.y + r / k; + if (p_2.x + k * p_2.y > 0.) { + p_2 = vec2(p_2.x - k * p_2.y, -k * p_2.x - p_2.y) / 2.; } - p.x = p.x - clamp(p.x, -2. * r, 0.); - return -length(p) * sign(p.y); + p_2.x = p_2.x - clamp(p_2.x, -2. * r, 0.); + return -length(p_2) * sign(p_2.y); } fn sd_triangle_isosceles(p: vec2, q: vec2) -> f32 { - var p = p; - p.x = abs(p.x); - let a = p - q * clamp(dot(p, q)/dot(q, q), 0., 1.); - let b = p - q * vec2(clamp(p.x / q.x, 0., 1.), 1.); + var p_2 = p; + p_2.x = abs(p_2.x); + let a = p_2 - q * clamp(dot(p_2, q)/dot(q, q), 0., 1.); + let b = p_2 - q * vec2(clamp(p_2.x / q.x, 0., 1.), 1.); let s = -sign(q.y); - let d = min(vec2(dot(a, a), s * (p.x * q.y - p.y * q.x)), - vec2(dot(b, b), s * (p.y - q.y))); + let d = min(vec2(dot(a, a), s * (p_2.x * q.y - p_2.y * q.x)), + vec2(dot(b, b), s * (p_2.y - q.y))); return -sqrt(d.x) * sign(d.y); } @@ -126,33 +126,33 @@ fn sd_triangle(p: vec2, p0: vec2, p1: vec2, p2: vec2) -> f32 } fn sd_uneven_capsule(p: vec2, r1: f32, r2: f32, h: f32) -> f32 { - var p = p; - p.x = abs(p.x); + var p_2 = p; + p_2.x = abs(p_2.x); let b = (r1 - r2) / h; let a = sqrt(1. - b * b); - let k = dot(p, vec2(-b, a)); + let k = dot(p_2, vec2(-b, a)); if (k < 0.) { - return length(p) - r1; + return length(p_2) - r1; } if (k > a*h) { - return length(p - vec2(0., h)) - r2; + return length(p_2 - vec2(0., h)) - r2; } - return dot(p, vec2(a, b)) - r1; + return dot(p_2, vec2(a, b)) - r1; } fn sd_pentagon(p: vec2, r: f32) -> f32 { let k = vec3(0.809016994, 0.587785252, 0.726542528); - var p = p; - p.x = abs(p.x); - p = p - 2. * min(dot(vec2(-k.x, k.y), p), 0.) * vec2(-k.x, k.y); - p = p - 2. * min(dot(vec2(k.x, k.y), p), 0.) * vec2(k.x, k.y); - p = p - vec2(clamp(p.x, -r * k.z, r * k.z), r); - return length(p) * sign(p.y); + var p_2 = p; + p_2.x = abs(p_2.x); + p_2 = p_2 - 2. * min(dot(vec2(-k.x, k.y), p_2), 0.) * vec2(-k.x, k.y); + p_2 = p_2 - 2. * min(dot(vec2(k.x, k.y), p_2), 0.) * vec2(k.x, k.y); + p_2 = p_2 - vec2(clamp(p_2.x, -r * k.z, r * k.z), r); + return length(p_2) * sign(p_2.y); } -fn sd_hexagon(p: vec2, r: f32) -> f32 { +fn sd_hexagon(p_in: vec2, r: f32) -> f32 { let k = vec3(-0.866025404, 0.5, 0.577350269); - var p = abs(p); + var p = abs(p_in); p = p - 2. * min(dot(k.xy, p), 0.) * k.xy; p = p - vec2(clamp(p.x, -k.z * r, k.z * r), r); return length(p) * sign(p.y); @@ -160,26 +160,26 @@ fn sd_hexagon(p: vec2, r: f32) -> f32 { fn sd_octagon(p: vec2, r: f32) -> f32 { let k = vec3(-0.9238795325, 0.3826834323, 0.4142135623); - var p = abs(p); - p = p - 2. * min(dot(vec2(k.x, k.y), p), 0.) * vec2(k.x, k.y); - p = p - 2. * min(dot(vec2(-k.x, k.y), p), 0.) * vec2(-k.x, k.y); - p = p - vec2(clamp(p.x, -k.z * r, k.z * r), r); - return length(p) * sign(p.y); + var p_2 = abs(p); + p_2 = p_2 - 2. * min(dot(vec2(k.x, k.y), p_2), 0.) * vec2(k.x, k.y); + p_2 = p_2 - 2. * min(dot(vec2(-k.x, k.y), p_2), 0.) * vec2(-k.x, k.y); + p_2 = p_2 - vec2(clamp(p_2.x, -k.z * r, k.z * r), r); + return length(p_2) * sign(p_2.y); } -fn sd_hexagram(p: vec2, r: f32) -> f32 { +fn sd_hexagram(p_in: vec2, r: f32) -> f32 { let k = vec4(-0.5, 0.8660254038, 0.5773502692, 1.7320508076); - var p = abs(p); + var p = abs(p_in); p = p - 2. * min(dot(k.xy, p), 0.) * k.xy; p = p - 2. * min(dot(k.yx, p), 0.) * k.yx; p = p - vec2(clamp(p.x, r * k.z, r * k.w), r); return length(p) * sign(p.y); } -fn sd_star_5_(p: vec2, r: f32, rf: f32) -> f32 { +fn sd_star_5_(p_in: vec2, r: f32, rf: f32) -> f32 { let k1 = vec2(0.809016994375, -0.587785252292); let k2 = vec2(-k1.x, k1.y); - var p = p; + var p = p_in; p.x = abs(p.x); p = p - 2. * max(dot(k1, p), 0.) * k1; p = p - 2. * max(dot(k2, p), 0.) * k2; @@ -197,31 +197,31 @@ fn modulo(x: f32, y: f32) -> f32 { return x - y * floor(x / y); } -fn sd_star(p: vec2, r: f32, n: i32, m: f32) -> f32 { +fn sd_star(p_in: vec2, r: f32, n: i32, m: f32) -> f32 { // next 4 lines can be precomputed for a given shape let an = 3.141593 / f32(n); let en = 3.141593 / m; // m is between 2 and n let acs = vec2(cos(an), sin(an)); let ecs = vec2(cos(en), sin(en)); // ecs=vec2(0, 1) for regular polygon - let bn = modulo(atan2(p.x, p.y), (2. * an)) - an; - var p = length(p) * vec2(cos(bn), abs(sin(bn))); + let bn = modulo(atan2(p_in.x, p_in.y), (2. * an)) - an; + var p = length(p_in) * vec2(cos(bn), abs(sin(bn))); p = p - r * acs; p = p + ecs * clamp(-dot(p, ecs), 0., r * acs.y / ecs.y); return length(p) * sign(p.x); } -fn sd_pie(p: vec2, c: vec2, r: f32) -> f32 { - var p = p; +fn sd_pie(p_in: vec2, c: vec2, r: f32) -> f32 { + var p = p_in; p.x = abs(p.x); let l = length(p) - r; let m = length(p - c * clamp(dot(p, c), 0., r)); // c=sin/cos of aperture return max(l, m * sign(c.y * p.x - c.x * p.y)); } -fn sd_cut_disk(p: vec2, r: f32, h: f32) -> f32 { +fn sd_cut_disk(p_in: vec2, r: f32, h: f32) -> f32 { let w = sqrt(r * r - h * h); // constant for any given shape - var p = p; + var p = p_in; p.x = abs(p.x); let s = max( (h - r) * p.x * p.x + w * w * (h + r - 2. * p.y), @@ -235,8 +235,8 @@ fn sd_cut_disk(p: vec2, r: f32, h: f32) -> f32 { } // sc is the sin/cos of the arc's aperture -fn sd_arc(p: vec2, sc: vec2, ra: f32, rb: f32) -> f32 { - var p = p; +fn sd_arc(p_in: vec2, sc: vec2, ra: f32, rb: f32) -> f32 { + var p = p_in; p.x = abs(p.x); return select( abs(length(p)-ra), @@ -245,9 +245,9 @@ fn sd_arc(p: vec2, sc: vec2, ra: f32, rb: f32) -> f32 { ) - rb; } -fn sd_arc_oriented(p: vec2, sc_orientation: vec2, sc_aperture: vec2, ra: f32, rb: f32) -> f32 +fn sd_arc_oriented(p_in: vec2, sc_orientation: vec2, sc_aperture: vec2, ra: f32, rb: f32) -> f32 { - var p = p; + var p = p_in; p = p * mat2x2(sc_orientation.x, sc_orientation.y, -sc_orientation.y, sc_orientation.x); p.x = abs(p.x); let k = select( @@ -258,8 +258,8 @@ fn sd_arc_oriented(p: vec2, sc_orientation: vec2, sc_aperture: vec2, c: vec2, r: f32, w: vec2) -> f32 { - var p = p; +fn sd_horseshoe(p_in: vec2, c: vec2, r: f32, w: vec2) -> f32 { + var p = p_in; p.x = abs(p.x); let l = length(p); p = mat2x2(-c.x, c.y, c.y, c.x) * p; @@ -271,9 +271,9 @@ fn sd_horseshoe(p: vec2, c: vec2, r: f32, w: vec2) -> f32 { return length(max(p, vec2(0.))) + min(0., max(p.x, p.y)); } -fn sd_rounded_cross(p: vec2, h: f32) -> f32 { +fn sd_rounded_cross(p_in: vec2, h: f32) -> f32 { let k = 0.5 * (h + 1. / h); // k should be const at modeling time - var p = abs(p); + var p = abs(p_in); return select( sqrt(min( dot2_(p - vec2(0., h)), @@ -284,8 +284,8 @@ fn sd_rounded_cross(p: vec2, h: f32) -> f32 { ); } -fn sd_egg(p: vec2, ra: f32, rb: f32) -> f32 { - var p = p; +fn sd_egg(p_in: vec2, ra: f32, rb: f32) -> f32 { + var p = p_in; let k = sqrt(3.); p.x = abs(p.x); let r = ra - rb; @@ -300,8 +300,8 @@ fn sd_egg(p: vec2, ra: f32, rb: f32) -> f32 { ) - rb; } -fn sd_heart(p: vec2) -> f32 { - var p = p; +fn sd_heart(p_in: vec2) -> f32 { + var p = p_in; p.x = abs(p.x); if (p.y + p.x > 1.) { @@ -314,8 +314,8 @@ fn sd_heart(p: vec2) -> f32 { )) * sign(p.x - p.y); } -fn sd_cross(p: vec2, b: vec2, r: f32) -> f32 { - var p = abs(p); +fn sd_cross(p_in: vec2, b: vec2, r: f32) -> f32 { + var p = abs(p_in); p = select(p.xy, p.yx, p.y > p.x); let q = p - b; let k = max(q.y, q.x); @@ -327,8 +327,8 @@ fn sd_cross(p: vec2, b: vec2, r: f32) -> f32 { return sign(k) * length(max(w, vec2(0.))) + r; } -fn sd_rounded_x(p: vec2, w: f32, r: f32) -> f32 { - let p = abs(p); +fn sd_rounded_x(p_in: vec2, w: f32, r: f32) -> f32 { + let p = abs(p_in); return length(p - min(p.x + p.y, w) * 0.5) - r; } @@ -354,8 +354,8 @@ fn sd_rounded_x(p: vec2, w: f32, r: f32) -> f32 { // https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm // Has huge issues with instability when close to a circle or very eccentric -fn sd_ellipse(p: vec2, a: f32, b: f32) -> f32 { - var p = abs(p); +fn sd_ellipse(p_in: vec2, a: f32, b: f32) -> f32 { + var p = abs(p_in); var ab = vec2(a, b); if (p.x > p.y) { p = p.yx; @@ -392,8 +392,8 @@ fn sd_ellipse(p: vec2, a: f32, b: f32) -> f32 { return length(r - p) * sign(p.y - r.y); } -fn sd_parabola(pos: vec2, k: f32) -> f32 { - var pos = pos; +fn sd_parabola(p_in: vec2, k: f32) -> f32 { + var pos = p_in; pos.x = abs(pos.x); let ik = 1. / k; let p = ik * (pos.y - 0.5 * ik) / 3.; @@ -408,8 +408,8 @@ fn sd_parabola(pos: vec2, k: f32) -> f32 { return length(pos-vec2(x, k*x*x)) * sign(pos.x-x); } -fn sd_parabola_segment(pos: vec2, wi: f32, he: f32) -> f32 { - var pos = pos; +fn sd_parabola_segment(p_in: vec2, wi: f32, he: f32) -> f32 { + var pos = p_in; pos.x = abs(pos.x); let ik = wi * wi / he; let p = ik * (he - pos.y - 0.5 * ik) / 3.; @@ -466,8 +466,8 @@ fn sd_bezier(pos: vec2, A: vec2, B: vec2, C: vec2) -> f32 { return sqrt(res); } -fn sd_blobby_cross(pos: vec2, he: f32) -> f32 { - var pos = abs(pos); +fn sd_blobby_cross(p_in: vec2, he: f32) -> f32 { + var pos = abs(p_in); pos = vec2( abs(pos.x - pos.y), 1. - pos.x - pos.y @@ -491,8 +491,8 @@ fn sd_blobby_cross(pos: vec2, he: f32) -> f32 { return length(z) * sign(z.y); } -fn sd_tunnel(p: vec2, wh: vec2) -> f32 { - let p = vec2(abs(p.x), -p.y); +fn sd_tunnel(p_in: vec2, wh: vec2) -> f32 { + let p = vec2(abs(p_in.x), -p_in.y); var q = p - wh; let d1 = dot2_(vec2(max(q.x, 0.), q.y)); @@ -503,7 +503,8 @@ fn sd_tunnel(p: vec2, wh: vec2) -> f32 { return select(d, -d, max(q.x, q.y) < 0.); } -fn sd_stairs(p: vec2, wh: vec2, n: f32) -> f32 { +fn sd_stairs(p_in: vec2, wh: vec2, n: f32) -> f32 { + var p = p_in; let ba = wh * n; var d = min( dot2_(p - vec2(clamp(p.x, 0., ba.x), 0.)), @@ -512,7 +513,7 @@ fn sd_stairs(p: vec2, wh: vec2, n: f32) -> f32 { var s = sign(max(-p.y, p.x - ba.x)); let dia = length(wh); - var p = mat2x2(wh.x, -wh.y, wh.y, wh.x) * p / dia; + p = mat2x2(wh.x, -wh.y, wh.y, wh.x) * p / dia; let id = clamp(round(p.x / dia), 0., n - 1.); p.x = p.x - id * dia; p = mat2x2(wh.x, wh.y,-wh.y, wh.x) * p / dia; @@ -529,8 +530,8 @@ fn sd_stairs(p: vec2, wh: vec2, n: f32) -> f32 { return sqrt(d) * s; } -fn sd_vesica(p: vec2, r: f32, d: f32) -> f32 { - let p = abs(p); +fn sd_vesica(p_in: vec2, r: f32, d: f32) -> f32 { + let p = abs(p_in); let b = sqrt(r * r - d * d); return select( length(p - vec2(-d, 0.)) - r, @@ -539,8 +540,8 @@ fn sd_vesica(p: vec2, r: f32, d: f32) -> f32 { ); } -fn sd_moon(p: vec2, d: f32, ra: f32, rb: f32) -> f32 { - var p = p; +fn sd_moon(p_in: vec2, d: f32, ra: f32, rb: f32) -> f32 { + var p = p_in; p.y = abs(p.y); let a = (ra * ra - rb * rb + d * d) / (2. * d); let b = sqrt(max(ra * ra - a * a, 0.)); @@ -653,10 +654,10 @@ fn op_smooth_intersect(d1: f32, d2: f32, k: f32) -> f32 { return mix(d2, d1, h) + k * h * (1. - h); } -// complex (and sometimes inexact shapes:) +// // complex (and sometimes inexact shapes:) -fn sd_arrow_head(p: vec2, w: f32, h: f32) -> f32 { - var p = p; - p.x = abs(p.x); - return sd_segment(p, vec2(0., 0.), vec2(w, -h)); -} \ No newline at end of file +// fn sd_arrow_head(p: vec2, w: f32, h: f32) -> f32 { +// var p = p; +// p.x = abs(p.x); +// return sd_segment(p, vec2(0., 0.), vec2(w, -h)); +// } \ No newline at end of file diff --git a/assets/star_bevy.wgsl b/assets/star_bevy.wgsl index 48ae5d5..d14f43d 100644 --- a/assets/star_bevy.wgsl +++ b/assets/star_bevy.wgsl @@ -10,9 +10,9 @@ fn bevy_head(p: vec2) -> f32 { return min(skull, beak); } -fn bevy(p: vec2) -> f32 { +fn bevy(p_in: vec2) -> f32 { let scale = 300.0; - var p = p / scale; + var p = p_in / scale; let p_upper_wing = p - vec2(-0.3, -0.25); let upper_wing = max( diff --git a/examples/basic.rs b/examples/basic.rs index 03f39d8..b0816af 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -28,9 +28,9 @@ fn setup( let peanut = shaders.add_sdf_body( r" // Taking the absolute value of p.x creates a vertical line of symmetry -let p = vec2(abs(p.x), p.y); +let p_2 = vec2(abs(p.x), p.y); // By subtracting from p, we can move shapes -return smud::sd_circle(p - vec2(20., 0.), 40.); +return smud::sd_circle(p_2 - vec2(20., 0.), 40.); ", ); @@ -71,7 +71,7 @@ return smud::sd_circle(p - vec2(20., 0.), 40.); sdf: bevy, // You can also specify a custom type of fill // The simple fill is just a simple anti-aliased opaque fill - fill: SIMPLE_FILL_HANDLE.typed(), + fill: SIMPLE_FILL_HANDLE, frame: Frame::Quad(295.), }, ..default() diff --git a/examples/bloom.rs b/examples/bloom.rs index ecabd36..4a2da01 100644 --- a/examples/bloom.rs +++ b/examples/bloom.rs @@ -32,7 +32,7 @@ fn setup(mut commands: Commands, mut shaders: ResMut>) { // The frame needs to be bigger than the shape we're drawing // Since the circle has radius 70, we make the half-size of the quad 80. frame: Frame::Quad(80.), - fill: SIMPLE_FILL_HANDLE.typed(), + fill: SIMPLE_FILL_HANDLE, }, ..default() }); diff --git a/examples/custom_fill.rs b/examples/custom_fill.rs index 257cd4a..67204d1 100644 --- a/examples/custom_fill.rs +++ b/examples/custom_fill.rs @@ -36,7 +36,7 @@ fn setup( shape: SmudShape { color: Color::BLUE, sdf: asset_server.load("bevy.wgsl"), - fill: SIMPLE_FILL_HANDLE.typed(), + fill: SIMPLE_FILL_HANDLE, frame: Frame::Quad(295.), }, ..default() diff --git a/examples/hot_reload.rs b/examples/hot_reload.rs index f3ce838..fa58a4c 100644 --- a/examples/hot_reload.rs +++ b/examples/hot_reload.rs @@ -1,20 +1,12 @@ -use bevy::{asset::ChangeWatcher, prelude::*}; +use bevy::prelude::*; use bevy_smud::prelude::*; -use std::time::Duration; fn main() { App::new() // bevy_smud comes with anti-aliasing built into the standards fills // which is more efficient than MSAA, and also works on Linux, wayland .insert_resource(Msaa::Off) - .add_plugins(( - DefaultPlugins.set(AssetPlugin { - // enable hot-reloading so we can see changes to wgsl files without relaunching the app - watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), - ..default() - }), - SmudPlugin, - )) + .add_plugins((DefaultPlugins, SmudPlugin)) .add_systems(Startup, setup) .run(); } @@ -34,7 +26,7 @@ fn setup(mut commands: Commands, asset_server: Res) { sdf: bevy, // You can also specify a custom type of fill // The simple fill is just a simple anti-aliased opaque fill - fill: SIMPLE_FILL_HANDLE.typed(), + fill: SIMPLE_FILL_HANDLE, frame: Frame::Quad(295.), }, ..default() diff --git a/src/bundle.rs b/src/bundle.rs index ffc75f6..8d6d433 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -15,8 +15,10 @@ pub struct ShapeBundle { pub global_transform: GlobalTransform, /// User indication of whether an entity is visible pub visibility: Visibility, - /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering - pub computed_visibility: ComputedVisibility, + /// The inherited visibility of the entity. + pub inherited_visibility: InheritedVisibility, + /// The view visibility of the entity. + pub view_visibility: ViewVisibility, } // #[derive(Bundle, Default, Clone, Debug)] diff --git a/src/components.rs b/src/components.rs index dc3b086..be95ec3 100644 --- a/src/components.rs +++ b/src/components.rs @@ -26,7 +26,7 @@ impl Default for SmudShape { color: Color::PINK, sdf: default(), frame: default(), - fill: DEFAULT_FILL_HANDLE.typed(), + fill: DEFAULT_FILL_HANDLE, } } } diff --git a/src/lib.rs b/src/lib.rs index 7471256..c17238f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,9 @@ #![doc = include_str!("../README.md")] #![allow(clippy::too_many_arguments)] -use std::cmp::Ordering; +use std::ops::Range; use bevy::{ - asset::HandleId, core_pipeline::core_2d::Transparent2d, ecs::{ query::ROQueryItem, @@ -16,22 +15,20 @@ use bevy::{ }, math::Vec3Swizzles, prelude::*, - reflect::Uuid, render::{ globals::{GlobalsBuffer, GlobalsUniform}, render_phase::{ - AddRenderCommand, BatchedPhaseItem, DrawFunctions, PhaseItem, RenderCommand, - RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass, + AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand, RenderCommandResult, + RenderPhase, SetItemPipeline, TrackedRenderPass, }, render_resource::{ - BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, - BufferBindingType, BufferUsages, BufferVec, CachedRenderPipelineId, ColorTargetState, - ColorWrites, Face, FragmentState, FrontFace, MultisampleState, PipelineCache, - PolygonMode, PrimitiveState, PrimitiveTopology, RenderPipelineDescriptor, ShaderImport, - ShaderStages, ShaderType, SpecializedRenderPipeline, SpecializedRenderPipelines, - TextureFormat, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, - VertexStepMode, + BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor, + BindGroupLayoutEntry, BindingType, BlendState, BufferBindingType, BufferUsages, + BufferVec, CachedRenderPipelineId, ColorTargetState, ColorWrites, Face, FragmentState, + FrontFace, MultisampleState, PipelineCache, PolygonMode, PrimitiveState, + PrimitiveTopology, RenderPipelineDescriptor, ShaderImport, ShaderStages, ShaderType, + SpecializedRenderPipeline, SpecializedRenderPipelines, TextureFormat, VertexAttribute, + VertexBufferLayout, VertexFormat, VertexState, VertexStepMode, }, renderer::{RenderDevice, RenderQueue}, texture::BevyDefault, @@ -41,10 +38,10 @@ use bevy::{ }, Extract, MainWorld, Render, RenderApp, RenderSet, }, - utils::{FloatOrd, HashMap}, + utils::{EntityHashMap, FloatOrd, HashMap}, }; use bytemuck::{Pod, Zeroable}; -use copyless::VecHelper; +use fixedbitset::FixedBitSet; use shader_loading::*; // use ui::UiShapePlugin; @@ -52,10 +49,13 @@ pub use bundle::ShapeBundle; pub use components::*; pub use shader_loading::{DEFAULT_FILL_HANDLE, SIMPLE_FILL_HANDLE}; +use crate::util::generate_shader_id; + mod bundle; mod components; mod sdf_assets; mod shader_loading; +mod util; // mod ui; /// Re-export of the essentials needed for rendering shapes @@ -94,7 +94,13 @@ impl Plugin for SmudPlugin { .init_resource::() .init_resource::>() .add_systems(ExtractSchedule, (extract_shapes, extract_sdf_shaders)) - .add_systems(Render, queue_shapes.in_set(RenderSet::Queue)); + .add_systems( + Render, + ( + queue_shapes.in_set(RenderSet::Queue), + prepare_shapes.in_set(RenderSet::PrepareBindGroups), + ), + ); } app.register_type::(); @@ -132,22 +138,21 @@ impl RenderCommand

for SetShapeViewBindGroup } struct DrawShapeBatch; -impl RenderCommand

for DrawShapeBatch { +impl RenderCommand

for DrawShapeBatch { type Param = SRes; type ViewWorldQuery = (); type ItemWorldQuery = Read; fn render<'w>( - item: &P, + _item: &P, _view: (), - _shape_batch: &'_ ShapeBatch, + batch: &'_ ShapeBatch, shape_meta: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { - // let shape_batch = query_batch.get(item.entity()).unwrap(); let shape_meta = shape_meta.into_inner(); pass.set_vertex_buffer(0, shape_meta.vertices.buffer().unwrap().slice(..)); - pass.draw(0..4, item.batch_range().as_ref().unwrap().clone()); + pass.draw(0..4, batch.range.clone()); RenderCommandResult::Success } } @@ -198,7 +203,7 @@ impl FromWorld for SmudPipeline { #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct SmudPipelineKey { mesh: PipelineKey, - shader: (HandleId, HandleId), + shader: (AssetId, AssetId), hdr: bool, } @@ -249,7 +254,7 @@ impl SpecializedRenderPipeline for SmudPipeline { RenderPipelineDescriptor { vertex: VertexState { - shader: VERTEX_SHADER_HANDLE.typed(), + shader: VERTEX_SHADER_HANDLE, entry_point: "vertex".into(), shader_defs: Vec::new(), buffers: vec![VertexBufferLayout { @@ -298,7 +303,7 @@ impl SpecializedRenderPipeline for SmudPipeline { } #[derive(Default)] -struct ShapeShaders(HashMap<(HandleId, HandleId), Handle>); +struct ShapeShaders(HashMap<(AssetId, AssetId), Handle>); // TODO: do some of this work in the main world instead, so we don't need to take a mutable // reference to MainWorld. @@ -317,7 +322,7 @@ fn extract_sdf_shaders(mut main_world: ResMut, mut pipeline: ResMut match shader.import_path() { ShaderImport::Custom(p) => p.to_owned(), _ => { - let id = Uuid::new_v4(); + let id = generate_shader_id(); let path = format!("smud::generated::{id}"); shader.set_import_path(&path); path @@ -333,7 +338,7 @@ fn extract_sdf_shaders(mut main_world: ResMut, mut pipeline: ResMut match shader.import_path() { ShaderImport::Custom(p) => p.to_owned(), _ => { - let id = Uuid::new_v4(); + let id = generate_shader_id(); let path = format!("smud::generated::{id}"); shader.set_import_path(&path); path @@ -367,7 +372,9 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 {{ }} "# ), - format!("smud::generated::{shader_key:?}"), + // format!("smud::generated::{shader_key:?}"), + // TODO + format!("smud::generated::bogus_key"), ); // todo does this work, or is it too late? @@ -385,34 +392,39 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 {{ struct ExtractedShape { color: Color, frame: f32, - sdf_shader: Handle, // todo could be HandleId? - fill_shader: Handle, // todo could be HandleId? + sdf_shader: Handle, + fill_shader: Handle, transform: GlobalTransform, } #[derive(Resource, Default, Debug)] -struct ExtractedShapes(Vec); +struct ExtractedShapes { + shapes: EntityHashMap, +} fn extract_shapes( mut extracted_shapes: ResMut, - query: Extract>, + shape_query: Extract>, ) { - extracted_shapes.0.clear(); + extracted_shapes.shapes.clear(); - for (shape, computed_visibility, transform) in query.iter() { - if !computed_visibility.is_visible() { + for (entity, view_visibility, shape, transform) in shape_query.iter() { + if !view_visibility.get() { continue; } let Frame::Quad(frame) = shape.frame; - extracted_shapes.0.alloc().init(ExtractedShape { - color: shape.color, - transform: *transform, - sdf_shader: shape.sdf.clone_weak(), - fill_shader: shape.fill.clone_weak(), - frame, - }); + extracted_shapes.shapes.insert( + entity, + ExtractedShape { + color: shape.color, + transform: *transform, + sdf_shader: shape.sdf.clone_weak(), + fill_shader: shape.fill.clone_weak(), + frame, + }, + ); } } @@ -465,176 +477,183 @@ impl PipelineKey { } fn queue_shapes( - mut commands: Commands, + mut view_entities: Local, + draw_functions: Res>, + smud_pipeline: Res, + mut pipelines: ResMut>, + pipeline_cache: ResMut, + msaa: Res, + extracted_shapes: ResMut, mut views: Query<( &mut RenderPhase, - &ExtractedView, &VisibleEntities, + &ExtractedView, )>, - mut pipelines: ResMut>, - pipeline_cache: ResMut, - mut extracted_shapes: ResMut, // todo needs mut? - mut shape_meta: ResMut, - transparent_draw_functions: Res>, - render_device: Res, - smud_pipeline: Res, - msaa: Res, - view_uniforms: Res, - render_queue: Res, - globals_buffer: Res, + // ? ) { - // Clear the vertex buffer - shape_meta.vertices.clear(); - - let view_binding = match view_uniforms.uniforms.binding() { - Some(binding) => binding, - None => return, - }; - - let globals = globals_buffer.buffer.binding().unwrap(); // todo if-let - - shape_meta.view_bind_group = Some(render_device.create_bind_group(&BindGroupDescriptor { - entries: &[ - BindGroupEntry { - binding: 0, - resource: view_binding, - }, - BindGroupEntry { - binding: 1, - resource: globals.clone(), - }, - ], - label: Some("smud_shape_view_bind_group"), - layout: &smud_pipeline.view_layout, - })); - - // Vertex buffer index - let mut index = 0; - - let draw_smud_shape = transparent_draw_functions - .read() - .get_id::() - .unwrap(); - - let shape_meta = &mut shape_meta; + let draw_smud_shape_function = draw_functions.read().get_id::().unwrap(); // Iterate over each view (a camera is a view) - for (mut transparent_phase, view, _visible_entities) in views.iter_mut() { - // todo: check visible entities? - - let extracted_shapes = &mut extracted_shapes.0; - - // Sort shapes by z for correct transparency and then by handle to improve batching - extracted_shapes.sort_unstable_by(|a, b| { - match a - .transform - .translation() - .z - .partial_cmp(&b.transform.translation().z) - { - Some(Ordering::Equal) | None => { - (&a.sdf_shader, &a.fill_shader).cmp(&(&b.sdf_shader, &b.fill_shader)) - } - Some(other) => other, - } - }); + for (mut transparent_phase, visible_entities, view) in &mut views { + // todo: bevy_sprite does some hdr stuff, should we? + // let mut view_key = SpritePipelineKey::from_hdr(view.hdr) | msaa_key; let mesh_key = PipelineKey::from_msaa_samples(msaa.samples()) | PipelineKey::from_primitive_topology(PrimitiveTopology::TriangleStrip); - // Impossible starting values that will be replaced on the first iteration - let mut current_batch = ShapeBatch { - shader: ( - HandleId::Id(Uuid::nil(), u64::MAX), - HandleId::Id(Uuid::nil(), u64::MAX), - ), - }; - let mut current_batch_entity = Entity::from_raw(u32::MAX); - let mut current_batch_pipeline = CachedRenderPipelineId::INVALID; - - // Add a phase item for each shape, and detect when successive items can be batched. - // Spawn an entity with a `ShapeBatch` component for each possible batch. - // Compatible items share the same entity. - // Batches are merged later (in `batch_phase_system()`), so that they can be interrupted - // by any other phase item (and they can interrupt other items from batching). - for extracted_shape in extracted_shapes.iter() { - let new_batch = ShapeBatch { - shader: ( - extracted_shape.sdf_shader.id(), - extracted_shape.fill_shader.id(), - ), - }; + view_entities.clear(); + view_entities.extend(visible_entities.entities.iter().map(|e| e.index() as usize)); - if new_batch != current_batch { - current_batch_entity = commands.spawn(current_batch).id(); + transparent_phase + .items + .reserve(extracted_shapes.shapes.len()); - current_batch = new_batch; + for (entity, extracted_shape) in extracted_shapes.shapes.iter() { + let shader = ( + extracted_shape.sdf_shader.id(), + extracted_shape.fill_shader.id(), + ); - if let Some(_shader) = smud_pipeline.shaders.0.get(¤t_batch.shader) { - // todo pass the shader into specialize - let specialize_key = SmudPipelineKey { - mesh: mesh_key, - shader: current_batch.shader, - hdr: view.hdr, - }; - current_batch_pipeline = - pipelines.specialize(&pipeline_cache, &smud_pipeline, specialize_key); - } + let mut pipeline = CachedRenderPipelineId::INVALID; + + if let Some(_shader) = smud_pipeline.shaders.0.get(&shader) { + // todo pass the shader into specialize + let specialize_key = SmudPipelineKey { + mesh: mesh_key, + shader, + hdr: view.hdr, + }; + pipeline = pipelines.specialize(&pipeline_cache, &smud_pipeline, specialize_key); } - if current_batch_pipeline == CachedRenderPipelineId::INVALID { + if pipeline == CachedRenderPipelineId::INVALID { debug!("Shape not ready yet, skipping"); continue; // skip shapes that are not ready yet } - // let color = extracted_shape.color.as_linear_rgba_f32(); - // // encode color as a single u32 to save space - // let color = (color[0] * 255.0) as u32 - // | ((color[1] * 255.0) as u32) << 8 - // | ((color[2] * 255.0) as u32) << 16 - // | ((color[3] * 255.0) as u32) << 24; - - let color = extracted_shape.color.as_linear_rgba_f32(); - - let position = extracted_shape.transform.translation(); - let z = position.z; - let position = position.into(); - - let rotation_and_scale = extracted_shape - .transform - .affine() - .transform_vector3(Vec3::X) - .xy(); - - let scale = rotation_and_scale.length(); - let rotation = (rotation_and_scale / scale).into(); - - let vertex = ShapeVertex { - position, - color, - rotation, - scale, - frame: extracted_shape.frame, - }; - shape_meta.vertices.push(vertex); - - let item_start = index; - index += 1; - let item_end = index; + // These items will be sorted by depth with other phase items + let sort_key = FloatOrd(extracted_shape.transform.translation().z); + // Add the item to the render phase transparent_phase.add(Transparent2d { - entity: current_batch_entity, - draw_function: draw_smud_shape, - pipeline: current_batch_pipeline, - sort_key: FloatOrd(z), - batch_range: Some(item_start..item_end), + draw_function: draw_smud_shape_function, + pipeline, + entity: *entity, + sort_key, + // batch_range and dynamic_offset will be calculated in prepare_shapes + batch_range: 0..0, + dynamic_offset: None, }); } } +} - shape_meta - .vertices - .write_buffer(&render_device, &render_queue); +fn prepare_shapes( + mut commands: Commands, + mut previous_len: Local, + render_device: Res, + render_queue: Res, + mut shape_meta: ResMut, + view_uniforms: Res, + smud_pipeline: Res, + extracted_shapes: Res, + mut phases: Query<&mut RenderPhase>, + globals_buffer: Res, +) { + let globals = globals_buffer.buffer.binding().unwrap(); // todo if-let + + if let Some(view_binding) = view_uniforms.uniforms.binding() { + let mut batches: Vec<(Entity, ShapeBatch)> = Vec::with_capacity(*previous_len); + + // Clear the vertex buffer + shape_meta.vertices.clear(); + + shape_meta.view_bind_group = Some(render_device.create_bind_group( + "smud_shape_view_bind_group", + &smud_pipeline.view_layout, + &BindGroupEntries::sequential((view_binding, globals.clone())), + )); + + // Vertex buffer index + let mut index = 0; + + for mut transparent_phase in &mut phases { + let mut batch_item_index = 0; + // let mut batch_image_size = Vec2::ZERO; + // let mut batch_image_handle = AssetId::invalid(); + let mut batch_shader_handles = (AssetId::invalid(), AssetId::invalid()); + + // Iterate through the phase items and detect when successive shapes that can be batched. + // Spawn an entity with a `ShapeBatch` component for each possible batch. + // Compatible items share the same entity. + for item_index in 0..transparent_phase.items.len() { + let item = &transparent_phase.items[item_index]; + let Some(extracted_shape) = extracted_shapes.shapes.get(&item.entity) else { + // If there is a phase item that is not a shape, then we must start a new + // batch to draw the other phase item(s) and to respect draw order. This can be + // done by invalidating the batch_shader_handles + batch_shader_handles = (AssetId::invalid(), AssetId::invalid()); + continue; + }; + + let shader_handles = ( + extracted_shape.sdf_shader.id(), + extracted_shape.fill_shader.id(), + ); + + let batch_shader_changed = batch_shader_handles != shader_handles; + + let color = extracted_shape.color.as_linear_rgba_f32(); + + let position = extracted_shape.transform.translation(); + let position = position.into(); + + let rotation_and_scale = extracted_shape + .transform + .affine() + .transform_vector3(Vec3::X) + .xy(); + + let scale = rotation_and_scale.length(); + let rotation = (rotation_and_scale / scale).into(); + + let vertex = ShapeVertex { + position, + color, + rotation, + scale, + frame: extracted_shape.frame, + }; + shape_meta.vertices.push(vertex); + + if batch_shader_changed { + batch_item_index = item_index; + + batches.push(( + item.entity, + ShapeBatch { + shader: shader_handles, + range: index..index, + }, + )); + } + + transparent_phase.items[batch_item_index] + .batch_range_mut() + .end += 1; + + batches.last_mut().unwrap().1.range.end += 1; + index += 1; + } + } + + shape_meta + .vertices + .write_buffer(&render_device, &render_queue); + + *previous_len = batches.len(); + commands.insert_or_spawn_batch(batches); + } } #[repr(C)] @@ -662,7 +681,8 @@ impl Default for ShapeMeta { } } -#[derive(Component, Eq, PartialEq, Copy, Clone)] +#[derive(Component, Eq, PartialEq, Clone)] pub(crate) struct ShapeBatch { - shader: (HandleId, HandleId), + shader: (AssetId, AssetId), + range: Range, } diff --git a/src/sdf_assets.rs b/src/sdf_assets.rs index 81dc32d..c865c1f 100644 --- a/src/sdf_assets.rs +++ b/src/sdf_assets.rs @@ -1,4 +1,6 @@ -use bevy::{prelude::*, utils::Uuid}; +use bevy::prelude::*; + +use crate::util::generate_shader_id; /// Extension trait for Assets for conveniently creating new shaders from code pub trait SdfAssets { @@ -15,7 +17,7 @@ pub trait SdfAssets { impl SdfAssets for Assets { fn add_sdf_body>(&mut self, sdf: T) -> Handle { let body = sdf.into(); - let id = Uuid::new_v4(); + let id = generate_shader_id(); let shader = Shader::from_wgsl( format!( r#" @@ -35,7 +37,7 @@ fn sdf(p: vec2) -> f32 {{ fn add_fill_body>(&mut self, fill: T) -> Handle { let body = fill.into(); - let id = Uuid::new_v4(); + let id = generate_shader_id(); let shader = Shader::from_wgsl( format!( r#" diff --git a/src/shader_loading.rs b/src/shader_loading.rs index 8d7ff26..fa7052b 100644 --- a/src/shader_loading.rs +++ b/src/shader_loading.rs @@ -1,75 +1,72 @@ -use bevy::{prelude::*, reflect::TypeUuid}; +use bevy::{asset::load_internal_asset, prelude::*}; -const PRELUDE_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 11291576006157771079); -const PRELUDE_SHADER_IMPORT: &str = "smud::prelude"; +const PRELUDE_SHADER_HANDLE: Handle = Handle::weak_from_u128(11291576006157771079); -const SMUD_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 10055894596049459186); -const SMUD_SHADER_IMPORT: &str = "smud"; +const SMUD_SHADER_HANDLE: Handle = Handle::weak_from_u128(10055894596049459186); -const VIEW_BINDINGS_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 11792080578571156967); -const VIEW_BINDINGS_SHADER_IMPORT: &str = "smud::view_bindings"; +const VIEW_BINDINGS_SHADER_HANDLE: Handle = Handle::weak_from_u128(11792080578571156967); -pub const VERTEX_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 16846632126033267571); -const VERTEX_SHADER_IMPORT: &str = "smud::vertex"; +pub const VERTEX_SHADER_HANDLE: Handle = Handle::weak_from_u128(16846632126033267571); -pub const FRAGMENT_SHADER_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 10370213491934870425); -const FRAGMENT_SHADER_IMPORT: &str = "smud::fragment"; +pub const FRAGMENT_SHADER_HANDLE: Handle = Handle::weak_from_u128(10370213491934870425); /// The default fill used by `SmudShape` -pub const DEFAULT_FILL_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 18184663565780163454); -const DEFAULT_FILL_IMPORT: &str = "smud::default_fill"; +pub const DEFAULT_FILL_HANDLE: Handle = Handle::weak_from_u128(18184663565780163454); /// Simple single-colored filled fill -pub const SIMPLE_FILL_HANDLE: HandleUntyped = - HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 16286090377316294491); -const SIMPLE_FILL_IMPORT: &str = "smud::simple_fill"; +pub const SIMPLE_FILL_HANDLE: Handle = Handle::weak_from_u128(16286090377316294491); pub struct ShaderLoadingPlugin; impl Plugin for ShaderLoadingPlugin { fn build(&self, app: &mut App) { - let mut shaders = app.world.get_resource_mut::>().unwrap(); - - let prelude = Shader::from_wgsl(include_str!("../assets/prelude.wgsl"), "prelude.wgsl") - .with_import_path(PRELUDE_SHADER_IMPORT); - shaders.set_untracked(PRELUDE_SHADER_HANDLE, prelude); - - let smud = Shader::from_wgsl(include_str!("../assets/smud.wgsl"), "smud.wgsl") - .with_import_path(SMUD_SHADER_IMPORT); - shaders.set_untracked(SMUD_SHADER_HANDLE, smud); - - let view_bindings = Shader::from_wgsl( - include_str!("../assets/view_bindings.wgsl"), - "view_bindings.wgsl", - ) - .with_import_path(VIEW_BINDINGS_SHADER_IMPORT); - shaders.set_untracked(VIEW_BINDINGS_SHADER_HANDLE, view_bindings); - - let vertex = Shader::from_wgsl(include_str!("../assets/vertex.wgsl"), "vertex.wgsl") - .with_import_path(VERTEX_SHADER_IMPORT); - shaders.set_untracked(VERTEX_SHADER_HANDLE, vertex); - - let fragment = Shader::from_wgsl(include_str!("../assets/fragment.wgsl"), "fragment.wgsl") - .with_import_path(FRAGMENT_SHADER_IMPORT); - shaders.set_untracked(FRAGMENT_SHADER_HANDLE, fragment); - - let mut shaders = app.world.get_resource_mut::>().unwrap(); - let fill = Shader::from_wgsl( - include_str!("../assets/fills/cubic_falloff.wgsl"), - "cubic_falloff.wgsl", - ) - .with_import_path(DEFAULT_FILL_IMPORT); - shaders.set_untracked(DEFAULT_FILL_HANDLE, fill); - - let simple_fill = - Shader::from_wgsl(include_str!("../assets/fills/simple.wgsl"), "simple.wgsl") - .with_import_path(SIMPLE_FILL_IMPORT); - shaders.set_untracked(SIMPLE_FILL_HANDLE, simple_fill); + load_internal_asset!( + app, + PRELUDE_SHADER_HANDLE, + "../assets/prelude.wgsl", + Shader::from_wgsl + ); + + load_internal_asset!( + app, + SMUD_SHADER_HANDLE, + "../assets/smud.wgsl", + Shader::from_wgsl + ); + + load_internal_asset!( + app, + VIEW_BINDINGS_SHADER_HANDLE, + "../assets/view_bindings.wgsl", + Shader::from_wgsl + ); + + load_internal_asset!( + app, + VERTEX_SHADER_HANDLE, + "../assets/vertex.wgsl", + Shader::from_wgsl + ); + + load_internal_asset!( + app, + FRAGMENT_SHADER_HANDLE, + "../assets/fragment.wgsl", + Shader::from_wgsl + ); + + load_internal_asset!( + app, + DEFAULT_FILL_HANDLE, + "../assets/fills/cubic_falloff.wgsl", + Shader::from_wgsl + ); + + load_internal_asset!( + app, + SIMPLE_FILL_HANDLE, + "../assets/fills/simple.wgsl", + Shader::from_wgsl + ); } } diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..f7509ed --- /dev/null +++ b/src/util.rs @@ -0,0 +1,5 @@ +use bevy::utils::Uuid; + +pub fn generate_shader_id() -> String { + Uuid::new_v4().to_string().replace("-", "_") +} From 2c3df2b0fe6c50d2c425b549f10b616a0311d9b8 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 03:41:48 +0100 Subject: [PATCH 3/8] Fix shader import style warnings --- assets/fragment.wgsl | 4 ++-- assets/star_bevy.wgsl | 2 +- assets/view_bindings.wgsl | 4 ++-- src/lib.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/fragment.wgsl b/assets/fragment.wgsl index 3736db2..b3702a4 100644 --- a/assets/fragment.wgsl +++ b/assets/fragment.wgsl @@ -1,7 +1,7 @@ #define_import_path smud::fragment -#import smud::sdf as sdf -#import smud::fill as fill +#import smud::sdf +#import smud::fill struct FragmentInput { @location(0) color: vec4, diff --git a/assets/star_bevy.wgsl b/assets/star_bevy.wgsl index d14f43d..c446353 100644 --- a/assets/star_bevy.wgsl +++ b/assets/star_bevy.wgsl @@ -1,7 +1,7 @@ #define_import_path smud::star_bevy #import smud -#import smud::view_bindings globals +#import smud::view_bindings::globals fn bevy_head(p: vec2) -> f32 { let skull = smud::sd_ellipse(p, 0.22, 0.20); diff --git a/assets/view_bindings.wgsl b/assets/view_bindings.wgsl index 5047a6d..2c79f91 100644 --- a/assets/view_bindings.wgsl +++ b/assets/view_bindings.wgsl @@ -1,7 +1,7 @@ #define_import_path smud::view_bindings -#import bevy_render::view View -#import bevy_render::globals Globals +#import bevy_render::view::View +#import bevy_render::globals::Globals @group(0) @binding(0) var view: View; diff --git a/src/lib.rs b/src/lib.rs index c17238f..5bcff0f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -354,7 +354,7 @@ fn extract_sdf_shaders(mut main_world: ResMut, mut pipeline: ResMut globals: Globals; #import {sdf_import_path} as sdf From dc9537de83d33d415b38c8e97dd845d0e229236d Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 03:35:52 +0100 Subject: [PATCH 4/8] chore: Bump version --- Cargo.toml | 2 +- README.md | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bca0de8..c7beaa1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ keywords = ["gamedev", "bevy", "sdf"] license = "MIT OR Apache-2.0" name = "bevy_smud" repository = "https://github.com/johanhelsing/bevy_smud" -version = "0.6.0" +version = "0.7.0" [dependencies] bevy = { version = "0.12", default-features = false, features = [ diff --git a/README.md b/README.md index f5574cf..45145dd 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,10 @@ If you want something more finished, you should probably check out [bevy_prototy The `main` branch targets the latest bevy release. -I intend to support the `main` branch of Bevy in the `bevy-main` branch. - |bevy|bevy_smud| |----|---------| -|0.11|0.6, main| +|0.12|0.7, main| +|0.11|0.6 | |0.10|0.5 | |0.9 |0.4 | |0.8 |0.3 | From dfe5cc962c2d8953121f6c758590db1614122d1c Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 03:47:58 +0100 Subject: [PATCH 5/8] Clean up ci.yml --- .github/workflows/ci.yml | 57 +++++++++------------------------------- 1 file changed, 13 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e312ecd..8c159ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,59 +8,28 @@ name: ci jobs: check: - name: Check runs-on: ubuntu-latest steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install stable toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - - name: Rust Cache - uses: Swatinem/rust-cache@v2 - - - name: Run cargo check - run: cargo check + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo check test: - name: Test Suite runs-on: ubuntu-latest steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install stable toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - - name: Rust Cache - uses: Swatinem/rust-cache@v2 - - - name: Run cargo test - run: cargo test + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo test lints: - name: Lints runs-on: ubuntu-latest steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install stable toolchain - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable components: rustfmt, clippy - - - name: Rust Cache - uses: Swatinem/rust-cache@v2 - - - name: Run cargo fmt - run: cargo fmt --all -- --check - - - name: Run cargo clippy - run: cargo clippy -- -D warnings \ No newline at end of file + - uses: Swatinem/rust-cache@v2 + - run: cargo fmt --all -- --check + - run: cargo clippy -- -D warnings \ No newline at end of file From 3bc7d51f7600bcd579cdc3fafe2994e8c51fc279 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 03:48:33 +0100 Subject: [PATCH 6/8] ci: use checkout v4 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c159ae..ff3f851 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo check @@ -18,7 +18,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo test @@ -26,7 +26,7 @@ jobs: lints: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy From 8279aeb81bca3229ca70a109f6e0b64ce7c3c6bb Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 03:51:39 +0100 Subject: [PATCH 7/8] Fix regression during port to bevy 0.12 --- src/lib.rs | 4 +--- src/util.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5bcff0f..dc3968c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -372,9 +372,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 {{ }} "# ), - // format!("smud::generated::{shader_key:?}"), - // TODO - format!("smud::generated::bogus_key"), + format!("smud::generated::{shader_key:?}"), ); // todo does this work, or is it too late? diff --git a/src/util.rs b/src/util.rs index f7509ed..c81992a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,5 @@ use bevy::utils::Uuid; pub fn generate_shader_id() -> String { - Uuid::new_v4().to_string().replace("-", "_") + Uuid::new_v4().to_string().replace('-', "_") } From 68305220c7bc743e14618548b3d60a8626a40b8b Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 19 Nov 2023 03:54:43 +0100 Subject: [PATCH 8/8] Fix doc error --- README.md | 5 ++--- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 45145dd..37398bd 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,8 @@ use bevy_smud::prelude::*; fn main() { App::new() - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin)) + .add_systems(Startup, setup) .run(); } diff --git a/src/lib.rs b/src/lib.rs index dc3968c..68d8797 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ impl Plugin for SmudPlugin { fn build(&self, app: &mut App) { // All the messy boiler-plate for loading a bunch of shaders app.add_plugins(ShaderLoadingPlugin); - // app.add_plugin(UiShapePlugin); + // app.add_plugins(UiShapePlugin); if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app