Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Beacon to Utilities #13

Merged
merged 3 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
- Add Global Utility Objects by @Froggy618167725 in [#12](https://github.com/cohaereo/alkahest/pull/12)
- Lazy entity updating by @cohaereo
- Global entity tag by @cohaereo
- Add Beacon Utility tool by @Froggy618157725 in [#13](https://github.com/cohaereo/alkahest/pull/13)

### Changed

Expand Down
37 changes: 33 additions & 4 deletions src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{

#[derive(Clone)]
pub struct FpsCamera {
orientation: Vec2,
pub orientation: Vec2,
pub rotation: Quat,

pub front: Vec3,
Expand Down Expand Up @@ -70,6 +70,14 @@ impl FpsCamera {

pub fn update_mouse(&mut self, mouse_delta: Vec2) {
self.orientation += Vec2::new(mouse_delta.y * 0.8, mouse_delta.x) * 0.15;
// Cancel angle tween if the user rotates the camera
if self
.tween
.as_ref()
.map_or(false, |t| t.angle_movement.is_some())
{
self.tween = None;
}
self.update_vectors();
}

Expand Down Expand Up @@ -145,7 +153,8 @@ impl FpsCamera {
}

if let Some(tween) = &mut self.tween {
self.position = tween.update();
self.position = tween.update_pos().unwrap_or(self.position);
self.orientation = tween.update_angle().unwrap_or(self.orientation);
} else {
self.position += direction * speed;
}
Expand Down Expand Up @@ -297,8 +306,8 @@ impl FpsCamera {
pub fn focus(&mut self, pos: Vec3, distance: f32) {
self.tween = Some(Tween::new(
tween::ease_out_exponential,
self.position,
pos - self.front * distance,
Some((self.position, pos - self.front * distance)),
None,
0.70,
));
}
Expand All @@ -309,4 +318,24 @@ impl FpsCamera {

self.focus(center, radius);
}

// Calculate angle to point camera at pos.
// The angle has a minimal diff to current camera angle.
pub fn get_look_angle(&self, pos: Vec3) -> Vec2 {
let dir = pos - self.position;
let inv_r = dir.length_recip();
if inv_r.is_infinite() {
self.orientation
} else {
let theta = dir.x.atan2(dir.y).to_degrees();
let mut diff = (theta - self.orientation.y).rem_euclid(360.0);
if diff > 180.0 {
diff -= 360.0;
}
Vec2::new(
(dir.z * inv_r).acos().to_degrees() - 90.0,
self.orientation.y + diff,
)
}
}
}
115 changes: 109 additions & 6 deletions src/ecs/component_panels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ use crate::{
ecs::transform::TransformFlags,
hotkeys::{SHORTCUT_DELETE, SHORTCUT_HIDE},
icons::{
ICON_ALERT, ICON_ALPHA_A_BOX, ICON_ALPHA_B_BOX, ICON_AXIS_ARROW, ICON_CAMERA_CONTROL,
ICON_CUBE_OUTLINE, ICON_DELETE, ICON_EYE, ICON_EYE_OFF, ICON_HELP, ICON_IDENTIFIER,
ICON_MAP_MARKER, ICON_RADIUS_OUTLINE, ICON_RESIZE, ICON_ROTATE_ORBIT, ICON_RULER_SQUARE,
ICON_SPHERE, ICON_TAG,
ICON_ALERT, ICON_ALPHA_A_BOX, ICON_ALPHA_B_BOX, ICON_AXIS_ARROW, ICON_CAMERA,
ICON_CAMERA_CONTROL, ICON_CUBE_OUTLINE, ICON_DELETE, ICON_EYE, ICON_EYE_OFF, ICON_HELP,
ICON_IDENTIFIER, ICON_MAP_MARKER, ICON_RADIUS_OUTLINE, ICON_RESIZE, ICON_ROTATE_ORBIT,
ICON_RULER_SQUARE, ICON_SIGN_POLE, ICON_SPHERE, ICON_TAG,
},
render::tween::Tween,
resources::Resources,
util::{
text::{prettify_distance, split_pascal_case},
Expand All @@ -21,7 +22,7 @@ use crate::{

use super::{
components::{
EntityModel, EntityWorldId, Global, Label, Mutable, ResourcePoint, Ruler, Sphere,
Beacon, EntityModel, EntityWorldId, Global, Label, Mutable, ResourcePoint, Ruler, Sphere,
StaticInstances, Visible,
},
resolve_entity_icon, resolve_entity_name,
Expand Down Expand Up @@ -170,7 +171,8 @@ fn show_inspector_components(ui: &mut egui::Ui, e: EntityRef<'_>, resources: &Re
// HavokShape,
EntityWorldId,
Ruler,
Sphere
Sphere,
Beacon
);
}

Expand Down Expand Up @@ -589,3 +591,104 @@ impl ComponentPanel for Sphere {
});
}
}

impl ComponentPanel for Beacon {
fn inspector_name() -> &'static str {
"Beacon"
}

fn inspector_icon() -> char {
ICON_SIGN_POLE
}

fn has_inspector_ui() -> bool {
true
}

fn show_inspector_ui(&mut self, e: EntityRef<'_>, ui: &mut egui::Ui, resources: &Resources) {
if !e.has::<Transform>() {
ui.label(format!(
"{} This entity has no transform component",
ICON_ALERT
));
}

ui.horizontal(|ui| {
ui.strong("Distance after travel: ");
ui.add(
egui::DragValue::new(&mut self.distance)
.speed(0.1)
.clamp_range(0f32..=f32::INFINITY)
.min_decimals(2)
.max_decimals(2)
.suffix(" m"),
)
});

ui.horizontal(|ui| {
ui.strong("Duration of travel: ");
ui.add(
egui::DragValue::new(&mut self.travel_time)
.speed(0.1)
.clamp_range(0f32..=60.0)
.min_decimals(2)
.max_decimals(2)
.suffix(" s"),
)
});

ui.horizontal(|ui| {
ui.strong("Blink Frequency");
ui.add(
egui::DragValue::new(&mut self.freq)
.speed(0.1)
.clamp_range(0.0..=20.0),
)
});

ui.horizontal(|ui| {
ui.color_edit_button_srgb(&mut self.color);

ui.label("Color");
});

ui.separator();

let mut camera = resources.get_mut::<FpsCamera>().unwrap();
if let Some(transform) = e.get::<&Transform>() {
ui.label(format!(
"Distance to Beacon: {:.2} m",
(transform.translation - camera.position).length()
));

ui.horizontal(|ui| {
if ui.button(ICON_MAP_MARKER.to_string()).clicked() {
camera.tween = Some(Tween::new(
|x| x,
Some((
camera.position,
transform.translation - camera.front * self.distance,
)),
None,
self.travel_time,
));
}
ui.label("Go to Beacon Location");
});
ui.horizontal(|ui| {
if ui.button(ICON_CAMERA.to_string()).clicked() {
camera.tween = Some(Tween::new(
|x| x,
None,
Some((
camera.orientation,
camera.get_look_angle(transform.translation),
)),
self.travel_time,
));
}
ui.label("Look at Beacon Location");
});
}
}
}
18 changes: 18 additions & 0 deletions src/ecs/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,24 @@ impl Default for Sphere {
}
}
}

pub struct Beacon {
pub color: [u8; 3],
pub freq: f32,
pub distance: f32,
pub travel_time: f32,
}

impl Default for Beacon {
fn default() -> Self {
Self {
color: [255, 255, 255],
freq: 1.0,
distance: 0.5,
travel_time: 0.7,
}
}
}
/// Marker component to indicate that the entity is allowed to be modified in potentially destructive ways
/// (e.g. deleting it, changing it's name, etc.)
pub struct Mutable;
3 changes: 2 additions & 1 deletion src/ecs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub fn resolve_entity_icon(e: EntityRef<'_>) -> Option<char> {
icon_from_component_panels!(
// TODO(cohae): Custom havok icon
// HavokShape,
Beacon,
Ruler,
Sphere,
EntityModel,
Expand Down Expand Up @@ -66,7 +67,7 @@ pub fn resolve_entity_name(e: EntityRef<'_>, append_ent: bool) -> String {
};
}

name_from_component_panels!(Ruler, Sphere, EntityModel, StaticInstances);
name_from_component_panels!(Beacon, Ruler, Sphere, EntityModel, StaticInstances);

format!("ent {}", e.entity().id())
}
Expand Down
34 changes: 32 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ use std::time::{Duration, Instant};

use crate::activity::SActivity;
use crate::ecs::components::{
ActivityGroup, EntityModel, ResourcePoint, Ruler, Sphere, StaticInstances, Terrain, Visible,
Water,
ActivityGroup, Beacon, EntityModel, ResourcePoint, Ruler, Sphere, StaticInstances, Terrain,
Visible, Water,
};
use crate::ecs::resolve_aabb;
use crate::ecs::resources::SelectedEntity;
Expand Down Expand Up @@ -853,6 +853,16 @@ pub async fn main() -> anyhow::Result<()> {
}
draw_sphere(&mut debugshapes, transform, sphere, start_time);
}
for (_, (transform, beacon, visible)) in map
.scene
.query::<(&Transform, &Beacon, Option<&Visible>)>()
.iter()
{
if !visible.map_or(true, |v| v.0) {
continue;
}
draw_beacon(&mut debugshapes, transform, beacon, start_time);
}
}

