Added dynamic radar colors
parent
2e6f79ea31
commit
381dd4a383
2
TODO.md
2
TODO.md
|
@ -4,7 +4,7 @@
|
|||
- Sound system
|
||||
- Particles, impact effects
|
||||
- Debris on ship death
|
||||
- Radar: dynamic colors, size, planets and suns
|
||||
- Radar: ship size, planets and suns
|
||||
|
||||
----------------------------------
|
||||
|
||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit 91377416617d049acec68bb5a17647dcac7acd0e
|
||||
Subproject commit 62fd7fc297a2631691b588b898694e220d58cf78
|
|
@ -1,7 +1,9 @@
|
|||
[faction."player"]
|
||||
display_name = "Player"
|
||||
relationship.enemy = "hostile"
|
||||
color = [0.0, 1.0, 0.0]
|
||||
|
||||
[faction."enemy"]
|
||||
display_name = "Enemy"
|
||||
relationship.player = "hostile"
|
||||
color = [1.0, 0.0, 0.0]
|
||||
|
|
|
@ -14,6 +14,7 @@ pub(crate) mod syntax {
|
|||
#[derive(Debug, Deserialize)]
|
||||
pub struct Faction {
|
||||
pub display_name: String,
|
||||
pub color: [f32; 3],
|
||||
pub relationship: HashMap<String, super::Relationship>,
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +46,10 @@ pub struct Faction {
|
|||
/// The name of this faction
|
||||
pub name: String,
|
||||
|
||||
/// This faction's color.
|
||||
/// Format is RGB, with each color between 0 and 1.
|
||||
pub color: [f32; 3],
|
||||
|
||||
/// This faction's handle
|
||||
pub handle: FactionHandle,
|
||||
|
||||
|
@ -98,6 +103,7 @@ impl crate::Build for Faction {
|
|||
name: faction_name.to_owned(),
|
||||
handle: h,
|
||||
relationships,
|
||||
color: faction.color,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@ struct InstanceInput {
|
|||
@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,
|
||||
@location(6) color_transform: vec4<f32>,
|
||||
@location(7) texture_idx: u32,
|
||||
};
|
||||
|
||||
struct VertexInput {
|
||||
|
@ -15,6 +16,7 @@ struct VertexOutput {
|
|||
@builtin(position) position: vec4<f32>,
|
||||
@location(0) texture_coords: vec2<f32>,
|
||||
@location(1) index: u32,
|
||||
@location(2) color_transform: vec4<f32>,
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,6 +59,7 @@ fn vertex_main(
|
|||
out.position = transform * vec4<f32>(vertex.position, 1.0);
|
||||
out.texture_coords = vertex.texture_coords;
|
||||
out.index = instance.texture_idx;
|
||||
out.color_transform = instance.color_transform;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -68,5 +71,5 @@ fn fragment_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|||
sampler_array[0],
|
||||
in.texture_coords,
|
||||
0.0
|
||||
).rgba;
|
||||
).rgba * in.color_transform;
|
||||
}
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
texturearray::TextureArray,
|
||||
vertexbuffer::{
|
||||
consts::{SPRITE_INDICES, SPRITE_VERTICES},
|
||||
types::{SpriteInstance, StarfieldInstance, TexturedVertex},
|
||||
types::{ObjectInstance, StarfieldInstance, TexturedVertex, UiInstance},
|
||||
VertexBuffer,
|
||||
},
|
||||
ObjectSprite, UiSprite, OPENGL_TO_WGPU_MATRIX,
|
||||
|
@ -119,7 +119,7 @@ impl GPUState {
|
|||
}
|
||||
|
||||
let vertex_buffers = VertexBuffers {
|
||||
object: Rc::new(VertexBuffer::new::<TexturedVertex, SpriteInstance>(
|
||||
object: Rc::new(VertexBuffer::new::<TexturedVertex, ObjectInstance>(
|
||||
"objecte",
|
||||
&device,
|
||||
Some(SPRITE_VERTICES),
|
||||
|
@ -135,7 +135,7 @@ impl GPUState {
|
|||
galactica_constants::STARFIELD_SPRITE_INSTANCE_LIMIT,
|
||||
)),
|
||||
|
||||
ui: Rc::new(VertexBuffer::new::<TexturedVertex, SpriteInstance>(
|
||||
ui: Rc::new(VertexBuffer::new::<TexturedVertex, UiInstance>(
|
||||
"ui",
|
||||
&device,
|
||||
Some(SPRITE_VERTICES),
|
||||
|
@ -234,13 +234,13 @@ impl GPUState {
|
|||
self.update_starfield_buffer()
|
||||
}
|
||||
|
||||
/// Create a SpriteInstance for an object and add it to `instances`.
|
||||
/// Create a ObjectInstance for an object and add it to `instances`.
|
||||
/// Also handles child sprites.
|
||||
fn push_object_sprite(
|
||||
&self,
|
||||
camera_zoom: f32,
|
||||
camera_pos: Point2<f32>,
|
||||
instances: &mut Vec<SpriteInstance>,
|
||||
instances: &mut Vec<ObjectInstance>,
|
||||
clip_ne: Point2<f32>,
|
||||
clip_sw: Point2<f32>,
|
||||
s: &ObjectSprite,
|
||||
|
@ -314,7 +314,7 @@ impl GPUState {
|
|||
let t =
|
||||
OPENGL_TO_WGPU_MATRIX * translate * screen_aspect * rotate * sprite_aspect_and_scale;
|
||||
|
||||
instances.push(SpriteInstance {
|
||||
instances.push(ObjectInstance {
|
||||
transform: t.into(),
|
||||
texture_index: texture.index,
|
||||
});
|
||||
|
@ -332,7 +332,7 @@ impl GPUState {
|
|||
fn push_object_subsprite(
|
||||
&self,
|
||||
camera_zoom: f32,
|
||||
instances: &mut Vec<SpriteInstance>,
|
||||
instances: &mut Vec<ObjectInstance>,
|
||||
s: &ObjectSubSprite,
|
||||
parent_pos: Point2<f32>,
|
||||
parent_angle: Deg<f32>,
|
||||
|
@ -364,14 +364,14 @@ impl GPUState {
|
|||
* protate * translate
|
||||
* rotate * sprite_aspect_and_scale;
|
||||
|
||||
instances.push(SpriteInstance {
|
||||
instances.push(ObjectInstance {
|
||||
transform: t.into(),
|
||||
texture_index: texture.index,
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a SpriteInstance for a ui sprite and add it to `instances`
|
||||
fn push_ui_sprite(&self, instances: &mut Vec<SpriteInstance>, s: &UiSprite) {
|
||||
/// Create a ObjectInstance 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());
|
||||
|
||||
|
@ -417,16 +417,16 @@ impl GPUState {
|
|||
});
|
||||
let screen_aspect = Matrix4::from_nonuniform_scale(1.0 / self.window_aspect, 1.0, 1.0);
|
||||
|
||||
instances.push(SpriteInstance {
|
||||
instances.push(UiInstance {
|
||||
transform: (OPENGL_TO_WGPU_MATRIX * translate * screen_aspect * rotate * scale).into(),
|
||||
texture_index: texture.index,
|
||||
color: s.color.unwrap_or([1.0, 1.0, 1.0, 1.0]),
|
||||
});
|
||||
}
|
||||
|
||||
/// Make a SpriteInstance for each of the game's visible sprites.
|
||||
/// Will panic if SPRITE_INSTANCE_LIMIT is exceeded.
|
||||
///
|
||||
/// This is only called inside self.render()
|
||||
/// Make an instance for all the game's sprites
|
||||
/// (Objects and UI)
|
||||
/// This will Will panic if any X_SPRITE_INSTANCE_LIMIT is exceeded.
|
||||
fn update_sprite_instances(
|
||||
&self,
|
||||
camera_zoom: f32,
|
||||
|
@ -434,7 +434,7 @@ impl GPUState {
|
|||
objects: &Vec<ObjectSprite>,
|
||||
ui: &Vec<UiSprite>,
|
||||
) -> (usize, usize) {
|
||||
let mut object_instances: Vec<SpriteInstance> = Vec::new();
|
||||
let mut object_instances: Vec<ObjectInstance> = Vec::new();
|
||||
|
||||
// Game coordinates (relative to camera) of ne and sw corners of screen.
|
||||
// Used to skip off-screen sprites.
|
||||
|
@ -464,7 +464,7 @@ impl GPUState {
|
|||
bytemuck::cast_slice(&object_instances),
|
||||
);
|
||||
|
||||
let mut ui_instances: Vec<SpriteInstance> = Vec::new();
|
||||
let mut ui_instances: Vec<UiInstance> = Vec::new();
|
||||
|
||||
for s in ui {
|
||||
self.push_ui_sprite(&mut ui_instances, s);
|
||||
|
|
|
@ -38,6 +38,10 @@ pub struct UiSprite {
|
|||
/// 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>,
|
||||
|
||||
|
|
|
@ -81,19 +81,18 @@ impl BufferObject for StarfieldInstance {
|
|||
}
|
||||
}
|
||||
|
||||
// Represents a sprite instance in WGSL
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct SpriteInstance {
|
||||
pub struct ObjectInstance {
|
||||
/// Extra transformations this sprite
|
||||
/// (rotation, etc)
|
||||
pub transform: [[f32; 4]; 4],
|
||||
|
||||
// What texture to use for this sprite
|
||||
/// What texture to use for this sprite
|
||||
pub texture_index: u32,
|
||||
}
|
||||
|
||||
impl BufferObject for SpriteInstance {
|
||||
impl BufferObject for ObjectInstance {
|
||||
fn layout() -> wgpu::VertexBufferLayout<'static> {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: Self::SIZE,
|
||||
|
@ -133,3 +132,66 @@ impl BufferObject for SpriteInstance {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct UiInstance {
|
||||
/// Extra transformations this sprite
|
||||
/// (rotation, etc)
|
||||
pub transform: [[f32; 4]; 4],
|
||||
|
||||
/// This lets us color ui sprites dynamically.
|
||||
/// Each fragment's color is multiplied by this value.
|
||||
/// Fill this array with ones if no recoloring should be done.
|
||||
pub color: [f32; 4],
|
||||
|
||||
/// What texture to use for this sprite
|
||||
pub texture_index: u32,
|
||||
}
|
||||
|
||||
impl BufferObject for UiInstance {
|
||||
fn layout() -> wgpu::VertexBufferLayout<'static> {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: Self::SIZE,
|
||||
// Switch to a step mode of Vertex to Instance.
|
||||
// This means that our shaders will only change to use the next
|
||||
// instance when the shader starts processing a new instance
|
||||
step_mode: wgpu::VertexStepMode::Instance,
|
||||
attributes: &[
|
||||
// 4 arrays = 1 4x4 matrix
|
||||
wgpu::VertexAttribute {
|
||||
offset: 0,
|
||||
shader_location: 2,
|
||||
format: wgpu::VertexFormat::Float32x4,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
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,
|
||||
format: wgpu::VertexFormat::Float32x4,
|
||||
},
|
||||
// Color
|
||||
wgpu::VertexAttribute {
|
||||
offset: mem::size_of::<[f32; 16]>() as wgpu::BufferAddress,
|
||||
shader_location: 6,
|
||||
format: wgpu::VertexFormat::Float32x4,
|
||||
},
|
||||
// Texture
|
||||
wgpu::VertexAttribute {
|
||||
offset: mem::size_of::<[f32; 20]>() as wgpu::BufferAddress,
|
||||
shader_location: 7,
|
||||
format: wgpu::VertexFormat::Uint32,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ pub fn build_radar(
|
|||
y: radar_size,
|
||||
},
|
||||
angle: Deg(0.0),
|
||||
color: None,
|
||||
});
|
||||
|
||||
// Draw viewport frame
|
||||
|
@ -33,6 +34,7 @@ pub fn build_radar(
|
|||
};
|
||||
let m = d.magnitude() / radar_range;
|
||||
let d = d / radar_range * (radar_size / 2.0);
|
||||
let color = Some([0.5, 0.5, 0.5, 1.0]);
|
||||
if m < 0.8 {
|
||||
let texture = ct.get_texture_handle("ui::radarframe");
|
||||
let dimensions = Point2 {
|
||||
|
@ -47,6 +49,7 @@ pub fn build_radar(
|
|||
}),
|
||||
dimensions,
|
||||
angle: Deg(0.0),
|
||||
color,
|
||||
});
|
||||
|
||||
out.push(UiSprite {
|
||||
|
@ -57,6 +60,7 @@ pub fn build_radar(
|
|||
}),
|
||||
dimensions,
|
||||
angle: Deg(90.0),
|
||||
color,
|
||||
});
|
||||
|
||||
out.push(UiSprite {
|
||||
|
@ -67,6 +71,7 @@ pub fn build_radar(
|
|||
}),
|
||||
dimensions,
|
||||
angle: Deg(180.0),
|
||||
color,
|
||||
});
|
||||
|
||||
out.push(UiSprite {
|
||||
|
@ -77,6 +82,7 @@ pub fn build_radar(
|
|||
}),
|
||||
dimensions,
|
||||
angle: Deg(270.0),
|
||||
color,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -87,23 +93,13 @@ pub fn build_radar(
|
|||
let p = util::rigidbody_position(r);
|
||||
let d = p - pr;
|
||||
let m = d.magnitude() / radar_range;
|
||||
if m < 0.8 {
|
||||
let angle: Deg<f32> = util::rigidbody_rotation(r)
|
||||
.angle(Vector2 { x: 0.0, y: 1.0 })
|
||||
.into();
|
||||
if s.physics_handle == *player {
|
||||
out.push(UiSprite {
|
||||
texture,
|
||||
pos: AnchoredUiPosition::NwC(Point2 {
|
||||
x: radar_size / 2.0 + 10.0,
|
||||
y: radar_size / -2.0 - 10.0,
|
||||
}),
|
||||
dimensions: Point2 {
|
||||
x: texture.aspect,
|
||||
y: 1.0,
|
||||
} * 5.0f32.min((0.8 - m) * 50.0),
|
||||
angle: -angle,
|
||||
});
|
||||
} else if m < 0.8 {
|
||||
let f = ct.get_faction(s.ship.faction).color;
|
||||
let f = [f[0], f[1], f[2], 1.0];
|
||||
|
||||
out.push(UiSprite {
|
||||
texture,
|
||||
pos: AnchoredUiPosition::NwC(
|
||||
|
@ -117,6 +113,7 @@ pub fn build_radar(
|
|||
y: 1.0,
|
||||
} * 5.0f32.min((0.8 - m) * 50.0),
|
||||
angle: -angle,
|
||||
color: Some(f),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ impl Game {
|
|||
let s = object::Ship::new(
|
||||
&ct,
|
||||
content::ShipHandle { index: 0 },
|
||||
// This method of specifying factions is non-deterministic,
|
||||
// but that's ok since this is for debug.
|
||||
// TODO: fix
|
||||
content::FactionHandle { index: 0 },
|
||||
object::OutfitSet::new(ss),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue