// TODO: Change order of attributes
struct TilemapVertex {
@location(0) clip_pos_world_pos: vec4<f32>,
@location(1) color: vec4<f32>,
@location(2) tilemap_bounds_mipmap_level: vec3<f32>,
};
struct TilemapFragment {
@builtin(position) clip_pos: vec4<f32>,
@location(0) world_pos: vec2<f32>,
@location(1) color: vec4<f32>,
@location(2) tilemap_bounds_mipmap_level: vec3<f32>,
};
@group(0)
@binding(3)
var tex: texture_2d_array<f32>; // Fragment
@group(0)
@binding(4)
var tex_sampler: sampler; // Fragment
@group(0)
@binding(5)
var tilemap: texture_2d<u32>; // Vertex + Fragment
@vertex
fn vs_main(vertex: TilemapVertex) -> TilemapFragment {
var frag: TilemapFragment;
frag.clip_pos = vec4<f32>(vertex.clip_pos_world_pos.xy, 0., 1.);
frag.world_pos = vertex.clip_pos_world_pos.zw;
frag.color = vertex.color;
frag.tilemap_bounds_mipmap_level = vertex.tilemap_bounds_mipmap_level;
return frag;
}
const TILE_UV_TRANSFORMS = array<mat3x3<f32>, 8>(
mat3x3<f32>(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
mat3x3<f32>(-1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0),
mat3x3<f32>(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 1.0),
mat3x3<f32>(-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0),
mat3x3<f32>(0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0),
mat3x3<f32>(0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0),
mat3x3<f32>(0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
mat3x3<f32>(0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 1.0),
);
@fragment
fn fs_main(frag: TilemapFragment) -> @location(0) vec4<f32> {
let tilemap_bounds = frag.tilemap_bounds_mipmap_level.xy;
let clamped = clamp(frag.world_pos, vec2<f32>(0.), tilemap_bounds);
let tile_2d_index = vec2<u32>(floor(clamped));
let tile = textureLoad(tilemap, tile_2d_index, 0);
if (tile.x == u32(0)) {
discard;
}
var tile_inner_uv = vec3<f32>(fract(frag.world_pos), 1.);
var tile_uv_transforms = TILE_UV_TRANSFORMS;
let tex_coords = tile_uv_transforms[tile.y] * tile_inner_uv;
let mipmap_level = frag.tilemap_bounds_mipmap_level.z;
return textureSampleLevel(tex, tex_sampler, tex_coords.xy / tex_coords.z, tile.x, mipmap_level)
* frag.color; // Apply tilemap color
}