murrelet_gpu 0.1.2

gpu functions for murrelet, a livecode framework
Documentation
pub const SUFFIX: &str = r#"
    return FragmentOutput(result);
}
"#;

pub const BINDING_2TEX: &str = r#"
struct FragmentOutput {
    @location(0) f_color: vec4<f32>,
};

struct Uniforms {
    dims: vec4<f32>,
    more_info: vec4<f32>,
    more_info_other: vec4<f32>,
};

@group(0) @binding(0)
var tex: texture_2d<f32>;
@group(0) @binding(1)
var tex2: texture_2d<f32>;
@group(0) @binding(2)
var tex_sampler: sampler;

@group(0) @binding(3)
var<uniform> uniforms: Uniforms;
"#;

pub const BINDING_1TEX: &str = r#"
struct FragmentOutput {
    @location(0) f_color: vec4<f32>,
};

struct Uniforms {
    dims: vec4<f32>,
    more_info: vec4<f32>,
    more_info_other: vec4<f32>,
};

@group(0) @binding(0)
var tex: texture_2d<f32>;
@group(0) @binding(1)
var tex_sampler: sampler;

@group(0) @binding(2)
var<uniform> uniforms: Uniforms;
"#;

pub const BINDING_3D: &str = r#"
struct FragmentOutput {
    @location(0) f_color: vec4<f32>,
};

struct Uniforms {
    dims: vec4<f32>,
    more_info: vec4<f32>,
    more_info_other: vec4<f32>,
};

@group(0) @binding(0) var tex: texture_2d<f32>;
@group(0) @binding(1) var tex_sampler: sampler;
@group(0) @binding(2) var<uniform> uniforms: Uniforms;
@group(0) @binding(4) var shadow_map: texture_depth_2d;
@group(0) @binding(5) var shadow_sampler: sampler_comparison;

"#;

pub const INCLUDES: &str = r#"


// stealing from the internet
fn hsv2rgb(c: vec3<f32>) -> vec3<f32> {
    let K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    let r = vec3<f32>(
        clamp(p.x - K.x, 0.0, 1.0),
        clamp(p.y - K.x, 0.0, 1.0),
        clamp(p.z - K.x, 0.0, 1.0));
    return c.z * mix(K.xxx, r, c.y);
}

// https://bottosson.github.io/posts/oklab/
fn oklab_to_linear_srgb(oklab: vec3<f32>) -> vec3<f32> {
    let l_ = oklab.r + 0.3963377774 * oklab.g + 0.2158037573 * oklab.b;
    let m_ = oklab.r - 0.1055613458 * oklab.g - 0.0638541728 * oklab.b;
    let s_ = oklab.r - 0.0894841775 * oklab.g - 1.2914855480 * oklab.b;

    let l = l_*l_*l_;
    let m = m_*m_*m_;
    let s = s_*s_*s_;

    return vec3<f32>(
       4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
      -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
      -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s,
    );
}

fn linear_srgb_to_oklab(c: vec3<f32>) -> vec3<f32>
{
    let l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b;
  	let m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b;
	  let s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b;

    let l_ = pow(l, 1.0/3.0);
    let m_ = pow(m, 1.0/3.0);
    let s_ = pow(s, 1.0/3.0);

    return vec3<f32>(
        0.2104542553*l_ + 0.7936177850*m_ - 0.0040720468*s_,
        1.9779984951*l_ - 2.4285922050*m_ + 0.4505937099*s_,
        0.0259040371*l_ + 0.7827717662*m_ - 0.8086757660*s_,
    );
}


fn luma(rgb: vec3<f32>) -> f32 {
  let s: vec3<f32> = pow(rgb, vec3<f32>(2.2));
  let l: f32 = 0.2126 * s.r + 0.7152 * s.g + 0.0722 * s.b;
  return pow(l, 1.0 / 2.2);
}

fn rand(n: f32) -> f32 { return fract(sin(n) * 43758.5453123); }
fn noise(p: f32) -> f32 {
  let fl = floor(p);
  let fc = fract(p);
  return mix(rand(fl), rand(fl + 1.), fc);
}

fn rand2(n: vec2<f32>) -> f32 {
  return fract(sin(dot(n, vec2<f32>(12.9898, 4.1414))) * 43758.5453);
}

