// INCLUDE: global uniform header struct InstanceInput { @location(2) texture_index: u32, @location(3) object_index: u32, }; struct VertexInput { @location(0) position: vec3, @location(1) texture_coords: vec2, }; struct VertexOutput { @builtin(position) position: vec4, @location(0) texture_coords: vec2, @location(1) texture_index: u32, }; @group(0) @binding(0) var texture_array: binding_array>; @group(0) @binding(1) var sampler_array: binding_array; // INCLUDE: animate.wgsl fn transform_vertex(obj: ObjectLocation, vertex: VertexInput, instance: InstanceInput) -> vec4 { // Object scale let scale = obj.size / (global.camera_zoom.x * obj.zpos); // Apply scale and sprite aspect // Note that our mesh starts centered at (0, 0). This is important! var pos: vec2 = vec2( vertex.position.x * scale * sprites[instance.texture_index].aspect, vertex.position.y * scale ); // Apply rotation pos = mat2x2( vec2(cos(obj.angle), sin(obj.angle)), vec2(-sin(obj.angle), cos(obj.angle)) ) * pos; // Correct for screen aspect, preserving height // This must be done AFTER rotation. pos = vec2( pos.x / global.window_aspect.x, pos.y ); // Distance-adjusted world position let trans = (vec2(obj.xpos, obj.ypos) - global.camera_position) / obj.zpos; // Finally, translate // // Note that we divide camera zoom by two. // The height of the viewport is `zoom` in game units, // but it's 2 in screen units (since coordinates range from -1 to 1) pos = pos + vec2( trans.x / (global.camera_zoom.x / 2.0) / global.window_aspect.x, trans.y / (global.camera_zoom.x / 2.0) ); return vec4(pos, 0.0, 1.0);; } @vertex fn vertex_main( vertex: VertexInput, instance: InstanceInput, ) -> VertexOutput { var out: VertexOutput; out.position = transform_vertex(objects[instance.object_index], vertex, instance); let t = atlas[animate(instance, global.current_time.x)]; out.texture_index = t.atlas_texture; out.texture_coords = vec2(t.xpos, t.ypos); if vertex.texture_coords.x == 1.0 { out.texture_coords = vec2(out.texture_coords.x + t.width, out.texture_coords.y); } if vertex.texture_coords.y == 1.0 { out.texture_coords = vec2(out.texture_coords.x, out.texture_coords.y + t.height); } return out; } @fragment fn fragment_main(in: VertexOutput) -> @location(0) vec4 { return textureSampleLevel( texture_array[in.texture_index], sampler_array[0], in.texture_coords, 0.0 ).rgba; }