graph-explorer-render 0.1.0

WebGL2/wgpu renderer for graph-explorer — nodes, edges, halos and labels.
Documentation
struct Camera {
  center: vec2<f32>,
  zoom: f32,
  fade: f32,
  viewport: vec2<f32>,
  _pad1: vec2<f32>,
};
@group(0) @binding(0) var<uniform> cam: Camera;

// unit quad in (t, s): t along the edge 0..1, s across -1..1
var<private> CORNERS: array<vec2<f32>, 6> = array<vec2<f32>, 6>(
  vec2<f32>(0.0, -1.0), vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),
  vec2<f32>(0.0, -1.0), vec2<f32>(1.0, 1.0), vec2<f32>(0.0, 1.0),
);

struct VsOut { @builtin(position) clip: vec4<f32>, @location(0) color: vec4<f32>, @location(1) opacity: f32 };

@vertex
fn vs_main(
  @builtin(vertex_index) vi: u32,
  @location(0) a: vec2<f32>,
  @location(1) b: vec2<f32>,
  @location(2) color: vec4<f32>,
  @location(3) width: f32,
  @location(4) opacity: f32,
) -> VsOut {
  let c = CORNERS[vi];
  let d = b - a;
  let len = length(d);
  let dir = select(vec2<f32>(1.0, 0.0), d / len, len > 1e-5);
  let normal = vec2<f32>(-dir.y, dir.x);
  let world = mix(a, b, c.x) + normal * (width * 0.5) * c.y;
  let rel = (world - cam.center) * cam.zoom;
  let clip = vec2<f32>(rel.x / (cam.viewport.x * 0.5), rel.y / (cam.viewport.y * 0.5));
  var out: VsOut;
  out.clip = vec4<f32>(clip, 0.0, 1.0);
  out.color = color;
  out.opacity = opacity;
  return out;
}

@fragment
fn fs_main(in: VsOut) -> @location(0) vec4<f32> {
  return vec4<f32>(in.color.rgb, in.color.a * in.opacity * cam.fade);
}