// i don't know where this went
fn smoothStep(edge0: vec2<f32>, edge1: vec2<f32>, x: vec2<f32>) -> vec2<f32> {
    let t: vec2<f32> = clamp((x - edge0) / (edge1 - edge0), vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 1.0));
    return t * t * (vec2<f32>(3.0, 3.0) - 2.0 * t);
}


fn noise2(n: vec2<f32>) -> f32 {
  let d = vec2<f32>(0., 1.);
  let b = floor(n);
  let f = smoothStep(vec2<f32>(0.), vec2<f32>(1.), fract(n));
  return mix(mix(rand2(b), rand2(b + d.yx), f.x), mix(rand2(b + d.xy), rand2(b + d.yy), f.x), f.y);
}

fn pixel_noise2(tex_coords: vec2<f32>) -> f32 {
  let n = fract(tex_coords * uniforms.dims.y);
  let d = vec2<f32>(0., 1.);
  let b = floor(n);
  let f = smoothStep(vec2<f32>(0.), vec2<f32>(1.), fract(n));
  return mix(mix(rand2(b), rand2(b + d.yx), f.x), mix(rand2(b + d.xy), rand2(b + d.yy), f.x), f.y);
}

fn mod3(what_to_mod: vec3<f32>, what: vec3<f32>) -> vec3<f32> {
    return what_to_mod - floor(what_to_mod * 1.0 / what) * what;
}

fn step_3(input: vec3<f32>, compare: vec3<f32>) -> vec3<f32> {
    return vec3<f32>(step(input.r, compare.r), step(input.g, compare.g), step(input.b, compare.b));
}

fn mod289(x: vec2<f32>) -> vec2<f32> {
    return x - floor(x * (1. / 289.)) * 289.;
}

fn mod289_3(x: vec3<f32>) -> vec3<f32> {
    return x - floor(x * (1. / 289.)) * 289.;
}

fn permute3(x: vec3<f32>) -> vec3<f32> {
    return mod289_3(((x * 34.) + 1.) * x);
}

fn srandom(pos: vec3<f32>) -> f32 {
  return -1. + 2. * fract(sin(dot(pos.xyz, vec3<f32>(70.9898, 78.233, 32.4355))) * 43758.5453123);
}

// 1 if non-zero, 0 otherwise (where zero is 0.0001)
fn is_almost_nonzero(v: f32) -> f32 {
  return step(0.0001, v);
}

fn is_almost_zero(v: f32) -> f32 {
  return 1.0 - is_almost_nonzero(v);
}


fn fbm(i: vec2<f32>) -> f32 {
  var p = i;

  let m2: mat2x2<f32> = mat2x2<f32>(vec2<f32>(0.8, 0.6), vec2<f32>(-0.6, 0.8));
  var f: f32 = 0.;
  f = f + 0.5000 * noise2(p);
  p = m2 * p * 2.02;
  f = f + 0.2500 * noise2(p);
  p = m2 * p * 2.03;
  f = f + 0.1250 * noise2(p);
  p = m2 * p * 2.01;
  f = f + 0.0625 * noise2(p);
  return f / 0.9375;
}


fn clamp01(p: f32) -> f32 {
  return clamp(p, 0.0, 1.0);
}

fn clamp3(p: vec3<f32>, min: f32, max: f32) -> vec3<f32> {
  return vec3<f32>(
      clamp(p.x, 0.0, 1.0),
      clamp(p.y, 0.0, 1.0),
      clamp(p.z, 0.0, 1.0)
  );
}

fn clamp4(p: vec4<f32>, min: f32, max: f32) -> vec4<f32> {
  return vec4<f32>(
      clamp(p.x, 0.0, 1.0),
      clamp(p.y, 0.0, 1.0),
      clamp(p.z, 0.0, 1.0),
      clamp(p.a, 0.0, 1.0)
  );
}

fn color_if_for_neg_color(p: vec4<f32>) -> vec4<f32> {
  return vec4<f32>(step(0.0, p.r), step(0.0, p.g), step(0.0, p.b), 1.0);
}

fn color_if_for_over_1_color(p: vec4<f32>) -> vec4<f32> {
  return vec4<f32>(step(p.r, 1.0), step(p.g, 1.0), step(p.b, 1.0), 1.0);
}

fn red_if_alpha_over_green_if_under(p: vec4<f32>) -> vec4<f32> {
  return vec4<f32>(step(1.0, p.a), step(0.0, p.g), 0.0, 1.0);
}