if let Some(map) = maps.current_map_mut() {
Expand Down Expand Up @@ -1106,6 +1116,26 @@ fn draw_sphere(
debugshapes.sphere(transform.translation, transform.radius(), color);
}

fn draw_beacon(
debugshapes: &mut DebugShapes,
transform: &Transform,
beacon: &Beacon,
start_time: Instant,
) {
let color = [
beacon.color[0],
beacon.color[1],
beacon.color[2],
(150.0 + (start_time.elapsed().as_secs_f32() * 2.0 * PI * beacon.freq).sin() * 50.0) as u8,
];
debugshapes.sphere(transform.translation, 0.1, color);
debugshapes.line(
transform.translation + Vec3::Z * 0.1,
transform.translation + Vec3::Z * 5000.0,
color,
);
}

fn load_render_globals(renderer: &Renderer) {
let tag =
get_named_tag::<0x8080978C>("render_globals").expect("Could not find render globals!");
Expand Down
32 changes: 29 additions & 3 deletions src/overlays/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ use glam::Vec3;
use crate::{
camera::FpsCamera,
ecs::{
components::{Mutable, Ruler, Sphere},
components::{Beacon, Mutable, Ruler, Sphere},
resources::SelectedEntity,
tags::{EntityTag, Tags},
transform::{Transform, TransformFlags},
},
icons::ICON_RULER_SQUARE,
icons::ICON_SPHERE,
icons::{ICON_RULER_SQUARE, ICON_SIGN_POLE, ICON_SPHERE},
map::MapDataList,
};

Expand Down Expand Up @@ -74,6 +73,33 @@ impl Overlay for MenuBar {
se.0 = Some(e);
}

ui.close_menu();
}
}
if ui.button(format!("{} Beacon", ICON_SIGN_POLE)).clicked() {
let mut maps: std::cell::RefMut<'_, MapDataList> =
resources.get_mut::<MapDataList>().unwrap();

if let Some(map) = maps.current_map_mut() {
let camera = resources.get::<FpsCamera>().unwrap();
let e = map.scene.spawn((
Transform {
translation: camera.position,
flags: TransformFlags::IGNORE_ROTATION
| TransformFlags::IGNORE_SCALE,
..Default::default()
},
Beacon {
..Default::default()
},
Tags::from_iter([EntityTag::Utility]),
Mutable,
));

if let Some(mut se) = resources.get_mut::<SelectedEntity>() {
se.0 = Some(e);
}

ui.close_menu();
}
}
Expand Down
Loading