struct View { viewProj: mat4x4f, lightViewProj: mat4x4f, lightPosition: vec4f, eyePosition: vec4f, aspect: f32, }; struct Config { scale: f32, translateX: f32, translateY: f32, }; struct GlyphBuffer { texPosition: vec2f, texSize: vec2f, size: vec2f, unused: vec2f, }; struct LayoutBuffer { position: vec4f, // glyph_index w }; @group(0) @binding(0) var view: View; @group(1) @binding(0) var linearSampler: sampler; @group(1) @binding(1) var fontTexture: texture_2d; @group(1) @binding(2) var glyphBuffer: array; @group(2) @binding(0) var layoutBuffer: array; @group(2) @binding(1) var config: Config; struct VertexInput { @builtin(vertex_index) vertex_index: u32, @builtin(instance_index) instance_index: u32, }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) texture: vec2f, @location(1) @interpolate(flat) glyphIndex: u32, @location(2) foo: vec4f, }; const vertices = array( vec2f(1.0, 0.0), vec2f(0.0, 1.0), vec2f(0.0, 0.0), vec2f(1.0, 1.0), ); @vertex fn vertexMain(input: VertexInput) -> VertexOutput { let texture = vertices[input.vertex_index]; let position = vec2f(texture.x, 1.0 - texture.y); let glyphIndex = u32(layoutBuffer[input.instance_index].position.w); let viewPosition = position * glyphBuffer[glyphIndex].size + layoutBuffer[input.instance_index].position.xy; let screenPosition = viewPosition * vec2f(1 / view.aspect, 1) * config.scale + vec2f(config.translateX, config.translateY); var output: VertexOutput; output.position = vec4f(screenPosition, 0.0, 1.0); output.texture = texture; output.glyphIndex = glyphIndex; output.foo = vec4f(layoutBuffer[glyphIndex].position.xy, 0, 0); return output; } @fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f { var color = vec3f(input.texture.xy, 0); let p = glyphBuffer[input.glyphIndex].texPosition; let s = glyphBuffer[input.glyphIndex].texSize; let base = textureSample(fontTexture, linearSampler, input.texture * s + p); let t = f32(base.x > 0.5); if (base.x < 0.5) { discard; } return vec4f(t, t, t, 1); }