Moved ui rendering to pipeline
parent
a85a0f8188
commit
2e6f79ea31
|
@ -44,8 +44,11 @@ pub const CONTENT_ROOT: &'static str = "./content";
|
|||
/// Root directory of game textures
|
||||
pub const TEXTURE_ROOT: &'static str = "./assets/render";
|
||||
|
||||
/// We can draw at most this many sprites on the screen.
|
||||
pub const SPRITE_INSTANCE_LIMIT: u64 = 500;
|
||||
/// We can draw at most this many object sprites on the screen.
|
||||
pub const OBJECT_SPRITE_INSTANCE_LIMIT: u64 = 500;
|
||||
|
||||
/// We can draw at most this many ui sprites on the screen.
|
||||
pub const UI_SPRITE_INSTANCE_LIMIT: u64 = 100;
|
||||
|
||||
/// Must be small enough to fit in an i32
|
||||
pub const STARFIELD_INSTANCE_LIMIT: u64 = STARFIELD_COUNT * 24;
|
||||
pub const STARFIELD_SPRITE_INSTANCE_LIMIT: u64 = STARFIELD_COUNT * 24;
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
struct InstanceInput {
|
||||
@location(2) transform_matrix_0: vec4<f32>,
|
||||
@location(3) transform_matrix_1: vec4<f32>,
|
||||
@location(4) transform_matrix_2: vec4<f32>,
|
||||
@location(5) transform_matrix_3: vec4<f32>,
|
||||
@location(6) texture_idx: u32,
|
||||
};
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) texture_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4<f32>,
|
||||
@location(0) texture_coords: vec2<f32>,
|
||||
@location(1) index: u32,
|
||||
}
|
||||
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> global: GlobalUniform;
|
||||
struct GlobalUniform {
|
||||
camera_position: vec2<f32>,
|
||||
camera_zoom: vec2<f32>,
|
||||
camera_zoom_limits: vec2<f32>,
|
||||
window_size: vec2<f32>,
|
||||
window_aspect: vec2<f32>,
|
||||
starfield_texture: vec2<u32>,
|
||||
starfield_tile_size: vec2<f32>,
|
||||
starfield_size_limits: vec2<f32>,
|
||||
};
|
||||
|
||||
|
||||
@group(0) @binding(0)
|
||||
var texture_array: binding_array<texture_2d<f32>>;
|
||||
@group(0) @binding(1)
|
||||
var sampler_array: binding_array<sampler>;
|
||||
|
||||
|
||||
|
||||
|
||||
@vertex
|
||||
fn vertex_main(
|
||||
vertex: VertexInput,
|
||||
instance: InstanceInput,
|
||||
) -> VertexOutput {
|
||||
|
||||
let transform = mat4x4<f32>(
|
||||
instance.transform_matrix_0,
|
||||
instance.transform_matrix_1,
|
||||
instance.transform_matrix_2,
|
||||
instance.transform_matrix_3,
|
||||
);
|
||||
|
||||
var out: VertexOutput;
|
||||
out.position = transform * vec4<f32>(vertex.position, 1.0);
|
||||
out.texture_coords = vertex.texture_coords;
|
||||
out.index = instance.texture_idx;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@fragment
|
||||
fn fragment_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
return textureSampleLevel(
|
||||
texture_array[in.index],
|
||||
sampler_array[0],
|
||||
in.texture_coords,
|
||||
0.0
|
||||
).rgba;
|
||||
}
|
|
@ -37,8 +37,9 @@ pub struct GPUState {
|
|||
|
||||
window_aspect: f32,
|
||||
|
||||
sprite_pipeline: wgpu::RenderPipeline,
|
||||
object_pipeline: wgpu::RenderPipeline,
|
||||
starfield_pipeline: wgpu::RenderPipeline,
|
||||
ui_pipeline: wgpu::RenderPipeline,
|
||||
|
||||
starfield: Starfield,
|
||||
texture_array: TextureArray,
|
||||
|
@ -47,8 +48,9 @@ pub struct GPUState {
|
|||
}
|
||||
|
||||
struct VertexBuffers {
|
||||
sprite: Rc<VertexBuffer>,
|
||||
object: Rc<VertexBuffer>,
|
||||
starfield: Rc<VertexBuffer>,
|
||||
ui: Rc<VertexBuffer>,
|
||||
}
|
||||
|
||||
impl GPUState {
|
||||
|
@ -117,12 +119,12 @@ impl GPUState {
|
|||
}
|
||||
|
||||
let vertex_buffers = VertexBuffers {
|
||||
sprite: Rc::new(VertexBuffer::new::<TexturedVertex, SpriteInstance>(
|
||||
"sprite",
|
||||
object: Rc::new(VertexBuffer::new::<TexturedVertex, SpriteInstance>(
|
||||
"objecte",
|
||||
&device,
|
||||
Some(SPRITE_VERTICES),
|
||||
Some(SPRITE_INDICES),
|
||||
galactica_constants::SPRITE_INSTANCE_LIMIT,
|
||||
galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT,
|
||||
)),
|
||||
|
||||
starfield: Rc::new(VertexBuffer::new::<TexturedVertex, StarfieldInstance>(
|
||||
|
@ -130,7 +132,15 @@ impl GPUState {
|
|||
&device,
|
||||
Some(SPRITE_VERTICES),
|
||||
Some(SPRITE_INDICES),
|
||||
galactica_constants::STARFIELD_INSTANCE_LIMIT,
|
||||
galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT,
|
||||
)),
|
||||
|
||||
ui: Rc::new(VertexBuffer::new::<TexturedVertex, SpriteInstance>(
|
||||
"ui",
|
||||
&device,
|
||||
Some(SPRITE_VERTICES),
|
||||
Some(SPRITE_INDICES),
|
||||
galactica_constants::UI_SPRITE_INSTANCE_LIMIT,
|
||||
)),
|
||||
};
|
||||
|
||||
|
@ -145,15 +155,15 @@ impl GPUState {
|
|||
];
|
||||
|
||||
// Create render pipelines
|
||||
let sprite_pipeline = PipelineBuilder::new("sprite", &device)
|
||||
let object_pipeline = PipelineBuilder::new("object", &device)
|
||||
.set_shader(include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/shaders/",
|
||||
"sprite.wgsl"
|
||||
"object.wgsl"
|
||||
)))
|
||||
.set_format(config.format)
|
||||
.set_triangle(true)
|
||||
.set_vertex_buffer(&vertex_buffers.sprite)
|
||||
.set_vertex_buffer(&vertex_buffers.object)
|
||||
.set_bind_group_layouts(bind_group_layouts)
|
||||
.build();
|
||||
|
||||
|
@ -169,6 +179,18 @@ impl GPUState {
|
|||
.set_bind_group_layouts(bind_group_layouts)
|
||||
.build();
|
||||
|
||||
let ui_pipeline = PipelineBuilder::new("ui", &device)
|
||||
.set_shader(include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/shaders/",
|
||||
"ui.wgsl"
|
||||
)))
|
||||
.set_format(config.format)
|
||||
.set_triangle(true)
|
||||
.set_vertex_buffer(&vertex_buffers.ui)
|
||||
.set_bind_group_layouts(bind_group_layouts)
|
||||
.build();
|
||||
|
||||
let mut starfield = Starfield::new();
|
||||
starfield.regenerate();
|
||||
|
||||
|
@ -182,8 +204,9 @@ impl GPUState {
|
|||
window_size,
|
||||
window_aspect,
|
||||
|
||||
sprite_pipeline,
|
||||
object_pipeline,
|
||||
starfield_pipeline,
|
||||
ui_pipeline,
|
||||
|
||||
starfield,
|
||||
texture_array,
|
||||
|
@ -404,14 +427,14 @@ impl GPUState {
|
|||
/// Will panic if SPRITE_INSTANCE_LIMIT is exceeded.
|
||||
///
|
||||
/// This is only called inside self.render()
|
||||
fn make_sprite_instances(
|
||||
fn update_sprite_instances(
|
||||
&self,
|
||||
camera_zoom: f32,
|
||||
camera_pos: Point2<f32>,
|
||||
objects: &Vec<ObjectSprite>,
|
||||
ui: &Vec<UiSprite>,
|
||||
) -> Vec<SpriteInstance> {
|
||||
let mut instances: Vec<SpriteInstance> = Vec::new();
|
||||
) -> (usize, usize) {
|
||||
let mut object_instances: Vec<SpriteInstance> = Vec::new();
|
||||
|
||||
// Game coordinates (relative to camera) of ne and sw corners of screen.
|
||||
// Used to skip off-screen sprites.
|
||||
|
@ -419,20 +442,45 @@ impl GPUState {
|
|||
let clip_sw = Point2::from((self.window_aspect, -1.0)) * camera_zoom;
|
||||
|
||||
for s in objects {
|
||||
self.push_object_sprite(camera_zoom, camera_pos, &mut instances, clip_ne, clip_sw, s);
|
||||
}
|
||||
|
||||
for s in ui {
|
||||
self.push_ui_sprite(&mut instances, s);
|
||||
self.push_object_sprite(
|
||||
camera_zoom,
|
||||
camera_pos,
|
||||
&mut object_instances,
|
||||
clip_ne,
|
||||
clip_sw,
|
||||
s,
|
||||
);
|
||||
}
|
||||
|
||||
// Enforce sprite limit
|
||||
if instances.len() as u64 > galactica_constants::SPRITE_INSTANCE_LIMIT {
|
||||
if object_instances.len() as u64 > galactica_constants::OBJECT_SPRITE_INSTANCE_LIMIT {
|
||||
// TODO: no panic, handle this better.
|
||||
panic!("Sprite limit exceeded!")
|
||||
}
|
||||
|
||||
return instances;
|
||||
self.queue.write_buffer(
|
||||
&self.vertex_buffers.object.instances,
|
||||
0,
|
||||
bytemuck::cast_slice(&object_instances),
|
||||
);
|
||||
|
||||
let mut ui_instances: Vec<SpriteInstance> = Vec::new();
|
||||
|
||||
for s in ui {
|
||||
self.push_ui_sprite(&mut ui_instances, s);
|
||||
}
|
||||
|
||||
if ui_instances.len() as u64 > galactica_constants::UI_SPRITE_INSTANCE_LIMIT {
|
||||
panic!("Ui sprite limit exceeded!")
|
||||
}
|
||||
|
||||
self.queue.write_buffer(
|
||||
&self.vertex_buffers.ui.instances,
|
||||
0,
|
||||
bytemuck::cast_slice(&ui_instances),
|
||||
);
|
||||
|
||||
return (object_instances.len(), ui_instances.len());
|
||||
}
|
||||
|
||||
/// Make a StarfieldInstance for each star that needs to be drawn.
|
||||
|
@ -510,13 +558,8 @@ impl GPUState {
|
|||
);
|
||||
|
||||
// Create sprite instances
|
||||
let sprite_instances =
|
||||
self.make_sprite_instances(camera_zoom, camera_pos, object_sprites, ui_sprites);
|
||||
self.queue.write_buffer(
|
||||
&self.vertex_buffers.sprite.instances,
|
||||
0,
|
||||
bytemuck::cast_slice(&sprite_instances),
|
||||
);
|
||||
let (n_object, n_ui) =
|
||||
self.update_sprite_instances(camera_zoom, camera_pos, object_sprites, ui_sprites);
|
||||
|
||||
// These should match the indices in each shader,
|
||||
// and should each have a corresponding bind group layout.
|
||||
|
@ -533,13 +576,14 @@ impl GPUState {
|
|||
);
|
||||
|
||||
// Sprite pipeline
|
||||
self.vertex_buffers.sprite.set_in_pass(&mut render_pass);
|
||||
render_pass.set_pipeline(&self.sprite_pipeline);
|
||||
render_pass.draw_indexed(
|
||||
0..SPRITE_INDICES.len() as u32,
|
||||
0,
|
||||
0..sprite_instances.len() as _,
|
||||
);
|
||||
self.vertex_buffers.object.set_in_pass(&mut render_pass);
|
||||
render_pass.set_pipeline(&self.object_pipeline);
|
||||
render_pass.draw_indexed(0..SPRITE_INDICES.len() as u32, 0, 0..n_object as _);
|
||||
|
||||
// Ui pipeline
|
||||
self.vertex_buffers.ui.set_in_pass(&mut render_pass);
|
||||
render_pass.set_pipeline(&self.ui_pipeline);
|
||||
render_pass.draw_indexed(0..SPRITE_INDICES.len() as u32, 0, 0..n_ui as _);
|
||||
|
||||
// begin_render_pass borrows encoder mutably, so we can't call finish()
|
||||
// without dropping this variable.
|
||||
|
|
|
@ -94,7 +94,7 @@ impl Starfield {
|
|||
while ((nw_tile.x * 2 + 1)
|
||||
* (nw_tile.y * 2 + 1)
|
||||
* galactica_constants::STARFIELD_COUNT as i32)
|
||||
> galactica_constants::STARFIELD_INSTANCE_LIMIT as i32
|
||||
> galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT as i32
|
||||
{
|
||||
nw_tile -= Vector2::from((1, 1));
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ impl Starfield {
|
|||
}
|
||||
|
||||
// Enforce starfield limit
|
||||
if instances.len() as u64 > galactica_constants::STARFIELD_INSTANCE_LIMIT {
|
||||
if instances.len() as u64 > galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT {
|
||||
unreachable!("Starfield limit exceeded!")
|
||||
}
|
||||
self.instance_count = instances.len() as u32;
|
||||
|
|
|
@ -33,7 +33,6 @@ pub fn build_radar(
|
|||
};
|
||||
let m = d.magnitude() / radar_range;
|
||||
let d = d / radar_range * (radar_size / 2.0);
|
||||
println!("{:?}", d);
|
||||
if m < 0.8 {
|
||||
let texture = ct.get_texture_handle("ui::radarframe");
|
||||
let dimensions = Point2 {
|
||||
|
|
Loading…
Reference in New Issue