Moved UI positioning to shaders

master
Mark 2024-01-08 17:57:49 -08:00
parent 9cd4ead368
commit 45bc3d3b41
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
8 changed files with 270 additions and 301 deletions

View File

@ -0,0 +1,41 @@
// Given an anchored position and sprite dimensions,
// return the translation that should be applied on
// vertex coordinates
fn anchor(
anchor: u32, // Anchor index
position: vec2<f32>, // Anchored position
dim: vec2<f32>, // Sprite dimensions (width, height)
) -> vec2<f32> {
var trans: vec2<f32> = vec2(0.0, 0.0);
let window_dim = global_data.window_size / global_data.window_scale.x;
if anchor == 0u { // NW C (screen anchor, sprite anchor)
trans += vec2(-window_dim.x, window_dim.y) / 2.0; // origin
trans += vec2(0.0, 0.0) / 2.0; // offset
} else if anchor == 1u { // NW NW
trans += vec2(-window_dim.x, window_dim.y) / 2.0;
trans += vec2(dim.x, -dim.y) / 2.0;
} else if anchor == 2u { // NW NE
trans += vec2(-window_dim.x, window_dim.y) / 2.0;
trans += vec2(-dim.x, -dim.y) / 2.0;
} else if anchor == 3u { // NW SW
trans += vec2(-window_dim.x, window_dim.y) / 2.0;
trans += vec2(dim.x, dim.y) / 2.0;
} else if anchor == 4u { // NW SE
trans += vec2(-window_dim.x, window_dim.y) / 2.0;
trans += vec2(-dim.x, dim.y) / 2.0;
} else if anchor == 5u { // NE NE
trans += vec2(window_dim.x, window_dim.y) / 2.0;
trans += vec2(dim.x, -dim.y) / 2.0;
} else { // center / center as default, since it's the most visible variant.
trans += vec2(0.0, 0.0);
trans += vec2(0.0, 0.0) / 2.0;
}
trans += position;
// This renders correctly, but the offsets here are off by a factor of two.
// I'm not sure why... might be because WGPU screen coordinates are -1 to 1.
return (trans / window_dim) * 2.0;
}

View File

@ -1,10 +1,10 @@
// INCLUDE: global uniform header // INCLUDE: global uniform header
struct InstanceInput { struct InstanceInput {
@location(2) transform_matrix_0: vec4<f32>, @location(2) anchor: u32,
@location(3) transform_matrix_1: vec4<f32>, @location(3) position: vec2<f32>,
@location(4) transform_matrix_2: vec4<f32>, @location(4) angle: f32,
@location(5) transform_matrix_3: vec4<f32>, @location(5) size: f32,
@location(6) color_transform: vec4<f32>, @location(6) color_transform: vec4<f32>,
@location(7) sprite_index: u32, @location(7) sprite_index: u32,
}; };
@ -28,7 +28,7 @@ var sampler_array: binding_array<sampler>;
// INCLUDE: animate.wgsl // INCLUDE: animate.wgsl
// INCLUDE: anchor.wgsl
@vertex @vertex
fn vertex_main( fn vertex_main(
@ -36,17 +36,43 @@ fn vertex_main(
instance: InstanceInput, instance: InstanceInput,
) -> VertexOutput { ) -> VertexOutput {
let transform = mat4x4<f32>(
instance.transform_matrix_0, let window_dim = global_data.window_size / global_data.window_scale.x;
instance.transform_matrix_1, let scale = instance.size / window_dim.y;
instance.transform_matrix_2, let sprite_aspect = global_sprites[instance.sprite_index].aspect;
instance.transform_matrix_3,
// Apply scale and sprite aspect
// Note that our mesh starts centered at (0, 0). This is important!
var pos: vec2<f32> = vec2(
vertex.position.x * scale * sprite_aspect,
vertex.position.y * scale
);
// Apply rotation
pos = mat2x2(
vec2(cos(instance.angle), sin(instance.angle)),
vec2(-sin(instance.angle), cos(instance.angle))
) * pos;
// Correct for screen aspect, preserving height
pos = vec2(
pos.x / global_data.window_aspect.x,
pos.y
);
pos = pos + anchor(
instance.anchor,
instance.position,
vec2(instance.size * sprite_aspect, instance.size)
); );
var out: VertexOutput; var out: VertexOutput;
out.position = transform * vec4<f32>(vertex.position, 1.0); out.position = vec4<f32>(pos, 1.0, 1.0);
out.color_transform = instance.color_transform; out.color_transform = instance.color_transform;
// TODO: animate
// Pick texture frame // Pick texture frame
let t = global_atlas[u32(animate(instance.sprite_index, global_data.current_time.x, 0.0))]; let t = global_atlas[u32(animate(instance.sprite_index, global_data.current_time.x, 0.0))];
out.texture_index = u32(t.atlas_texture); out.texture_index = u32(t.atlas_texture);

View File

@ -0,0 +1,47 @@
/// The location of a UI element, in one of a few
/// possible coordinate systems.
///
/// Positive Y always points up,
/// positive X always points right.
#[derive(Debug, Clone)]
pub enum PositionAnchor {
/// Position of this sprite's center,
/// relative to the nw corner of the window.
NwC,
/// Position of this sprite's nw corner,
/// relative to the nw corner of the window.
NwNw,
/// Position of this sprite's ne corner,
/// relative to the nw corner of the window.
NwNe,
/// Position of this sprite's sw corner,
/// relative to the nw corner of the window.
NwSw,
/// Position of this sprite's se corner,
/// relative to the nw corner of the window.
NwSe,
/// Position of this sprite's ne corner,
/// relative to the ne corner of the window.
NeNe,
}
// These offsets are implemented in wgsl shaders.
impl PositionAnchor {
/// Get the uint that represents this anchor mode in shaders
pub fn to_int(&self) -> u32 {
match self {
Self::NwC => 0,
Self::NwNw => 1,
Self::NwNe => 2,
Self::NwSw => 3,
Self::NwSe => 4,
Self::NeNe => 5,
}
}
}

View File

@ -1,11 +1,9 @@
//! GPUState routines for drawing HUD elements //! GPUState routines for drawing HUD elements
use cgmath::{Deg, InnerSpace, Point2, Vector2}; use cgmath::{Deg, InnerSpace, Point2, Rad, Vector2};
use galactica_world::util; use galactica_world::util;
use crate::{ use crate::{vertexbuffer::types::UiInstance, GPUState, PositionAnchor, RenderState};
sprite::UiSprite, vertexbuffer::types::UiInstance, AnchoredUiPosition, GPUState, RenderState,
};
impl GPUState { impl GPUState {
pub(super) fn hud_add_radar(&mut self, state: &RenderState, instances: &mut Vec<UiInstance>) { pub(super) fn hud_add_radar(&mut self, state: &RenderState, instances: &mut Vec<UiInstance>) {
@ -14,7 +12,7 @@ impl GPUState {
let hide_range = 0.85; let hide_range = 0.85;
let shrink_distance = 20.0; let shrink_distance = 20.0;
//let system_object_scale = 1.0 / 600.0; //let system_object_scale = 1.0 / 600.0;
let ship_scale = 1.0 / 15.0; let ship_scale = 1.0 / 10.0;
let (_, player_body) = state.world.get_ship_body(*state.player).unwrap(); let (_, player_body) = state.world.get_ship_body(*state.player).unwrap();
let player_position = util::rigidbody_position(player_body); let player_position = util::rigidbody_position(player_body);
@ -22,33 +20,23 @@ impl GPUState {
let ship_sprite = state.content.get_sprite_handle("ui::shipblip"); let ship_sprite = state.content.get_sprite_handle("ui::shipblip");
let arrow_sprite = state.content.get_sprite_handle("ui::centerarrow"); let arrow_sprite = state.content.get_sprite_handle("ui::centerarrow");
self.push_ui_sprite( instances.push(UiInstance {
instances, anchor: PositionAnchor::NeNe.to_int(),
&UiSprite { position: [0.0, 0.0],
sprite: state.content.get_sprite_handle("ui::status"), angle: 0.0,
pos: AnchoredUiPosition::NeNe(Point2 { x: -10.0, y: -10.0 }), size: radar_size,
dimensions: Point2 { color: [1.0, 1.0, 1.0, 1.0],
x: radar_size, sprite_index: state.content.get_sprite_handle("ui::status").get_index(),
y: radar_size, });
},
angle: Deg(0.0),
color: None,
},
);
self.push_ui_sprite( instances.push(UiInstance {
instances, anchor: PositionAnchor::NwNw.to_int(),
&UiSprite { position: [10.0, -10.0],
sprite: state.content.get_sprite_handle("ui::radar"), angle: 0.0,
pos: AnchoredUiPosition::NwNw(Point2 { x: 10.0, y: -10.0 }), size: radar_size,
dimensions: Point2 { color: [1.0, 1.0, 1.0, 1.0],
x: radar_size, sprite_index: state.content.get_sprite_handle("ui::radar").get_index(),
y: radar_size, });
},
angle: Deg(0.0),
color: None,
},
);
/* /*
// Draw system objects // Draw system objects
@ -104,24 +92,20 @@ impl GPUState {
.into(); .into();
let f = state.content.get_faction(s.ship.faction).color; let f = state.content.get_faction(s.ship.faction).color;
let f = [f[0], f[1], f[2], 1.0]; let f = [f[0], f[1], f[2], 1.0];
self.push_ui_sprite(
instances, let position = Point2 {
&UiSprite { x: radar_size / 2.0 + 10.0,
sprite: ship_sprite, y: radar_size / -2.0 - 10.0,
pos: AnchoredUiPosition::NwC( } + (d * (radar_size / 2.0));
Point2 {
x: radar_size / 2.0 + 10.0, instances.push(UiInstance {
y: radar_size / -2.0 - 10.0, anchor: PositionAnchor::NwC.to_int(),
} + (d * (radar_size / 2.0)), position: position.into(),
), angle: -Rad::from(angle).0, // TODO: consistent angles
dimensions: Point2 { size,
x: ship_sprite.aspect, color: f.into(),
y: 1.0, sprite_index: ship_sprite.get_index(),
} * size, });
angle: -angle,
color: Some(f),
},
);
} }
} }
@ -132,93 +116,83 @@ impl GPUState {
} / radar_range; } / radar_range;
let m = d.magnitude(); let m = d.magnitude();
let d = d * (radar_size / 2.0); let d = d * (radar_size / 2.0);
let color = Some([0.3, 0.3, 0.3, 1.0]); let color = [0.3, 0.3, 0.3, 1.0];
if m < 0.8 { if m < 0.8 {
let sprite = state.content.get_sprite_handle("ui::radarframe"); let sprite = state.content.get_sprite_handle("ui::radarframe");
let dimensions = Point2 { let size = 7.0f32.min((0.8 - m) * 70.0);
x: sprite.aspect,
y: 1.0,
} * 7.0f32.min((0.8 - m) * 70.0);
self.push_ui_sprite(
instances,
&UiSprite {
sprite,
pos: AnchoredUiPosition::NwNw(Point2 {
x: (radar_size / 2.0 + 10.0) - d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}),
dimensions,
angle: Deg(0.0),
color,
},
);
self.push_ui_sprite( instances.push(UiInstance {
instances, anchor: PositionAnchor::NwNw.to_int(),
&UiSprite { position: Point2 {
sprite, x: (radar_size / 2.0 + 10.0) - d.x,
pos: AnchoredUiPosition::NwSw(Point2 { y: (radar_size / -2.0 - 10.0) + d.y,
x: (radar_size / 2.0 + 10.0) - d.x, }
y: (radar_size / -2.0 - 10.0) - d.y, .into(),
}), angle: 0.0,
dimensions, size,
angle: Deg(90.0), color,
color, sprite_index: sprite.get_index(),
}, });
);
self.push_ui_sprite( instances.push(UiInstance {
instances, anchor: PositionAnchor::NwSw.to_int(),
&UiSprite { position: Point2 {
sprite, x: (radar_size / 2.0 + 10.0) - d.x,
pos: AnchoredUiPosition::NwSe(Point2 { y: (radar_size / -2.0 - 10.0) - d.y,
x: (radar_size / 2.0 + 10.0) + d.x, }
y: (radar_size / -2.0 - 10.0) - d.y, .into(),
}), angle: Rad::from(Deg(90.0)).0,
dimensions, size,
angle: Deg(180.0), color,
color, sprite_index: sprite.get_index(),
}, });
);
self.push_ui_sprite( instances.push(UiInstance {
instances, anchor: PositionAnchor::NwSe.to_int(),
&UiSprite { position: Point2 {
sprite, x: (radar_size / 2.0 + 10.0) + d.x,
pos: AnchoredUiPosition::NwNe(Point2 { y: (radar_size / -2.0 - 10.0) - d.y,
x: (radar_size / 2.0 + 10.0) + d.x, }
y: (radar_size / -2.0 - 10.0) + d.y, .into(),
}), angle: Rad::from(Deg(180.0)).0,
dimensions, size,
angle: Deg(270.0), color,
color, sprite_index: sprite.get_index(),
}, });
);
instances.push(UiInstance {
anchor: PositionAnchor::NwNe.to_int(),
position: Point2 {
x: (radar_size / 2.0 + 10.0) + d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}
.into(),
angle: Rad::from(Deg(270.0)).0,
size,
color,
sprite_index: sprite.get_index(),
});
} }
// Arrow to center of system // Arrow to center of system
let q = Point2 { x: 0.0, y: 0.0 } - player_position; let q = Point2 { x: 0.0, y: 0.0 } - player_position;
let m = q.magnitude(); let m = q.magnitude();
if m > 200.0 { if m > 200.0 {
let player_angle: Deg<f32> = q.angle(Vector2 { x: 0.0, y: 1.0 }).into(); let player_angle = q.angle(Vector2 { x: 0.0, y: 1.0 });
self.push_ui_sprite(
instances, let position: Point2<f32> = Point2 {
&UiSprite { x: radar_size / 2.0 + 10.0,
sprite: arrow_sprite, y: radar_size / -2.0 - 10.0,
pos: AnchoredUiPosition::NwC( } + ((q.normalize() * 0.865) * (radar_size / 2.0));
Point2 {
x: radar_size / 2.0 + 10.0, instances.push(UiInstance {
y: radar_size / -2.0 - 10.0, anchor: PositionAnchor::NwC.to_int(),
} + ((q.normalize() * 0.865) * (radar_size / 2.0)), position: position.into(),
), angle: -player_angle.0,
dimensions: Point2 { size: 10.0,
x: arrow_sprite.aspect, color: [1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)],
y: 1.0, sprite_index: arrow_sprite.get_index(),
} * 10.0, });
angle: -player_angle,
color: Some([1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)]),
},
);
} }
} }
} }

View File

@ -1,18 +1,17 @@
use anyhow::Result; use anyhow::Result;
use bytemuck; use bytemuck;
use cgmath::{Matrix4, Point2, Vector3}; use cgmath::Point2;
use galactica_constants; use galactica_constants;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use std::{iter, rc::Rc}; use std::{iter, rc::Rc};
use wgpu; use wgpu;
use winit::{self, dpi::LogicalSize, window::Window}; use winit::{self, window::Window};
use crate::{ use crate::{
content, content,
globaluniform::{GlobalDataContent, GlobalUniform}, globaluniform::{GlobalDataContent, GlobalUniform},
pipeline::PipelineBuilder, pipeline::PipelineBuilder,
sprite::UiSprite,
starfield::Starfield, starfield::Starfield,
texturearray::TextureArray, texturearray::TextureArray,
vertexbuffer::{ vertexbuffer::{
@ -23,7 +22,7 @@ use crate::{
}, },
BufferObject, VertexBuffer, BufferObject, VertexBuffer,
}, },
RenderState, OPENGL_TO_WGPU_MATRIX, RenderState,
}; };
// Additional implementaitons for GPUState // Additional implementaitons for GPUState
@ -94,6 +93,15 @@ fn preprocess_shader(
)), )),
); );
let shader = shader.replace(
"// INCLUDE: anchor.wgsl",
&include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/shaders/include/",
"anchor.wgsl"
)),
);
return shader; return shader;
} }
@ -337,65 +345,6 @@ impl GPUState {
self.update_starfield_buffer() self.update_starfield_buffer()
} }
// TODO:remove
/// Create a UiInstance for a ui sprite and add it to `instances`
fn push_ui_sprite(&self, instances: &mut Vec<UiInstance>, s: &UiSprite) {
let logical_size: LogicalSize<f32> =
self.window_size.to_logical(self.window.scale_factor());
let width = s.dimensions.x;
let height = s.dimensions.y;
// Compute square scale, since we must apply screen aspect ratio
// AFTER rotation.
let scale = Matrix4::from_nonuniform_scale(
width / logical_size.height,
height / logical_size.height,
1.0,
);
let rotate = Matrix4::from_angle_z(s.angle);
let translate = Matrix4::from_translation(match s.pos {
super::AnchoredUiPosition::NwC(p) => Vector3 {
// Note the signs. Positive y points north!
x: -1.0 + p.x / (logical_size.width / 2.0),
y: 1.0 + p.y / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NwNw(p) => Vector3 {
x: -1.0 + (width / 2.0 + p.x) / (logical_size.width / 2.0),
y: 1.0 - (height / 2.0 - p.y) / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NwNe(p) => Vector3 {
x: -1.0 - (width / 2.0 - p.x) / (logical_size.width / 2.0),
y: 1.0 - (height / 2.0 - p.y) / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NwSw(p) => Vector3 {
x: -1.0 + (width / 2.0 + p.x) / (logical_size.width / 2.0),
y: 1.0 + (height / 2.0 + p.y) / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NwSe(p) => Vector3 {
x: -1.0 - (width / 2.0 - p.x) / (logical_size.width / 2.0),
y: 1.0 + (height / 2.0 + p.y) / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NeNe(p) => Vector3 {
x: 1.0 - (width / 2.0 - p.x) / (logical_size.width / 2.0),
y: 1.0 - (height / 2.0 - p.y) / (logical_size.height / 2.0),
z: 0.0,
},
});
let screen_aspect = Matrix4::from_nonuniform_scale(1.0 / self.window_aspect, 1.0, 1.0);
instances.push(UiInstance {
transform: (OPENGL_TO_WGPU_MATRIX * translate * screen_aspect * rotate * scale).into(),
sprite_index: s.sprite.get_index(),
color: s.color.unwrap_or([1.0, 1.0, 1.0, 1.0]),
});
}
/// Make an instance for all the game's sprites /// Make an instance for all the game's sprites
/// (Objects and UI) /// (Objects and UI)
/// This will Will panic if any X_SPRITE_INSTANCE_LIMIT is exceeded. /// This will Will panic if any X_SPRITE_INSTANCE_LIMIT is exceeded.
@ -637,7 +586,7 @@ impl GPUState {
]), ]),
);*/ );*/
// Ui pipeline // Radial progress bar
// TODO: do we need to do this every time? // TODO: do we need to do this every time?
self.vertex_buffers.radialbar.set_in_pass(&mut render_pass); self.vertex_buffers.radialbar.set_in_pass(&mut render_pass);
render_pass.set_pipeline(&self.radialbar_pipeline); render_pass.set_pipeline(&self.radialbar_pipeline);

View File

@ -7,19 +7,19 @@
//! and the only one external code should interact with. //! and the only one external code should interact with.
//! (Excluding data structs, like [`ObjectSprite`]) //! (Excluding data structs, like [`ObjectSprite`])
mod anchoredposition;
mod globaluniform; mod globaluniform;
mod gpustate; mod gpustate;
mod pipeline; mod pipeline;
mod renderstate; mod renderstate;
mod sprite;
mod starfield; mod starfield;
mod texturearray; mod texturearray;
mod vertexbuffer; mod vertexbuffer;
pub use anchoredposition::PositionAnchor;
use galactica_content as content; use galactica_content as content;
pub use gpustate::GPUState; pub use gpustate::GPUState;
pub use renderstate::RenderState; pub use renderstate::RenderState;
pub use sprite::AnchoredUiPosition;
use cgmath::Matrix4; use cgmath::Matrix4;

View File

@ -1,79 +0,0 @@
use crate::content;
use cgmath::{Deg, Point2};
/// The location of a UI element, in one of a few
/// possible coordinate systems.
///
/// Positive Y always points up,
/// positive X always points right.
#[derive(Debug, Clone)]
pub enum AnchoredUiPosition {
/// Position of this sprite's center,
/// relative to the nw corner of the window.
NwC(Point2<f32>),
/// Position of this sprite's nw corner,
/// relative to the nw corner of the window.
NwNw(Point2<f32>),
/// Position of this sprite's ne corner,
/// relative to the nw corner of the window.
NwNe(Point2<f32>),
/// Position of this sprite's sw corner,
/// relative to the nw corner of the window.
NwSw(Point2<f32>),
/// Position of this sprite's se corner,
/// relative to the nw corner of the window.
NwSe(Point2<f32>),
/// Position of this sprite's ne corner,
/// relative to the ne corner of the window.
NeNe(Point2<f32>),
}
impl AnchoredUiPosition {
pub fn to_anchor_int(&self) -> u32 {
match self {
Self::NwC(_) => 0,
Self::NwNw(_) => 1,
Self::NwNe(_) => 2,
Self::NwSw(_) => 3,
Self::NwSe(_) => 4,
Self::NeNe(_) => 5,
}
}
pub fn position(&self) -> &Point2<f32> {
match self {
Self::NwC(x)
| Self::NwNw(x)
| Self::NwNe(x)
| Self::NwSw(x)
| Self::NwSe(x)
| Self::NeNe(x) => x,
}
}
}
// TODO: remove
/// A sprite that represents a ui element
#[derive(Debug, Clone)]
pub struct UiSprite {
/// The sprite to draw
pub sprite: content::SpriteHandle,
/// This object's position, in logical (dpi-adjusted) pixels
pub pos: AnchoredUiPosition,
/// This sprite's color will be multiplied by this value.
/// If this is None, color will not be changed.
pub color: Option<[f32; 4]>,
/// The size of this sprite, in logical (dpi-adjusted) pixels
pub dimensions: Point2<f32>,
/// This sprite's rotation, measured ccw
pub angle: Deg<f32>,
}

View File

@ -120,10 +120,18 @@ impl BufferObject for ObjectInstance {
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct UiInstance { pub struct UiInstance {
/// Extra transformations this sprite /// How to interpret this object's coordinates.
/// (rotation, etc) /// this should be generated from an AnchoredUiPosition
/// TODO: remove pub anchor: u32,
pub transform: [[f32; 4]; 4],
/// Position of this object in logical pixels
pub position: [f32; 2],
/// The angle of this sprite, in radians
pub angle: f32,
/// The height of this sprite, in logical pixels
pub size: f32,
/// This lets us color ui sprites dynamically. /// This lets us color ui sprites dynamically.
/// Each fragment's color is multiplied by this value. /// Each fragment's color is multiplied by this value.
@ -143,36 +151,39 @@ impl BufferObject for UiInstance {
// instance when the shader starts processing a new instance // instance when the shader starts processing a new instance
step_mode: wgpu::VertexStepMode::Instance, step_mode: wgpu::VertexStepMode::Instance,
attributes: &[ attributes: &[
// 4 arrays = 1 4x4 matrix // Anchor
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: 0, offset: 0,
shader_location: 2, shader_location: 2,
format: wgpu::VertexFormat::Float32x4, format: wgpu::VertexFormat::Uint32,
}, },
// Position
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 1]>() as wgpu::BufferAddress,
shader_location: 3,
format: wgpu::VertexFormat::Float32x2,
},
// Angle
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
shader_location: 4,
format: wgpu::VertexFormat::Float32,
},
// Size
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress, offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
shader_location: 3,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
shader_location: 4,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
shader_location: 5, shader_location: 5,
format: wgpu::VertexFormat::Float32x4, format: wgpu::VertexFormat::Float32,
}, },
// Color // Color
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 16]>() as wgpu::BufferAddress, offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress,
shader_location: 6, shader_location: 6,
format: wgpu::VertexFormat::Float32x4, format: wgpu::VertexFormat::Float32x4,
}, },
// Sprite // Sprite
wgpu::VertexAttribute { wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 20]>() as wgpu::BufferAddress, offset: mem::size_of::<[f32; 9]>() as wgpu::BufferAddress,
shader_location: 7, shader_location: 7,
format: wgpu::VertexFormat::Uint32, format: wgpu::VertexFormat::Uint32,
}, },
@ -286,7 +297,7 @@ pub struct RadialBarInstance {
/// this should be generated from an AnchoredUiPosition /// this should be generated from an AnchoredUiPosition
pub anchor: u32, pub anchor: u32,
/// Position of this particle in logical pixels /// Position of this object in logical pixels
pub position: [f32; 2], pub position: [f32; 2],
/// The diameter of this bar, in logical pixels /// The diameter of this bar, in logical pixels