Moved UI positioning to shaders
parent
9cd4ead368
commit
45bc3d3b41
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)]),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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>,
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue