diff --git a/Cargo.toml b/Cargo.toml index 97e19da..d158308 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,27 +7,27 @@ keywords = ["gamedev", "bevy", "sdf"] license = "MIT OR Apache-2.0" name = "bevy_smud" repository = "https://github.com/johanhelsing/bevy_smud" -version = "0.5.0" +version = "0.6.0" [dependencies] -bevy = {version = "0.10", default-features = false, features = [ +bevy = { version = "0.11", default-features = false, features = [ "bevy_core_pipeline", "bevy_render", "bevy_asset", # needed for handle ids ]} bytemuck = { version = "1.7", features = ["derive"] } copyless = "0.1" -bitflags = "1.3" +bitflags = "2.4" [dev-dependencies] -bevy = {version = "0.10", default-features = false, features = [ +bevy = {version = "0.11", 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.15" -bevy_lospec = "0.4" -bevy_pancam = "0.8" +bevy_asset_loader = "0.17" +bevy_lospec = "0.5" +bevy_pancam = "0.9" rand = "0.8" [profile.dev] diff --git a/README.md b/README.md index fffed18..f5574cf 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ fn setup( Make sure you reuse the shaders, i.e. don't call `add_sdf_expr` every frame. -You can also define shapes in .wgsl files. Note that in order to use the built-in shapes, you have to import [`bevy_smud::shapes`](https://github.com/johanhelsing/bevy_smud/blob/main/assets/shapes.wgsl), and you must create a function named `sdf` that takes a `vec2` and returns `f32`. +You can also define shapes in .wgsl files. Note that in order to use the built-in shapes, you have to import [`smud`](https://github.com/johanhelsing/bevy_smud/blob/main/assets/smud.wgsl), and you must create a function named `sdf` that takes a `vec2` and returns `f32`. Other than that, make sure you understand how to combine shapes, use symmetries and change domains. For instance, the [bevy](https://github.com/johanhelsing/bevy_smud/blob/main/assets/bevy.wgsl) in the screenshot above is built up of several circles, ellipses, and a vesica for the beak. @@ -91,7 +91,8 @@ I intend to support the `main` branch of Bevy in the `bevy-main` branch. |bevy|bevy_smud| |----|---------| -|0.10|0.5, main| +|0.11|0.6, main| +|0.10|0.5 | |0.9 |0.4 | |0.8 |0.3 | |0.7 |0.2 | diff --git a/assets/bevy.wgsl b/assets/bevy.wgsl index cd03903..8b3bc74 100644 --- a/assets/bevy.wgsl +++ b/assets/bevy.wgsl @@ -1,9 +1,11 @@ -#import bevy_smud::shapes +#define_import_path smud::bevy + +#import smud fn bevy_head(p: vec2) -> f32 { - let skull = sd_ellipse(p, 0.22, 0.20); - let p_beak = sd_rotate_rad(p - vec2(0.12, 0.02), 1.2); - let beak = sd_vesica(p_beak, 0.3, 0.2); + let skull = smud::sd_ellipse(p, 0.22, 0.20); + let p_beak = smud::rotate_rad(p - vec2(0.12, 0.02), 1.2); + let beak = smud::sd_vesica(p_beak, 0.3, 0.2); return min(skull, beak); } @@ -13,13 +15,13 @@ fn sdf(p: vec2) -> f32 { let p_upper_wing = p - vec2(-0.3, -0.25); let upper_wing = max( - sd_ellipse(p_upper_wing, 0.7, 0.6), - -sd_rotate_rad(p, 0.40).y - 0.03 + smud::sd_ellipse(p_upper_wing, 0.7, 0.6), + -smud::rotate_rad(p, 0.40).y - 0.03 // -sd_circle(p_upper_wing - vec2(-0.35, -0.05), 0.6) ); let p_lower_wing = p - vec2(-0.3, -0.35); let lower_wing = max( - sd_ellipse(p_lower_wing, 0.7, 0.5), + smud::sd_ellipse(p_lower_wing, 0.7, 0.5), -p.y - 0.5 ); @@ -30,25 +32,25 @@ fn sdf(p: vec2) -> f32 { let head = bevy_head(p - vec2(0.18, 0.40)); - let chest = sd_smooth_intersect( - sd_ellipse(p - vec2(-0.8, -0.05), 1.3, 0.7), + let chest = smud::op_smooth_intersect( + smud::sd_ellipse(p - vec2(-0.8, -0.05), 1.3, 0.7), max(-chest_clip, -tail_clip), 0.04 // -sd_ellipse(p - vec2(-0.8, 0.15), 0.9, 0.8) ); - let tail_wing_hole = sd_ellipse(sd_rotate_rad(p -vec2(-0.8, -0.4), -0.1), 0.63, 0.25); + let tail_wing_hole = smud::sd_ellipse(smud::rotate_rad(p -vec2(-0.8, -0.4), -0.1), 0.63, 0.25); - let chest_head = sd_smooth_union(chest, head, 0.07); - let chest_head_tail = sd_smooth_subtract(tail_wing_hole, chest_head, 0.07); + let chest_head = smud::op_smooth_union(chest, head, 0.07); + let chest_head_tail = smud::op_smooth_subtract(tail_wing_hole, chest_head, 0.07); - let body = sd_smooth_union( + let body = smud::op_smooth_union( chest_head_tail, max(wings, -tail_wing_hole + 0.01), 0.01 ); - let eye = sd_circle(p - vec2(0.20, 0.45), 0.05); + let eye = smud::sd_circle(p - vec2(0.20, 0.45), 0.05); let bevy = max(body, -eye); return bevy * scale; diff --git a/assets/fills/cubic_falloff.wgsl b/assets/fills/cubic_falloff.wgsl index 7f009ce..8b3dc62 100644 --- a/assets/fills/cubic_falloff.wgsl +++ b/assets/fills/cubic_falloff.wgsl @@ -1,3 +1,5 @@ +#define_import_path smud::default_fill + fn fill(d: f32, color: vec4) -> vec4 { let d2 = 1. - (d * 0.13); let alpha = clamp(d2 * d2 * d2, 0., 1.) * color.a; diff --git a/assets/fills/outline.wgsl b/assets/fills/outline.wgsl index 836600e..c6c69ed 100644 --- a/assets/fills/outline.wgsl +++ b/assets/fills/outline.wgsl @@ -1,5 +1,9 @@ +#define_import_path smud::outline + +#import smud + fn fill(d: f32, color: vec4) -> vec4 { let d_2 = abs(d - 1.) - 1.; - let a = sd_fill_alpha_fwidth(d_2); + let a = smud::sd_fill_alpha_fwidth(d_2); return vec4(color.rgb, a * color.a); } \ No newline at end of file diff --git a/assets/fills/simple.wgsl b/assets/fills/simple.wgsl index c8ac6ae..10a384d 100644 --- a/assets/fills/simple.wgsl +++ b/assets/fills/simple.wgsl @@ -1,4 +1,8 @@ +#define_import_path smud::simple_fill + +#import smud + fn fill(d: f32, color: vec4) -> vec4 { - let a = sd_fill_alpha_fwidth(d); + let a = smud::sd_fill_alpha_fwidth(d); return vec4(color.rgb, a * color.a); } \ No newline at end of file diff --git a/assets/fragment.wgsl b/assets/fragment.wgsl index 34e0cc5..3736db2 100644 --- a/assets/fragment.wgsl +++ b/assets/fragment.wgsl @@ -1,3 +1,8 @@ +#define_import_path smud::fragment + +#import smud::sdf as sdf +#import smud::fill as fill + struct FragmentInput { @location(0) color: vec4, @location(1) pos: vec2, @@ -5,6 +10,6 @@ struct FragmentInput { @fragment fn fragment(in: FragmentInput) -> @location(0) vec4 { - let d = sdf(in.pos); - return fill(d, in.color); + let d = sdf::sdf(in.pos); + return fill::fill(d, in.color); } \ No newline at end of file diff --git a/assets/gallery/blobby_cross.wgsl b/assets/gallery/blobby_cross.wgsl index 4369fb4..783612b 100644 --- a/assets/gallery/blobby_cross.wgsl +++ b/assets/gallery/blobby_cross.wgsl @@ -1,6 +1,8 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::blobby_cross + +#import smud fn sdf(p: vec2) -> f32 { let s = 20.; - return (sd_blobby_cross(p / s, 0.7) * s) - 4.; + return (smud::sd_blobby_cross(p / s, 0.7) * s) - 4.; } \ No newline at end of file diff --git a/assets/gallery/box.wgsl b/assets/gallery/box.wgsl index 2fa5886..216af01 100644 --- a/assets/gallery/box.wgsl +++ b/assets/gallery/box.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::box + +#import smud fn sdf(p: vec2) -> f32 { - return sd_box(p, vec2(30., 20.)); + return smud::sd_box(p, vec2(30., 20.)); } \ No newline at end of file diff --git a/assets/gallery/circle.wgsl b/assets/gallery/circle.wgsl index 84e84ab..fd8cb3d 100644 --- a/assets/gallery/circle.wgsl +++ b/assets/gallery/circle.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::circle + +#import smud fn sdf(p: vec2) -> f32 { - return sd_circle(p, 25.); + return smud::sd_circle(p, 25.); } \ No newline at end of file diff --git a/assets/gallery/donut.wgsl b/assets/gallery/donut.wgsl index a89dead..a7566ee 100644 --- a/assets/gallery/donut.wgsl +++ b/assets/gallery/donut.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::donut + +#import smud fn sdf(p: vec2) -> f32 { - return abs(sd_circle(p, 18.)) - 3.; + return abs(smud::sd_circle(p, 18.)) - 3.; } \ No newline at end of file diff --git a/assets/gallery/egg.wgsl b/assets/gallery/egg.wgsl index 63d8f90..0dfac92 100644 --- a/assets/gallery/egg.wgsl +++ b/assets/gallery/egg.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::egg + +#import smud fn sdf(p: vec2) -> f32 { - return sd_egg(p, 25., 10.); + return smud::sd_egg(p, 25., 10.); } \ No newline at end of file diff --git a/assets/gallery/ellipse.wgsl b/assets/gallery/ellipse.wgsl index 20dd109..20021f4 100644 --- a/assets/gallery/ellipse.wgsl +++ b/assets/gallery/ellipse.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::ellipse + +#import smud fn sdf(p: vec2) -> f32 { - return sd_ellipse(p, 25., 15.); + return smud::sd_ellipse(p, 25., 15.); } \ No newline at end of file diff --git a/assets/gallery/heart.wgsl b/assets/gallery/heart.wgsl index 1395875..8e01615 100644 --- a/assets/gallery/heart.wgsl +++ b/assets/gallery/heart.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::heart + +#import smud fn sdf(p: vec2) -> f32 { - return sd_heart((p / 40.) - vec2(0., -0.5)) * 40.; + return smud::sd_heart((p / 40.) - vec2(0., -0.5)) * 40.; } \ No newline at end of file diff --git a/assets/gallery/hexagon.wgsl b/assets/gallery/hexagon.wgsl index 3281f3e..5429dd7 100644 --- a/assets/gallery/hexagon.wgsl +++ b/assets/gallery/hexagon.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::hexagon + +#import smud fn sdf(p: vec2) -> f32 { - return sd_hexagon(p, 20.); + return smud::sd_hexagon(p, 20.); } \ No newline at end of file diff --git a/assets/gallery/horseshoe.wgsl b/assets/gallery/horseshoe.wgsl index 67f353e..2a6dfc5 100644 --- a/assets/gallery/horseshoe.wgsl +++ b/assets/gallery/horseshoe.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::horseshoe + +#import smud fn sdf(p: vec2) -> f32 { - return sd_horseshoe(p, sin_cos(0.4), 17., vec2(6., 4.)); + return smud::sd_horseshoe(p, smud::sin_cos(0.4), 17., vec2(6., 4.)); } \ No newline at end of file diff --git a/assets/gallery/moon.wgsl b/assets/gallery/moon.wgsl index 0ae581e..40b802b 100644 --- a/assets/gallery/moon.wgsl +++ b/assets/gallery/moon.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::moon + +#import smud fn sdf(p: vec2) -> f32 { - return sd_moon(p, 10., 25., 20.); + return smud::sd_moon(p, 10., 25., 20.); } \ No newline at end of file diff --git a/assets/gallery/pie.wgsl b/assets/gallery/pie.wgsl index 633d494..2202918 100644 --- a/assets/gallery/pie.wgsl +++ b/assets/gallery/pie.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::pie + +#import smud fn sdf(p: vec2) -> f32 { - return sd_pie(p, sin_cos(0.8), 25.); + return smud::sd_pie(p, smud::sin_cos(0.8), 25.); } \ No newline at end of file diff --git a/assets/gallery/rounded_x.wgsl b/assets/gallery/rounded_x.wgsl index ec1bf60..d7a77f4 100644 --- a/assets/gallery/rounded_x.wgsl +++ b/assets/gallery/rounded_x.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::horseshoe + +#import smud fn sdf(p: vec2) -> f32 { - return sd_rounded_x(p, 30., 4.); + return smud::sd_rounded_x(p, 30., 4.); } \ No newline at end of file diff --git a/assets/gallery/segment.wgsl b/assets/gallery/segment.wgsl index b2d6321..662f722 100644 --- a/assets/gallery/segment.wgsl +++ b/assets/gallery/segment.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::segment + +#import smud fn sdf(p: vec2) -> f32 { - return sd_segment(p, vec2(-13.), vec2(13.)) - 3.; + return smud::sd_segment(p, vec2(-13.), vec2(13.)) - 3.; } \ No newline at end of file diff --git a/assets/gallery/stairs.wgsl b/assets/gallery/stairs.wgsl index ef95684..1ac2cbf 100644 --- a/assets/gallery/stairs.wgsl +++ b/assets/gallery/stairs.wgsl @@ -1,7 +1,9 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::stairs + +#import smud fn sdf(p: vec2) -> f32 { let s = 5.; let p = p - vec2(-20.); - return sd_stairs(p / s, vec2(1.), 8.) * s; + return smud::sd_stairs(p / s, vec2(1.), 8.) * s; } \ No newline at end of file diff --git a/assets/gallery/star_4.wgsl b/assets/gallery/star_4.wgsl index cffeff1..ab9e359 100644 --- a/assets/gallery/star_4.wgsl +++ b/assets/gallery/star_4.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::star_4 + +#import smud fn sdf(p: vec2) -> f32 { - return sd_star(p * 0.5, 10., 4, 3.0); + return smud::sd_star(p * 0.5, 10., 4, 3.0); } \ No newline at end of file diff --git a/assets/gallery/star_5.wgsl b/assets/gallery/star_5.wgsl index 4221999..a7e2299 100644 --- a/assets/gallery/star_5.wgsl +++ b/assets/gallery/star_5.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::star_5 + +#import smud fn sdf(p: vec2) -> f32 { - return sd_star_5(p, 10., 2.); + return smud::sd_star_5_(p, 10., 2.); } \ No newline at end of file diff --git a/assets/gallery/triangle.wgsl b/assets/gallery/triangle.wgsl index 06395d8..46d788e 100644 --- a/assets/gallery/triangle.wgsl +++ b/assets/gallery/triangle.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::triangle + +#import smud fn sdf(p: vec2) -> f32 { - return sd_equilateral_triangle(p, 20.); + return smud::sd_equilateral_triangle(p, 20.); } \ No newline at end of file diff --git a/assets/gallery/vesica.wgsl b/assets/gallery/vesica.wgsl index c282f55..3cf2eca 100644 --- a/assets/gallery/vesica.wgsl +++ b/assets/gallery/vesica.wgsl @@ -1,5 +1,7 @@ -#import bevy_smud::shapes +#define_import_path smud::gallery::vesica + +#import smud fn sdf(p: vec2) -> f32 { - return sd_vesica(p, 30., 15.); + return smud::sd_vesica(p, 30., 15.); } \ No newline at end of file diff --git a/assets/prelude.wgsl b/assets/prelude.wgsl index 88184cb..ebaf9c5 100644 --- a/assets/prelude.wgsl +++ b/assets/prelude.wgsl @@ -1,5 +1,7 @@ -type float4 = vec4; -type float3 = vec3; -type float = f32; +#define_import_path smud::prelude + +alias float4 = vec4; +alias float3 = vec3; +alias float = f32; const PI: f32 = 3.141592653589793; \ No newline at end of file diff --git a/assets/shapes.wgsl b/assets/smud.wgsl similarity index 90% rename from assets/shapes.wgsl rename to assets/smud.wgsl index fb78c80..997e791 100644 --- a/assets/shapes.wgsl +++ b/assets/smud.wgsl @@ -1,3 +1,4 @@ +#define_import_path smud // Most of these are ported versions of the ones on Inigo Quilez website, https://iquilezles.org fn sd_circle(p: vec2, r: f32) -> f32 { @@ -44,7 +45,7 @@ fn ndot(a: vec2, b: vec2) -> f32 { return a.x * b.x - a.y * b.y; } -fn dot2(a: vec2) -> f32 { +fn dot2_(a: vec2) -> f32 { return dot(a, a); } @@ -62,9 +63,9 @@ fn sd_trapezoid(p: vec2, r1: f32, r2: f32, he: f32) -> f32 { 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.); + let cb = p - k1 + k2 * clamp(dot(k1 - p, k2) / dot2_(k2), 0., 1.); let s = select(1., -1., cb.x < 0. && ca.y < 0.); - return s * sqrt(min(dot2(ca), dot2(cb))); + return s * sqrt(min(dot2_(ca), dot2_(cb))); } fn sd_parallelogram(p: vec2, wi: f32, he: f32, sk: f32) -> f32 { @@ -175,7 +176,7 @@ fn sd_hexagram(p: vec2, r: f32) -> f32 { return length(p) * sign(p.y); } -fn sd_star_5(p: vec2, r: f32, rf: f32) -> f32 { +fn sd_star_5_(p: vec2, r: f32, rf: f32) -> f32 { let k1 = vec2(0.809016994375, -0.587785252292); let k2 = vec2(-k1.x, k1.y); var p = p; @@ -275,10 +276,10 @@ fn sd_rounded_cross(p: vec2, h: f32) -> f32 { var p = abs(p); return select( sqrt(min( - dot2(p - vec2(0., h)), - dot2(p - vec2(1., 0.)) + dot2_(p - vec2(0., h)), + dot2_(p - vec2(1., 0.)) )), - k - sqrt(dot2(p - vec2(1., k))), + k - sqrt(dot2_(p - vec2(1., k))), p.x < 1. && p.y < p.x * (k - h) + h ); } @@ -304,12 +305,12 @@ fn sd_heart(p: vec2) -> f32 { p.x = abs(p.x); if (p.y + p.x > 1.) { - return sqrt(dot2(p - vec2(0.25, 0.75))) - sqrt(2.) / 4.; + return sqrt(dot2_(p - vec2(0.25, 0.75))) - sqrt(2.) / 4.; } return sqrt(min( - dot2(p - vec2(0., 1.)), - dot2(p - 0.5 * max(p.x + p.y, 0.)) + dot2_(p - vec2(0., 1.)), + dot2_(p - 0.5 * max(p.x + p.y, 0.)) )) * sign(p.x - p.y); } @@ -445,7 +446,7 @@ fn sd_bezier(pos: vec2, A: vec2, B: vec2, C: vec2) -> f32 { let x = (vec2(h, -h) - q) / 2.; let uv = sign(x) * pow(abs(x), vec2(1. / 3.)); let t = clamp(uv.x + uv.y - kx, 0., 1.); - res = dot2(d + (c + b * t) * t); + res = dot2_(d + (c + b * t) * t); } else { @@ -456,8 +457,8 @@ fn sd_bezier(pos: vec2, A: vec2, B: vec2, C: vec2) -> f32 { let u = vec3(m + m, -n - m, n - m) * z - vec3(kx); let t = clamp(u, vec3(0.), vec3(1.)); res = min( - dot2(d + (c + b * t.x) * t.x), - dot2(d + (c + b * t.y) * t.y) + dot2_(d + (c + b * t.x) * t.x), + dot2_(d + (c + b * t.y) * t.y) ); // the third root cannot be the closest // res = min(res, dot2(d+(c+b*t.z)*t.z)); @@ -494,9 +495,9 @@ fn sd_tunnel(p: vec2, wh: vec2) -> f32 { let p = vec2(abs(p.x), -p.y); var q = p - wh; - let d1 = dot2(vec2(max(q.x, 0.), q.y)); + let d1 = dot2_(vec2(max(q.x, 0.), q.y)); q.x = select(length(p) - wh.x, q.x, p.y > 0.); - let d2 = dot2(vec2(q.x, max(q.y, 0.))); + let d2 = dot2_(vec2(q.x, max(q.y, 0.))); let d = sqrt(min(d1, d2)); return select(d, -d, max(q.x, q.y) < 0.); @@ -505,8 +506,8 @@ fn sd_tunnel(p: vec2, wh: vec2) -> f32 { fn sd_stairs(p: vec2, wh: vec2, n: f32) -> f32 { let ba = wh * n; var d = min( - dot2(p - vec2(clamp(p.x, 0., ba.x), 0.)), - dot2(p - vec2(ba.x, clamp(p.y, 0., ba.y))) + dot2_(p - vec2(clamp(p.x, 0., ba.x), 0.)), + dot2_(p - vec2(ba.x, clamp(p.y, 0., ba.y))) ); var s = sign(max(-p.y, p.x - ba.x)); @@ -522,8 +523,8 @@ fn sd_stairs(p: vec2, wh: vec2, n: f32) -> f32 { s = 1.; } p = select(-p, p, id < 0.5 || p.x > 0.); - d = min(d, dot2(p - vec2(0., clamp(p.y, -hh, hh)))); - d = min(d, dot2(p - vec2(clamp(p.x, 0., wh.x), hh))); + d = min(d, dot2_(p - vec2(0., clamp(p.y, -hh, hh)))); + d = min(d, dot2_(p - vec2(clamp(p.x, 0., wh.x), hh))); return sqrt(d) * s; } @@ -554,18 +555,18 @@ fn sd_moon(p: vec2, d: f32, ra: f32, rb: f32) -> f32 { ); } -fn sd_renormalize_uv(uv: vec2) -> vec2 { +fn renormalize_uv(uv: vec2) -> vec2 { return uv * 2. - vec2(1., 1.); } -fn sd_exponential_falloff(d: f32, size: f32, power: f32) -> f32 { +fn exponential_falloff(d: f32, size: f32, power: f32) -> f32 { var a = (size - d) / size; a = clamp(a, 0.0, 1.0); a = pow(a, power); return a; } -fn sd_exponential_falloff_3(d: f32, size: f32) -> f32 { +fn exponential_falloff_3_(d: f32, size: f32) -> f32 { var a = (size - d) / size; a = clamp(a, 0.0, 1.0); a = a * a * a; @@ -588,25 +589,25 @@ fn sd_fill_alpha_nearest(distance: f32) -> f32 { return step(-distance, 0.); } -fn sd_fill_with_falloff_3(d: f32, falloff_size: f32, falloff_color: vec4, fill_color: vec4) -> vec4 { +fn sd_fill_with_falloff_3_(d: f32, falloff_size: f32, falloff_color: vec4, fill_color: vec4) -> vec4 { // todo compose with others? let aaf = 0.7 / fwidth(d); // TODO: this could just be a uniform instead let t_color = clamp(d * aaf, 0.0, 1.0); var color = mix(fill_color, falloff_color, t_color); - let falloff = sd_exponential_falloff_3(d, falloff_size); + let falloff = exponential_falloff_3_(d, falloff_size); color.a = color.a * falloff; return color; } -fn sd_union(distance_1: f32, distance_2: f32) -> f32 { +fn op_union(distance_1: f32, distance_2: f32) -> f32 { return min(distance_1, distance_2); } -fn sd_subtract(distance_1: f32, distance_2: f32) -> f32 { +fn op_subtract(distance_1: f32, distance_2: f32) -> f32 { return max(-distance_1, distance_2); } -fn sd_intersect(distance_1: f32, distance_2: f32) -> f32 { +fn op_intersect(distance_1: f32, distance_2: f32) -> f32 { return max(distance_1, distance_2); } @@ -617,7 +618,7 @@ fn sin_cos(a: f32) -> vec2 { } // Rotation given sin cos vector -fn sd_rotate(p: vec2, sc: vec2) -> vec2 { +fn rotate(p: vec2, sc: vec2) -> vec2 { let s = sc.x; let c = sc.y; return vec2( @@ -626,28 +627,28 @@ fn sd_rotate(p: vec2, sc: vec2) -> vec2 { ); } -fn sd_rotate_rad(p: vec2, a: f32) -> vec2 { - return sd_rotate(p, sin_cos(a)); +fn rotate_rad(p: vec2, a: f32) -> vec2 { + return rotate(p, sin_cos(a)); } -fn sd_rotate_45(p: vec2) -> vec2 { +fn rotate_45_(p: vec2) -> vec2 { let c = 0.70710678118; // cos(pi / 4) == sin(pi / 4); let xc = p.x * c; let yc = p.y * c; return vec2(xc - yc, xc + yc); } -fn sd_smooth_subtract(d1: f32, d2: f32, k: f32) -> f32 { +fn op_smooth_subtract(d1: f32, d2: f32, k: f32) -> f32 { let h = clamp(0.5 - 0.5 * (d2 + d1) / k, 0., 1.); return mix(d2, -d1, h) + k * h * (1. - h); } -fn sd_smooth_union(d1: f32, d2: f32, k: f32) -> f32 { +fn op_smooth_union(d1: f32, d2: f32, k: f32) -> f32 { let h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0., 1.); return mix(d2, d1, h) - k * h * (1. - h); } -fn sd_smooth_intersect(d1: f32, d2: f32, k: f32) -> f32 { +fn op_smooth_intersect(d1: f32, d2: f32, k: f32) -> f32 { let h = clamp(0.5 - 0.5 * (d2 - d1) / k, 0., 1.); return mix(d2, d1, h) + k * h * (1. - h); } diff --git a/assets/star_bevy.wgsl b/assets/star_bevy.wgsl index 60d4f8c..48ae5d5 100644 --- a/assets/star_bevy.wgsl +++ b/assets/star_bevy.wgsl @@ -1,9 +1,12 @@ -#import bevy_smud::shapes +#define_import_path smud::star_bevy + +#import smud +#import smud::view_bindings globals fn bevy_head(p: vec2) -> f32 { - let skull = sd_ellipse(p, 0.22, 0.20); - let p_beak = sd_rotate_rad(p - vec2(0.12, 0.02), 1.2); - let beak = sd_vesica(p_beak, 0.3, 0.2); + let skull = smud::sd_ellipse(p, 0.22, 0.20); + let p_beak = smud::rotate_rad(p - vec2(0.12, 0.02), 1.2); + let beak = smud::sd_vesica(p_beak, 0.3, 0.2); return min(skull, beak); } @@ -13,13 +16,13 @@ fn bevy(p: vec2) -> f32 { let p_upper_wing = p - vec2(-0.3, -0.25); let upper_wing = max( - sd_ellipse(p_upper_wing, 0.7, 0.6), - -sd_rotate_rad(p, 0.40).y - 0.03 - // -sd_circle(p_upper_wing - vec2(-0.35, -0.05), 0.6) + smud::sd_ellipse(p_upper_wing, 0.7, 0.6), + -smud::rotate_rad(p, 0.40).y - 0.03 + // -smud::sd_circle(p_upper_wing - vec2(-0.35, -0.05), 0.6) ); let p_lower_wing = p - vec2(-0.3, -0.35); let lower_wing = max( - sd_ellipse(p_lower_wing, 0.7, 0.5), + smud::sd_ellipse(p_lower_wing, 0.7, 0.5), -p.y - 0.5 ); @@ -30,25 +33,25 @@ fn bevy(p: vec2) -> f32 { let head = bevy_head(p - vec2(0.18, 0.40)); - let chest = sd_smooth_intersect( - sd_ellipse(p - vec2(-0.8, -0.05), 1.3, 0.7), + let chest = smud::op_smooth_intersect( + smud::sd_ellipse(p - vec2(-0.8, -0.05), 1.3, 0.7), max(-chest_clip, -tail_clip), 0.04 // -sd_ellipse(p - vec2(-0.8, 0.15), 0.9, 0.8) ); - let tail_wing_hole = sd_ellipse(sd_rotate_rad(p -vec2(-0.8, -0.4), -0.1), 0.63, 0.25); + let tail_wing_hole = smud::sd_ellipse(smud::rotate_rad(p -vec2(-0.8, -0.4), -0.1), 0.63, 0.25); - let chest_head = sd_smooth_union(chest, head, 0.07); - let chest_head_tail = sd_smooth_subtract(tail_wing_hole, chest_head, 0.07); + let chest_head = smud::op_smooth_union(chest, head, 0.07); + let chest_head_tail = smud::op_smooth_subtract(tail_wing_hole, chest_head, 0.07); - let body = sd_smooth_union( + let body = smud::op_smooth_union( chest_head_tail, max(wings, -tail_wing_hole + 0.01), 0.01 ); - let eye = sd_circle(p - vec2(0.20, 0.45), 0.05); + let eye = smud::sd_circle(p - vec2(0.20, 0.45), 0.05); let bevy = max(body, -eye); return bevy * scale; @@ -56,7 +59,7 @@ fn bevy(p: vec2) -> f32 { fn star(p: vec2) -> f32 { let s = 500.; - return sd_star_5(p / s, 0.3, 0.6) * s; + return smud::sd_star_5_(p / s, 0.3, 0.6) * s; } fn sdf(p: vec2) -> f32 { diff --git a/assets/vertex.wgsl b/assets/vertex.wgsl index a6ef6bd..05deb30 100644 --- a/assets/vertex.wgsl +++ b/assets/vertex.wgsl @@ -1,4 +1,4 @@ -#import bevy_smud::prelude +#define_import_path smud::vertex struct View { view_proj: mat4x4, diff --git a/assets/view_bindings.wgsl b/assets/view_bindings.wgsl new file mode 100644 index 0000000..5047a6d --- /dev/null +++ b/assets/view_bindings.wgsl @@ -0,0 +1,10 @@ +#define_import_path smud::view_bindings + +#import bevy_render::view View +#import bevy_render::globals Globals + +@group(0) @binding(0) +var view: View; + +@group(0) @binding(1) +var globals: Globals; diff --git a/examples/basic.rs b/examples/basic.rs index 8e747a8..03f39d8 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -7,9 +7,8 @@ fn main() { // 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) - .add_plugin(SmudPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin)) + .add_systems(Startup, setup) .run(); } @@ -22,7 +21,7 @@ fn setup( // p is the position of a fragment within the sdf shape, with 0, 0 at the center. // Here we are using the built-in sd_circle function, which accepts the // radius as a parameter. - let circle = shaders.add_sdf_expr("sd_circle(p, 70.)"); + let circle = shaders.add_sdf_expr("smud::sd_circle(p, 70.)"); // There are other ways to define sdfs as well: // .add_sdf_body let's you add multiple lines and needs to end with a return statements @@ -31,7 +30,7 @@ fn setup( // Taking the absolute value of p.x creates a vertical line of symmetry let p = vec2(abs(p.x), p.y); // By subtracting from p, we can move shapes -return sd_circle(p - vec2(20., 0.), 40.); +return smud::sd_circle(p - vec2(20., 0.), 40.); ", ); diff --git a/examples/bench.rs b/examples/bench.rs index 681eaf8..5ce0654 100644 --- a/examples/bench.rs +++ b/examples/bench.rs @@ -17,13 +17,15 @@ fn main() { LoadingState::new(GameState::Loading).continue_to_state(GameState::Running), ) .add_collection_to_loading_state::<_, AssetHandles>(GameState::Loading) - .add_plugins(DefaultPlugins) - .add_plugin(LogDiagnosticsPlugin::default()) - .add_plugin(FrameTimeDiagnosticsPlugin) - .add_plugin(SmudPlugin) - .add_plugin(PanCamPlugin) - .add_plugin(bevy_lospec::PalettePlugin) - .add_system(setup.in_schedule(OnEnter(GameState::Running))) + .add_plugins(( + DefaultPlugins, + LogDiagnosticsPlugin::default(), + FrameTimeDiagnosticsPlugin, + SmudPlugin, + PanCamPlugin, + bevy_lospec::PalettePlugin, + )) + .add_systems(OnEnter(GameState::Running), setup) // .add_system_set(SystemSet::on_update(GameState::Running).with_system(update)) .run(); } diff --git a/examples/bevy.rs b/examples/bevy.rs index 1c6b496..5ed4315 100644 --- a/examples/bevy.rs +++ b/examples/bevy.rs @@ -8,10 +8,8 @@ fn main() { // which is more efficient than MSAA, and also works on Linux, wayland .insert_resource(Msaa::Off) .insert_resource(ClearColor(Color::rgb(0.7, 0.8, 0.7))) - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_plugin(PanCamPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin, PanCamPlugin)) + .add_systems(Startup, setup) .run(); } diff --git a/examples/bloom.rs b/examples/bloom.rs index 52fa333..ecabd36 100644 --- a/examples/bloom.rs +++ b/examples/bloom.rs @@ -1,6 +1,6 @@ //! This example shows that bevy_smud works with bloom enabled //! -//! Note that you could probably achieve chieper and higher quality bloom-like +//! Note that you could probably achieve cheaper and higher quality bloom-like //! effects by creating a custom fill. use bevy::{core_pipeline::bloom::BloomSettings, prelude::*}; @@ -13,9 +13,8 @@ fn main() { // which is more efficient than MSAA, and also works on Linux, wayland .insert_resource(Msaa::Off) .insert_resource(ClearColor(Color::BLACK)) - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin)) + .add_systems(Startup, setup) .run(); } @@ -24,7 +23,7 @@ fn setup(mut commands: Commands, mut shaders: ResMut>) { // p is the position of a fragment within the sdf shape, with 0, 0 at the center. // Here we are using the built-in sd_circle function, which accepts the // radius as a parameter. - let circle = shaders.add_sdf_expr("sd_circle(p, 70.)"); + let circle = shaders.add_sdf_expr("smud::sd_circle(p, 70.)"); commands.spawn(ShapeBundle { shape: SmudShape { diff --git a/examples/custom_fill.rs b/examples/custom_fill.rs index df5ecde..257cd4a 100644 --- a/examples/custom_fill.rs +++ b/examples/custom_fill.rs @@ -8,10 +8,8 @@ fn main() { // which is more efficient than MSAA, and also works on Linux, wayland .insert_resource(Msaa::Off) .insert_resource(ClearColor(Color::BLACK)) - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_plugin(PanCamPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin, PanCamPlugin)) + .add_systems(Startup, setup) .run(); } @@ -52,7 +50,7 @@ fn setup( fill: shaders.add_fill_body( r" let d_2 = abs(d - 1.) - 1.; -let a = sd_fill_alpha_fwidth(d_2); +let a = smud::sd_fill_alpha_fwidth(d_2); return vec4(color.rgb, a * color.a); ", ), diff --git a/examples/gallery.rs b/examples/gallery.rs index a5742ac..76591b0 100644 --- a/examples/gallery.rs +++ b/examples/gallery.rs @@ -14,13 +14,15 @@ fn main() { LoadingState::new(GameState::Loading).continue_to_state(GameState::Running), ) .add_collection_to_loading_state::<_, AssetHandles>(GameState::Loading) - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_plugin(bevy::diagnostic::LogDiagnosticsPlugin::default()) - .add_plugin(bevy::diagnostic::FrameTimeDiagnosticsPlugin) - .add_plugin(PanCamPlugin) - .add_plugin(bevy_lospec::PalettePlugin) - .add_system(setup.in_schedule(OnEnter(GameState::Running))) + .add_plugins(( + DefaultPlugins, + SmudPlugin, + bevy::diagnostic::LogDiagnosticsPlugin::default(), + bevy::diagnostic::FrameTimeDiagnosticsPlugin, + PanCamPlugin, + bevy_lospec::PalettePlugin, + )) + .add_systems(OnEnter(GameState::Running), setup) .run(); } diff --git a/examples/hot_reload.rs b/examples/hot_reload.rs index 99ebeb5..f3ce838 100644 --- a/examples/hot_reload.rs +++ b/examples/hot_reload.rs @@ -1,18 +1,21 @@ -use bevy::prelude::*; +use bevy::{asset::ChangeWatcher, 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: true, - ..default() - })) - .add_plugin(SmudPlugin) - .add_startup_system(setup) + .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_systems(Startup, setup) .run(); } diff --git a/examples/sorting.rs b/examples/sorting.rs index 4d27b04..69b306d 100644 --- a/examples/sorting.rs +++ b/examples/sorting.rs @@ -8,10 +8,8 @@ fn main() { // which is more efficient than MSAA, and also works on Linux, wayland .insert_resource(Msaa::Off) .insert_resource(ClearColor(Color::rgb(0.7, 0.8, 0.7))) - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_plugin(PanCamPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin, PanCamPlugin)) + .add_systems(Startup, setup) .run(); } @@ -21,7 +19,7 @@ fn setup(mut commands: Commands, mut shaders: ResMut>) { transform: Transform::from_translation(Vec3::Z * 3.), shape: SmudShape { color: Color::rgb(0.0, 0.0, 0.0), - sdf: shaders.add_sdf_body("return sd_circle(p, 70.);"), + sdf: shaders.add_sdf_body("return smud::sd_circle(p, 70.);"), frame: Frame::Quad(80.), ..default() }, @@ -33,7 +31,7 @@ fn setup(mut commands: Commands, mut shaders: ResMut>) { transform: Transform::from_translation(Vec3::Z * 2.), shape: SmudShape { color: Color::rgb(0.46, 0.42, 0.80), - sdf: shaders.add_sdf_body("return sd_circle(p, 150.);"), + sdf: shaders.add_sdf_body("return smud::sd_circle(p, 150.);"), frame: Frame::Quad(200.), ..default() }, @@ -45,7 +43,7 @@ fn setup(mut commands: Commands, mut shaders: ResMut>) { transform: Transform::from_translation(Vec3::Z * 1.), shape: SmudShape { color: Color::rgb(0.83, 0.82, 0.80), - sdf: shaders.add_sdf_body("return sd_vesica(p.yx, 400., 150.);"), + sdf: shaders.add_sdf_body("return smud::sd_vesica(p.yx, 400., 150.);"), frame: Frame::Quad(400.), ..default() }, diff --git a/examples/time.rs b/examples/time.rs index 5f4f450..117e0e4 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -8,10 +8,8 @@ fn main() { // which is more efficient than MSAA, and also works on Linux, wayland .insert_resource(Msaa::Off) .insert_resource(ClearColor(Color::rgb(0.7, 0.8, 0.7))) - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_plugin(PanCamPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin, PanCamPlugin)) + .add_systems(Startup, setup) .run(); } diff --git a/examples/transforms.rs b/examples/transforms.rs index 2a274eb..9f4186b 100644 --- a/examples/transforms.rs +++ b/examples/transforms.rs @@ -10,10 +10,8 @@ fn main() { // which is more efficient than MSAA, and also works on Linux, wayland .insert_resource(Msaa::Off) .insert_resource(ClearColor(Color::rgb(0.7, 0.8, 0.7))) - .add_plugins(DefaultPlugins) - .add_plugin(SmudPlugin) - .add_plugin(PanCamPlugin) - .add_startup_system(setup) + .add_plugins((DefaultPlugins, SmudPlugin, PanCamPlugin)) + .add_systems(Startup, setup) .run(); } diff --git a/src/components.rs b/src/components.rs index 8b68d89..dc3b086 100644 --- a/src/components.rs +++ b/src/components.rs @@ -32,7 +32,7 @@ impl Default for SmudShape { } /// Bounds for describing how far the fragment shader of a shape will reach, should be bigger than the shape unless you want to clip it -#[derive(Reflect, FromReflect, Debug, Clone, Copy)] +#[derive(Reflect, Debug, Clone, Copy)] pub enum Frame { /// A quad with a given half-size (!) Quad(f32), // todo: it probably makes sense for this to be the full width instead... diff --git a/src/lib.rs b/src/lib.rs index 1f0dd54..7471256 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,7 +39,7 @@ use bevy::{ ExtractedView, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities, }, - Extract, MainWorld, RenderApp, RenderSet, + Extract, MainWorld, Render, RenderApp, RenderSet, }, utils::{FloatOrd, HashMap}, }; @@ -84,7 +84,7 @@ pub struct SmudPlugin; impl Plugin for SmudPlugin { fn build(&self, app: &mut App) { // All the messy boiler-plate for loading a bunch of shaders - app.add_plugin(ShaderLoadingPlugin); + app.add_plugins(ShaderLoadingPlugin); // app.add_plugin(UiShapePlugin); if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { @@ -92,14 +92,19 @@ impl Plugin for SmudPlugin { .add_render_command::() .init_resource::() .init_resource::() - .init_resource::() .init_resource::>() - .add_systems((extract_shapes, extract_sdf_shaders).in_schedule(ExtractSchedule)) - .add_system(queue_shapes.in_set(RenderSet::Queue)); + .add_systems(ExtractSchedule, (extract_shapes, extract_sdf_shaders)) + .add_systems(Render, queue_shapes.in_set(RenderSet::Queue)); } app.register_type::(); } + + fn finish(&self, app: &mut App) { + app.get_sub_app_mut(RenderApp) + .unwrap() + .init_resource::(); + } } type DrawSmudShape = (SetItemPipeline, SetShapeViewBindGroup<0>, DrawShapeBatch); @@ -310,10 +315,10 @@ fn extract_sdf_shaders(mut main_world: ResMut, mut pipeline: ResMut match shader.import_path() { - Some(ShaderImport::Custom(p)) => p.to_owned(), + ShaderImport::Custom(p) => p.to_owned(), _ => { let id = Uuid::new_v4(); - let path = format!("bevy_smud::generated::{id}"); + let path = format!("smud::generated::{id}"); shader.set_import_path(&path); path } @@ -326,10 +331,10 @@ fn extract_sdf_shaders(mut main_world: ResMut, mut pipeline: ResMut match shader.import_path() { - Some(ShaderImport::Custom(p)) => p.to_owned(), + ShaderImport::Custom(p) => p.to_owned(), _ => { let id = Uuid::new_v4(); - let path = format!("bevy_smud::generated::{id}"); + let path = format!("smud::generated::{id}"); shader.set_import_path(&path); path } @@ -341,16 +346,29 @@ fn extract_sdf_shaders(mut main_world: ResMut, mut pipeline: ResMut globals: Globals; -#import {sdf_import_path} -#import {fill_import_path} -#import bevy_smud::fragment +#import {sdf_import_path} as sdf +#import {fill_import_path} as fill + +struct FragmentInput {{ + @location(0) color: vec4, + @location(1) pos: vec2, +}}; + +@fragment +fn fragment(in: FragmentInput) -> @location(0) vec4 {{ + let d = sdf::sdf(in.pos); + return fill::fill(d, in.color); +}} "# - )); + ), + format!("smud::generated::{shader_key:?}"), + ); // todo does this work, or is it too late? let generated_shader_handle = shaders.add(generated_shader); @@ -401,7 +419,8 @@ fn extract_shapes( // fork of Mesh2DPipelineKey (in order to remove bevy_sprite dependency) // todo: merge with SmudPipelineKey? bitflags::bitflags! { -#[repr(transparent)] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[repr(transparent)] struct PipelineKey: u32 { const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS; const PRIMITIVE_TOPOLOGY_RESERVED_BITS = Self::PRIMITIVE_TOPOLOGY_MASK_BITS << Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS; @@ -421,7 +440,7 @@ impl PipelineKey { } pub fn msaa_samples(&self) -> u32 { - 1 << ((self.bits >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS) + 1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS) } pub fn from_primitive_topology(primitive_topology: PrimitiveTopology) -> Self { @@ -432,8 +451,8 @@ impl PipelineKey { } pub fn primitive_topology(&self) -> PrimitiveTopology { - let primitive_topology_bits = - (self.bits >> Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS) & Self::PRIMITIVE_TOPOLOGY_MASK_BITS; + let primitive_topology_bits = (self.bits() >> Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS) + & Self::PRIMITIVE_TOPOLOGY_MASK_BITS; match primitive_topology_bits { x if x == PrimitiveTopology::PointList as u32 => PrimitiveTopology::PointList, x if x == PrimitiveTopology::LineList as u32 => PrimitiveTopology::LineList, diff --git a/src/sdf_assets.rs b/src/sdf_assets.rs index 6c6b256..81dc32d 100644 --- a/src/sdf_assets.rs +++ b/src/sdf_assets.rs @@ -1,4 +1,4 @@ -use bevy::prelude::*; +use bevy::{prelude::*, utils::Uuid}; /// Extension trait for Assets for conveniently creating new shaders from code pub trait SdfAssets { @@ -15,26 +15,41 @@ pub trait SdfAssets { impl SdfAssets for Assets { fn add_sdf_body>(&mut self, sdf: T) -> Handle { let body = sdf.into(); - let shader = Shader::from_wgsl(format!( - r#" -#import bevy_smud::shapes + let id = Uuid::new_v4(); + let shader = Shader::from_wgsl( + format!( + r#" +#define_import_path smud::sdf{id} + +#import smud + fn sdf(p: vec2) -> f32 {{ {body} }} "# - )); + ), + file!(), + ); self.add(shader) } fn add_fill_body>(&mut self, fill: T) -> Handle { let body = fill.into(); - let shader = Shader::from_wgsl(format!( - r#" + let id = Uuid::new_v4(); + let shader = Shader::from_wgsl( + format!( + r#" +#define_import_path smud::fill{id} + +#import smud + fn fill(d: f32, color: vec4) -> vec4 {{ {body} }} "# - )); + ), + file!(), + ); self.add(shader) } diff --git a/src/shader_loading.rs b/src/shader_loading.rs index 56eebe5..8d7ff26 100644 --- a/src/shader_loading.rs +++ b/src/shader_loading.rs @@ -2,29 +2,33 @@ use bevy::{prelude::*, reflect::TypeUuid}; const PRELUDE_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 11291576006157771079); -const PRELUDE_SHADER_IMPORT: &str = "bevy_smud::prelude"; +const PRELUDE_SHADER_IMPORT: &str = "smud::prelude"; -const SHAPES_SHADER_HANDLE: HandleUntyped = +const SMUD_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 10055894596049459186); -const SHAPES_SHADER_IMPORT: &str = "bevy_smud::shapes"; +const SMUD_SHADER_IMPORT: &str = "smud"; + +const VIEW_BINDINGS_SHADER_HANDLE: HandleUntyped = + HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 11792080578571156967); +const VIEW_BINDINGS_SHADER_IMPORT: &str = "smud::view_bindings"; pub const VERTEX_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 16846632126033267571); -const VERTEX_SHADER_IMPORT: &str = "bevy_smud::vertex"; +const VERTEX_SHADER_IMPORT: &str = "smud::vertex"; pub const FRAGMENT_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 10370213491934870425); -const FRAGMENT_SHADER_IMPORT: &str = "bevy_smud::fragment"; +const FRAGMENT_SHADER_IMPORT: &str = "smud::fragment"; /// 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 = "bevy_smud::default_fill"; +const DEFAULT_FILL_IMPORT: &str = "smud::default_fill"; /// Simple single-colored filled fill pub const SIMPLE_FILL_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 16286090377316294491); -const SIMPLE_FILL_IMPORT: &str = "bevy_smud::simple_fill"; +const SIMPLE_FILL_IMPORT: &str = "smud::simple_fill"; pub struct ShaderLoadingPlugin; @@ -32,29 +36,40 @@ 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")) + 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 shapes = Shader::from_wgsl(include_str!("../assets/shapes.wgsl")) - .with_import_path(SHAPES_SHADER_IMPORT); - shaders.set_untracked(SHAPES_SHADER_HANDLE, shapes); + 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")) + 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")) + 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")) - .with_import_path(DEFAULT_FILL_IMPORT); + 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")) - .with_import_path(SIMPLE_FILL_IMPORT); + 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); } }