use snapshot::{begin_snapshots, snapshot, snapshot_test};
use crate::{pre::PreParsed, utils::WithErrors};
begin_snapshots!();
#[snapshot_test]
fn ifdef() {
snapshot!(PreParsed r#"
#ifdef FOO
// FOO is defined
#endif
"#);
snapshot!(PreParsed r#"
#ifdef FOO_BAR_BAZ
// FOO_BAR_BAZ is defined
#else
// FOO_BAR_BAZ is _not_ defined
#endif
"#);
snapshot!(PreParsed r#"
#ifdef FOO
// FOO is defined
#else ifdef BAR
// BAR is defined
#else ifdef BAZ
// BAZ is defined
#else
// None of FOO, BAR, or BAZ are defined
#endif
"#);
snapshot!(PreParsed r#"
#ifdef FOO
// FOO is defined
#else ifdef BAR
// BAR is defined
#else ifdef BAZ
// BAZ is defined
#endif
"#);
snapshot!(PreParsed r#"
fn main() {
const c = 2;
var a: i32;
let x: i32 = generateValue();
switch x {
#ifdef FOO
case 0: {
a = #{FOO};
}
case 1, c {
a = #{FOO} * 6;
}
case 3, default {
a = #{FOO} * 8;
}
#else
case 0: {
a = 1;
}
case 1, c {
a = 3;
}
case 3, default {
a = 4;
}
#endif
}
}
"#);
}
#[snapshot_test]
fn ifndef() {
snapshot!(PreParsed r#"
#ifndef FOO
// FOO is not defined
#endif
"#);
snapshot!(PreParsed r#"
#ifndef FOO_BAR_BAZ
// FOO_BAR_BAZ is not defined
#else
// FOO_BAR_BAZ _is_ defined
#endif
"#);
snapshot!(PreParsed r#"
#ifndef FOO
// FOO is not defined
#else ifndef BAR
// FOO is defined, but BAR is not
#else ifndef BAZ
// FOO and BAR are defined, but BAZ is not
#else
// All of FOO, BAR, and BAZ are defined
#endif
"#);
snapshot!(PreParsed r#"
#ifndef FOO
// FOO is not defined
#else ifndef BAR
// FOO is defined, but BAR is not
#else ifndef BAZ
// FOO and BAR are defined, but BAZ is not
#endif
"#);
snapshot!(PreParsed r#"
fn main() {
const c = 2;
var a: i32;
let x: i32 = generateValue();
switch x {
#ifndef FOO
case 0: {
a = 1;
}
case 1, c {
a = 3;
}
case 3, default {
a = 4;
}
#else
case 0: {
a = #{FOO};
}
case 1, c {
a = #{FOO} * 6;
}
case 3, default {
a = #{FOO} * 8;
}
#endif
}
}
"#);
}
#[snapshot_test]
fn if_expr() {
snapshot!(PreParsed r#"
#ifdef FOO
#if FOO > 2
// FOO is defined and is greater than 2
#else if FOO < 0
// FOO is defined and is < 0
#else
// FOO is defined in the range [0, 2]
#endif
#endif // #ifdef FOO
"#);
}
#[snapshot_test]
fn skybox_wgsl() {
snapshot!(PreParsed(WithErrors) r#"
#import bevy_render::view::View
#import bevy_pbr::utils::coords_to_viewport_uv
struct SkyboxUniforms {
brightness: f32,
#ifdef SIXTEEN_BYTE_ALIGNMENT
_wasm_padding_8b: u32,
_wasm_padding_12b: u32,
_wasm_padding_16b: u32,
#endif
}
@group(0) @binding(0) var skybox: texture_cube<f32>;
@group(0) @binding(1) var skybox_sampler: sampler;
@group(0) @binding(2) var<uniform> view: View;
@group(0) @binding(3) var<uniform> uniforms: SkyboxUniforms;
fn coords_to_ray_direction(position: vec2<f32>, viewport: vec4<f32>) -> vec3<f32> {
// Using world positions of the fragment and camera to calculate a ray direction
// breaks down at large translations. This code only needs to know the ray direction.
// The ray direction is along the direction from the camera to the fragment position.
// In view space, the camera is at the origin, so the view space ray direction is
// along the direction of the fragment position - (0,0,0) which is just the
// fragment position.
// Use the position on the near clipping plane to avoid -inf world position
// because the far plane of an infinite reverse projection is at infinity.
let view_position_homogeneous = view.inverse_projection * vec4(
coords_to_viewport_uv(position, viewport) * vec2(2.0, -2.0) + vec2(-1.0, 1.0),
1.0,
1.0,
);
let view_ray_direction = view_position_homogeneous.xyz / view_position_homogeneous.w;
// Transforming the view space ray direction by the view matrix, transforms the
// direction to world space. Note that the w element is set to 0.0, as this is a
// vector direction, not a position, That causes the matrix multiplication to ignore
// the translations from the view matrix.
let ray_direction = (view.view * vec4(view_ray_direction, 0.0)).xyz;
return normalize(ray_direction);
}
struct VertexOutput {
@builtin(position) position: vec4<f32>,
};
// 3 | 2.
// 2 | : `.
// 1 | x-----x.
// 0 | | s | `.
// -1 | 0-----x.....1
// +---------------
// -1 0 1 2 3
//
// The axes are clip-space x and y. The region marked s is the visible region.
// The digits in the corners of the right-angled triangle are the vertex
// indices.
@vertex
fn skybox_vertex(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
// See the explanation above for how this works.
let clip_position = vec4(
f32(vertex_index & 1u),
f32((vertex_index >> 1u) & 1u),
0.25,
0.5
) * 4.0 - vec4(1.0);
return VertexOutput(clip_position);
}
@fragment
fn skybox_fragment(in: VertexOutput) -> @location(0) vec4<f32> {
let ray_direction = coords_to_ray_direction(in.position.xy, view.viewport);
// Cube maps are left-handed so we negate the z coordinate.
return textureSample(skybox, skybox_sampler, ray_direction * vec3(1.0, 1.0, -1.0)) * uniforms.brightness;
}
"#);
}