struct VertexInput { @builtin(vertex_index) vertex_idx: u32, @location(0) pos: vec2, @location(1) dim: u32, @location(2) uv: u32, @location(3) color: u32, @location(4) content_type_with_srgb: u32, @location(5) depth: f32, } struct VertexOutput { @invariant @builtin(position) position: vec4, @location(0) color: vec4, @location(1) uv: vec2, @location(2) @interpolate(flat) content_type: u32, }; struct Params { screen_resolution: vec2, _pad: vec2, }; @group(0) @binding(0) var color_atlas_texture: texture_2d; @group(0) @binding(1) var mask_atlas_texture: texture_2d; @group(0) @binding(2) var atlas_sampler: sampler; @group(1) @binding(0) var params: Params; fn srgb_to_linear(c: f32) -> f32 { if c <= 0.04045 { return c / 12.92; } else { return pow((c + 0.055) / 1.055, 2.4); } } @vertex fn vs_main(in_vert: VertexInput) -> VertexOutput { var pos = in_vert.pos; let width = in_vert.dim & 0xffffu; let height = (in_vert.dim & 0xffff0000u) >> 16u; let color = in_vert.color; var uv = vec2(in_vert.uv & 0xffffu, (in_vert.uv & 0xffff0000u) >> 16u); let v = in_vert.vertex_idx; let corner_position = vec2( in_vert.vertex_idx & 1u, (in_vert.vertex_idx >> 1u) & 1u, ); let corner_offset = vec2(width, height) * corner_position; uv = uv + corner_offset; pos = pos + vec2(corner_offset); var vert_output: VertexOutput; vert_output.position = vec4( 2.0 * vec2(pos) / vec2(params.screen_resolution) - 1.0, in_vert.depth, 1.0, ); vert_output.position.y *= -1.0; let content_type = in_vert.content_type_with_srgb & 0xffffu; let srgb = (in_vert.content_type_with_srgb & 0xffff0000u) >> 16u; switch srgb { case 0u: { vert_output.color = vec4( f32((color & 0x00ff0000u) >> 16u) / 255.0, f32((color & 0x0000ff00u) >> 8u) / 255.0, f32(color & 0x000000ffu) / 255.0, f32((color & 0xff000000u) >> 24u) / 255.0, ); } case 1u: { vert_output.color = vec4( srgb_to_linear(f32((color & 0x00ff0000u) >> 16u) / 255.0), srgb_to_linear(f32((color & 0x0000ff00u) >> 8u) / 255.0), srgb_to_linear(f32(color & 0x000000ffu) / 255.0), f32((color & 0xff000000u) >> 24u) / 255.0, ); } default: {} } var dim: vec2 = vec2(0u); switch content_type { case 0u: { dim = textureDimensions(color_atlas_texture); break; } case 1u: { dim = textureDimensions(mask_atlas_texture); break; } default: {} } vert_output.content_type = content_type; vert_output.uv = vec2(uv) / vec2(dim); return vert_output; } @fragment fn fs_main(in_frag: VertexOutput) -> @location(0) vec4 { switch in_frag.content_type { case 0u: { var sample = textureSampleLevel(color_atlas_texture, atlas_sampler, in_frag.uv, 0.0); sample[3] = sample[3] * in_frag.color.a; return sample; } case 1u: { return vec4(in_frag.color.rgb, in_frag.color.a * textureSampleLevel(mask_atlas_texture, atlas_sampler, in_frag.uv, 0.0).x); } default: { return vec4(0.0); } } }