4667c90
· Thribhu K
fix: fixed some editor and project settings stuff, which means HistoricalOption was implemented as a new type.
Unverified
diff --git a/.sdkmanrc b/.sdkmanrc
new file mode 100644
index 0000000..5a6900d
--- /dev/null
+++ b/.sdkmanrc
@@ -0,0 +1,3 @@
+# Enable auto-env through the sdkman_auto_env config
+# Add key=value pairs of SDKs to use below
+java=21.0.9-tem
diff --git a/dropbear-engine/src/lib.rs b/dropbear-engine/src/lib.rs
index 20e5cd0..f9f6107 100644
--- a/dropbear-engine/src/lib.rs
+++ b/dropbear-engine/src/lib.rs
@@ -931,6 +931,9 @@ impl ApplicationHandler for App {
self.windows.remove(&target_window_id);
}
}
+ scene::SceneCommand::SetFPS(new_fps) => {
+ self.set_target_fps(new_fps);
+ }
_ => {}
}
}
diff --git a/dropbear-engine/src/scene.rs b/dropbear-engine/src/scene.rs
index 21647b8..9058d3e 100644
--- a/dropbear-engine/src/scene.rs
+++ b/dropbear-engine/src/scene.rs
@@ -33,6 +33,7 @@ pub enum SceneCommand {
DebugMessage(String),
RequestWindow(WindowData),
CloseWindow(WindowId),
+ SetFPS(u32),
}
impl Default for SceneCommand {
@@ -145,7 +146,7 @@ impl Manager {
}
SceneCommand::None => {}
SceneCommand::DebugMessage(msg) => log::debug!("{}", msg),
- SceneCommand::RequestWindow(_) | SceneCommand::CloseWindow(_) => {
+ SceneCommand::RequestWindow(_) | SceneCommand::CloseWindow(_) | SceneCommand::SetFPS(_) => {
return vec![command];
}
}
diff --git a/eucalyptus-core/src/runtime.rs b/eucalyptus-core/src/runtime.rs
index e2cceee..9532ce5 100644
--- a/eucalyptus-core/src/runtime.rs
+++ b/eucalyptus-core/src/runtime.rs
@@ -4,6 +4,7 @@ use crate::scene::SceneConfig;
use crate::states::{PROJECT, SCENES};
use anyhow::Context;
use semver::Version;
+use crate::utils::option::HistoricalOption;
/// The settings of a project in its runtime.
///
@@ -16,8 +17,10 @@ pub struct RuntimeSettings {
///
/// The first scene is not set is expected to be the first scene out of the
/// projects scene list, or just a normal anyhow error.
+ #[serde(default)]
pub initial_scene: Option<String>,
- pub target_fps: u32,
+ #[serde(default)]
+ pub target_fps: HistoricalOption<u32>,
}
impl RuntimeSettings {
@@ -25,7 +28,7 @@ impl RuntimeSettings {
pub fn new() -> Self {
Self {
initial_scene: None,
- target_fps: u32::MAX,
+ target_fps: HistoricalOption::none(),
}
}
}
diff --git a/eucalyptus-core/src/utils.rs b/eucalyptus-core/src/utils.rs
index 5744646..4f65b4f 100644
--- a/eucalyptus-core/src/utils.rs
+++ b/eucalyptus-core/src/utils.rs
@@ -1,5 +1,7 @@
//! Utility functions and helpers
+pub mod option;
+
use crate::states::Node;
use dropbear_engine::utils::{ResourceReference, ResourceReferenceType, relative_path_from_euca};
use std::path::{Path, PathBuf};
diff --git a/eucalyptus-core/src/utils/option.rs b/eucalyptus-core/src/utils/option.rs
new file mode 100644
index 0000000..2b5ec32
--- /dev/null
+++ b/eucalyptus-core/src/utils/option.rs
@@ -0,0 +1,120 @@
+//! Custom optional implementations
+
+use serde::{Deserialize, Serialize};
+
+/// An optional value that when replaced can store the old value.
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
+pub struct HistoricalOption<T> {
+ _inner: Option<T>,
+ _old: Option<T>,
+}
+
+impl<T> HistoricalOption<T> {
+ /// Creates a new HistoricalOption with Some value
+ pub fn new(value: T) -> Self {
+ Self {
+ _inner: Some(value),
+ _old: None,
+ }
+ }
+
+ /// Creates a new HistoricalOption with None
+ pub fn none() -> Self {
+ Self {
+ _inner: None,
+ _old: None,
+ }
+ }
+
+ /// Replaces the current value, storing the old one in history
+ pub fn replace(&mut self, new_value: Option<T>) {
+ self._old = self._inner.take();
+ self._inner = new_value;
+ }
+
+ /// Swaps the old value with the new one.
+ pub fn swap(&mut self) {
+ let old = self._old.take();
+ let inner = self._inner.take();
+ self._inner = old;
+ self._old = inner;
+ }
+
+ /// Sets to None, storing the old value in history
+ pub fn clear(&mut self) {
+ self.replace(None);
+ }
+
+ /// Gets a reference to the current value
+ pub fn get(&self) -> Option<&T> {
+ self._inner.as_ref()
+ }
+
+ /// Gets a mutable reference to the current value
+ pub fn get_mut(&mut self) -> Option<&mut T> {
+ self._inner.as_mut()
+ }
+
+ /// Gets a reference to the old/previous value
+ pub fn old(&self) -> Option<&T> {
+ self._old.as_ref()
+ }
+
+ /// Takes the old value, leaving None in its place
+ pub fn take_old(&mut self) -> Option<T> {
+ self._old.take()
+ }
+
+ /// Returns true if the current value is Some
+ pub fn is_some(&self) -> bool {
+ self._inner.is_some()
+ }
+
+ /// Returns true if the current value is None
+ pub fn is_none(&self) -> bool {
+ self._inner.is_none()
+ }
+
+ /// Converts to the inner Option
+ pub fn into_inner(self) -> Option<T> {
+ self._inner
+ }
+
+ /// Turn the option ON.
+ /// If there is a saved history value, restore it.
+ /// Otherwise, use the provided default.
+ pub fn enable_or(&mut self, default_val: T) {
+ if self._inner.is_none() {
+ self._inner = Some(self._old.take().unwrap_or(default_val));
+ }
+ }
+
+ /// Turn the option OFF.
+ /// Save the current value into history so it can be restored later.
+ pub fn disable(&mut self) {
+ if self._inner.is_some() {
+ self._old = self._inner.take();
+ }
+ }
+}
+
+impl<T> From<Option<T>> for HistoricalOption<T> {
+ fn from(opt: Option<T>) -> Self {
+ Self {
+ _inner: opt,
+ _old: None,
+ }
+ }
+}
+
+impl<T> From<T> for HistoricalOption<T> {
+ fn from(value: T) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<T> Default for HistoricalOption<T> {
+ fn default() -> Self {
+ Self::none()
+ }
+}
\ No newline at end of file
diff --git a/eucalyptus-editor/src/editor/scene.rs b/eucalyptus-editor/src/editor/scene.rs
index 968ce6f..bbee890 100644
--- a/eucalyptus-editor/src/editor/scene.rs
+++ b/eucalyptus-editor/src/editor/scene.rs
@@ -170,6 +170,13 @@ impl Scene for Editor {
}
{
+ if let Some(fps) = EDITOR_SETTINGS.read().target_fps.get() {
+ log::debug!("setting new fps for editor: {}", fps);
+ self.scene_command = SceneCommand::SetFPS(*fps);
+ }
+ }
+
+ {
// basic futurequeue spawn queue management.
let mut completed = Vec::new();
for (i, handle) in self.light_spawn_queue.iter().enumerate() {
diff --git a/eucalyptus-editor/src/editor/settings/editor.rs b/eucalyptus-editor/src/editor/settings/editor.rs
index 78adc72..b618605 100644
--- a/eucalyptus-editor/src/editor/settings/editor.rs
+++ b/eucalyptus-editor/src/editor/settings/editor.rs
@@ -1,8 +1,10 @@
//! The scene for a window that opens up settings related to the eucalyptus-editor.
use app_dirs2::AppDataType;
-use egui::{CentralPanel};
+use egui::{CentralPanel, Id, Slider, SliderClamping};
use egui_dock::DockState;
+use egui_ltreeview::{Action, NodeBuilder};
+use eucalyptus_core::utils::option::HistoricalOption;
use gilrs::{Button, GamepadId};
use hecs::spin::Lazy;
use parking_lot::RwLock;
@@ -31,6 +33,9 @@ pub struct EditorSettings {
#[serde(default)]
pub dock_layout: Option<DockState<EditorTab>>,
+ #[serde(default)]
+ pub target_fps: HistoricalOption<u32>,
+
/// Is the debug menu shown?
///
/// Primarily used internally for testing out features of the editor, however
@@ -47,6 +52,7 @@ impl EditorSettings {
Self {
dock_layout: None,
is_debug_menu_shown: false,
+ target_fps: HistoricalOption::none(),
}
}
@@ -95,6 +101,16 @@ pub struct EditorSettingsWindow {
scene_command: SceneCommand,
input_state: InputState,
window: Option<WindowId>,
+
+ current_leaf: EditorSettingsCurrentLeaf,
+}
+
+#[derive(Default)]
+enum EditorSettingsCurrentLeaf {
+ #[default]
+ None,
+
+ Performance,
}
impl EditorSettingsWindow {
@@ -103,6 +119,7 @@ impl EditorSettingsWindow {
scene_command: SceneCommand::None,
input_state: Default::default(),
window: None,
+ current_leaf: Default::default(),
}
}
}
@@ -116,8 +133,81 @@ impl Scene for EditorSettingsWindow {
fn update(&mut self, _dt: f32, graphics: &mut RenderContext) {
CentralPanel::default().show(&graphics.shared.get_egui_context(), |ui| {
- ui.centered_and_justified(|ui| {
- ui.label("Hello editor settings window! not implemented yet (˘・_・˘)")
+ let mut editor = EDITOR_SETTINGS.write();
+
+ egui::SidePanel::left("editor_settings_tree_panel")
+ .resizable(true)
+ .default_width(200.0)
+ .width_range(150.0..=400.0)
+ .show_inside(ui, |ui| {
+ egui::ScrollArea::vertical()
+ .auto_shrink([false; 2])
+ .show(ui, |ui| {
+ let (_resp, action) = egui_ltreeview::TreeView::new(Id::from("editor_settings"))
+ .show(ui, |builder| {
+ builder.node(
+ NodeBuilder::leaf("Performance")
+ .label("Performance")
+ );
+ });
+
+ for a in action {
+ match a {
+ Action::SetSelected(selected) => {
+ let selected = selected.first().cloned();
+ if let Some(s) = selected {
+ match s {
+ "Performance" => {
+ self.current_leaf = EditorSettingsCurrentLeaf::Performance;
+ }
+ _ => {
+ self.current_leaf = EditorSettingsCurrentLeaf::None;
+ },
+ }
+ }
+ }
+ Action::Move(_) => {}
+ Action::Drag(_) => {}
+ Action::Activate(_) => {}
+ Action::DragExternal(_) => {}
+ Action::MoveExternal(_) => {}
+ }
+ }
+ });
+ });
+
+ egui::CentralPanel::default().show_inside(ui, |ui| {
+ egui::ScrollArea::vertical()
+ .auto_shrink([false; 2])
+ .show(ui, |ui| {
+ match self.current_leaf {
+ EditorSettingsCurrentLeaf::Performance => {
+ ui.heading("Performance Settings");
+ ui.separator();
+
+ ui.label("Target FPS:");
+ ui.horizontal(|ui| {
+ let mut local_set_max_fps = editor.target_fps.is_some();
+
+ if ui.checkbox(&mut local_set_max_fps, "Set max frames-per-second (FPS)").changed() {
+ if local_set_max_fps {
+ editor.target_fps.enable_or(120);
+ } else {
+ editor.target_fps.disable();
+ }
+ }
+
+ if let Some(v) = editor.target_fps.get_mut() {
+ ui.add(
+ Slider::new(v, 1..=1000)
+ .clamping(SliderClamping::Never)
+ );
+ }
+ });
+ }
+ _ => {}
+ }
+ });
});
});
diff --git a/eucalyptus-editor/src/editor/settings/project.rs b/eucalyptus-editor/src/editor/settings/project.rs
index 1aa171c..55d040b 100644
--- a/eucalyptus-editor/src/editor/settings/project.rs
+++ b/eucalyptus-editor/src/editor/settings/project.rs
@@ -1,6 +1,6 @@
//! The scene for a window that opens up settings related to the project, "Play Mode" runtime and redback-runtime.
-use egui::{CentralPanel, Color32, Id, RichText};
+use egui::{CentralPanel, Color32, Id, RichText, Slider, SliderClamping};
use egui_ltreeview::{Action, NodeBuilder};
use gilrs::{Button, GamepadId};
use semver::Version;
@@ -55,7 +55,7 @@ impl Scene for ProjectSettingsWindow {
CentralPanel::default().show(&graphics.shared.get_egui_context(), |ui| {
let mut project = PROJECT.write();
- egui::SidePanel::left("settings_tree_panel")
+ egui::SidePanel::left("project_settings_tree_panel")
.resizable(true)
.default_width(200.0)
.width_range(150.0..=400.0)
@@ -157,16 +157,22 @@ impl Scene for ProjectSettingsWindow {
ui.label("Target FPS:");
ui.horizontal(|ui| {
- let mut local_max_fps = false;
- ui.checkbox(&mut local_max_fps, "Set max fps");
+ let mut local_set_max_fps = project.runtime_settings.target_fps.is_some();
- if local_max_fps {
- project.runtime_settings.target_fps = u32::MAX;
+ if ui.checkbox(&mut local_set_max_fps, "Set max frames-per-second (FPS)").changed() {
+ if local_set_max_fps {
+ project.runtime_settings.target_fps.enable_or(120);
+ } else {
+ project.runtime_settings.target_fps.disable();
+ }
}
- ui.add_enabled_ui(project.runtime_settings.target_fps == u32::MAX, |ui| {
- ui.add(egui::Slider::new(&mut project.runtime_settings.target_fps, 30..=1000).clamping(egui::SliderClamping::Never));
- });
+ if let Some(v) = project.runtime_settings.target_fps.get_mut() {
+ ui.add(
+ Slider::new(v, 1..=1000)
+ .clamping(SliderClamping::Never)
+ );
+ }
});
}
_ => {}
diff --git a/eucalyptus-editor/src/runtime/scene.rs b/eucalyptus-editor/src/runtime/scene.rs
index 687b1a9..c1a46ca 100644
--- a/eucalyptus-editor/src/runtime/scene.rs
+++ b/eucalyptus-editor/src/runtime/scene.rs
@@ -228,6 +228,13 @@ impl Scene for PlayMode {
graphics.shared.future_queue.poll();
self.poll(graphics);
+ {
+ if let Some(fps) = PROJECT.read().runtime_settings.target_fps.get() {
+ log::debug!("setting new fps for play mode session: {}", fps);
+ self.scene_command = SceneCommand::SetFPS(*fps);
+ }
+ }
+
if let Some(ref progress) = self.scene_progress {
if !progress.scene_handle_requested && self.world_receiver.is_none() && self.scene_loading_handle.is_none() {
log::debug!("Starting async load for scene: {}", progress.requested_scene);