fn mod289_4(x: vec4<f32>) -> vec4<f32> { return x - floor(x * (1. / 289.)) * 289.; }
fn perm4(x: vec4<f32>) -> vec4<f32> { return mod289_4(((x * 34.) + 1.) * x); }

fn noise3(p: vec3<f32>) -> f32 {
    let a = floor(p);
    var d: vec3<f32> = p - a;
    d = d * d * (3. - 2. * d);

    let b = a.xxyy + vec4<f32>(0., 1., 0., 1.);
    let k1 = perm4(b.xyxy);
    let k2 = perm4(k1.xyxy + b.zzww);

    let c = k2 + a.zzzz;
    let k3 = perm4(c);
    let k4 = perm4(c + 1.);

    let o1 = fract(k3 * (1. / 41.));
    let o2 = fract(k4 * (1. / 41.));

    let o3 = o2 * d.z + o1 * (1. - d.z);
    let o4 = o3.yw * d.x + o3.xz * (1. - d.x);

    return o4.y * d.y + o4.x * (1. - d.y);
}

// i don't know if this is right
fn toroid_noise(r1: f32, r2: f32, xy: vec2<f32>) -> f32 {
  let x = fract(xy.x);
  let y = fract(xy.y);

  let angle_x = x * 2.0 * 3.1415926535;
  let angle_y = y * 2.0 * 3.1415926535;

  // convert the coordinates to the location in the 3d torus
  let torus_coords: vec3<f32> = vec3<f32>(
      (r1 + r2 * cos(angle_y)) * cos(angle_x),
      (r1 + r2 * cos(angle_y)) * sin(angle_x),
      r2 * sin(angle_y),
  );

  let rn = noise3(torus_coords);
  return rn;
}
"#;

pub const VERTEX_SHADER: &str = "
struct VertexOutput {
  @location(0) tex_coords: vec2<f32>,
  @location(1) world_pos: vec4<f32>,
  @location(2) normal: vec3<f32>,
  @location(3) light_space_pos: vec4<f32>,
  @location(4) world_pos: vec3<f32>,
  @builtin(position) out_pos: vec4<f32>,
};

@vertex
fn main(@location(0) pos: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) face_loc: vec2<f32>) -> VertexOutput {
  let tex_coords: vec2<f32> = vec2<f32>(pos.x * 0.5 + 0.5, 1.0 - (pos.y * 0.5 + 0.5));
  let out_pos: vec4<f32> = vec4<f32>(pos.xy, 0.0, 1.0);
  return VertexOutput(
    tex_coords,
    vec4<f32>(0.0), // shad_info
    vec3<f32>(0.0), //normal
    vec4<f32>(0.0), //light space pos
    vec3<f32>(0.0), //world_pos,
    out_pos);
}";

pub const VERTEX_SHADER_3D: &str = "
struct Uniforms {
  view_proj: mat4x4<f32>,
  light_proj: mat4x4<f32>,
};
@group(0) @binding(3) var<uniform> uniforms: Uniforms;

struct VertexOutput {
  @location(0) tex_coords: vec2<f32>,
  @location(1) shad_info: vec4<f32>,
  @location(2) normal: vec3<f32>,
  @location(3) light_space_pos: vec4<f32>,
  @location(4) world_pos: vec3<f32>,
  @builtin(position) out_pos: vec4<f32>,
};

@vertex
fn main(@location(0) pos: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) face_loc: vec2<f32>) -> VertexOutput {
  let world_pos: vec4<f32> = vec4<f32>(pos, 1.0);
  let clip_pos: vec4<f32> = uniforms.view_proj * world_pos;
  let light_space_pos = uniforms.light_proj * vec4<f32>(pos, 1.0);

  let shad_info: vec4<f32> = vec4<f32>(face_loc, clip_pos.za);

  let tex_coords: vec2<f32> = vec2<f32>(pos.x * 0.5 + 0.5, 1.0 - (pos.y * 0.5 + 0.5));

  return VertexOutput(tex_coords, shad_info, normal, light_space_pos, pos, clip_pos);

}";

pub const PREFIX: &str = r#"
@fragment
fn main(@location(0) tex_coords: vec2<f32>, @location(1) shad_info: vec4<f32>, @location(2) normal: vec3<f32>, @location(3) light_space_pos: vec4<f32>, @location(4) world_pos: vec3<f32>) -> FragmentOutput {
"#;