0a6e235
· Thribhu K
fix: linux support works better now (since i moved to linux and got rid of windows).
feature: got a brand new logo for dropbear. i sketched it up quickly, but it works...
jarvis, run github actions (for my linux people)
Unverified
diff --git a/Cargo.toml b/Cargo.toml
index d59eeca..c257e24 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,7 +21,6 @@ members = [
[workspace.dependencies]
anyhow = { version = "1.0", features = ["backtrace"] }
app_dirs2 = "2.5"
-arboard = "3.6"
bytemuck = { version = "1.24", features = ["derive"] }
chrono = "0.4"
clap = { version = "4.5", features = ["derive"] }
diff --git a/README.md b/README.md
index b5c3cfc..24a1d4e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,9 @@
-# dropbear
+<div style="text-align: center;">
+ <img src="resources/eucalyptus-editor.png" alt="dropbear engine logo, specifically a koala falling off a eucalyptus tree, looking like a 'dropbear'. looks nice, right?">
+ <div style="position: relative; top: -50px; ">
+ <h1>dropbear</h1>
+ </div>
+</div>
dropbear is a game engine used to create games, made in Rust and scripted with the Kotlin Language.
diff --git a/dropbear-engine/Cargo.toml b/dropbear-engine/Cargo.toml
index 2c060fa..887b142 100644
--- a/dropbear-engine/Cargo.toml
+++ b/dropbear-engine/Cargo.toml
@@ -46,7 +46,6 @@ postcard.workspace = true
[target.'cfg(not(target_os = "android"))'.dependencies]
rfd.workspace = true
-arboard.workspace = true
[dependencies.image]
version = "0.25"
diff --git a/dropbear-engine/src/lib.rs b/dropbear-engine/src/lib.rs
index f9f6107..8a85c3e 100644
--- a/dropbear-engine/src/lib.rs
+++ b/dropbear-engine/src/lib.rs
@@ -20,6 +20,8 @@ pub mod utils;
pub static WGPU_BACKEND: OnceLock<String> = OnceLock::new();
pub const PHYSICS_STEP_RATE: u32 = 120;
const MAX_PHYSICS_STEPS_PER_FRAME: usize = 4;
+/// Note: image size is 256x256
+pub const LOGO_AS_BYTES: &[u8] = include_bytes!("../../resources/eucalyptus-editor.png");
use app_dirs2::{AppDataType, AppInfo};
use bytemuck::Contiguous;
@@ -83,6 +85,17 @@ pub struct State {
pub scene_manager: scene::Manager,
}
+/// Generates the dropbear engine logo in a form that [winit::window::Icon] can accept.
+///
+/// Returns (the bytes, width, height) in resp order.
+pub fn gen_logo() -> anyhow::Result<(Vec<u8>, u32, u32)> {
+ let image = image::load_from_memory(LOGO_AS_BYTES)?.into_rgba8();
+ let (width, height) = image.dimensions();
+ let rgba = image.into_raw();
+ Ok((rgba, width, height))
+
+}
+
impl State {
/// Asynchronously initialised the state and sets up the backend and surface for wgpu to render to.
pub async fn new(window: Arc<Window>, instance: Arc<Instance>, future_queue: Arc<FutureQueue>) -> anyhow::Result<Self> {
@@ -90,6 +103,10 @@ impl State {
let size = window.inner_size();
+ let initial_width = size.width.max(1);
+ let initial_height = size.height.max(1);
+ let is_surface_configured = size.width > 0 && size.height > 0;
+
let surface = instance.create_surface(window.clone())?;
let adapter = instance
@@ -167,15 +184,17 @@ Hardware:
let config = SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: surface_format,
- width: size.width,
- height: size.height,
+ width: initial_width,
+ height: initial_height,
present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![],
desired_maximum_frame_latency: 2,
};
- surface.configure(&device, &config);
+ if is_surface_configured {
+ surface.configure(&device, &config);
+ }
let depth_texture = Texture::create_depth_texture(&config, &device, Some("depth texture"));
let viewport_texture =
@@ -256,7 +275,7 @@ Hardware:
device: Arc::new(device),
queue: Arc::new(queue),
config,
- is_surface_configured: true,
+ is_surface_configured,
depth_texture,
texture_bind_layout: texture_bind_group_layout,
material_tint_bind_layout: material_tint_bind_group_layout,
@@ -422,6 +441,8 @@ Hardware:
fn cleanup(mut self, event_loop: &ActiveEventLoop) {
self.scene_manager.clear_all(event_loop);
+ let _ = self.device.poll(wgpu::PollType::Poll);
+
drop(self.egui_renderer);
drop(self.depth_texture);
@@ -769,6 +790,26 @@ impl App {
self.windows.insert(window_id, win_state);
Ok(window_id)
}
+
+ fn quit(&mut self, event_loop: &ActiveEventLoop, hook: Option<fn()>) {
+ if let Some(h) = hook {
+ log::debug!("App has a pre-exit hook, executing...");
+ h();
+ }
+
+ log::info!("Exiting app!");
+
+ let windows = std::mem::take(&mut self.windows);
+ for (_, state) in windows {
+ state.cleanup(event_loop);
+ }
+ self.root_window_id = None;
+
+ #[cfg(not(target_os = "linux"))]
+ event_loop.exit();
+ #[cfg(target_os = "linux")]
+ std::process::exit(0);
+ }
}
impl ApplicationHandler for App {
@@ -832,7 +873,7 @@ impl ApplicationHandler for App {
if matches!(event, WindowEvent::CloseRequested) {
if Some(window_id) == self.root_window_id {
log::info!("Root window closed, exiting app");
- event_loop.exit();
+ self.quit(event_loop, None);
} else {
log::info!("Closing non-root window: {:?}", window_id);
if let Some(state) = self.windows.remove(&window_id) {
@@ -926,11 +967,15 @@ impl ApplicationHandler for App {
scene::SceneCommand::CloseWindow(target_window_id) => {
log::info!("Scene requested closing window: {:?}", target_window_id);
if Some(target_window_id) == self.root_window_id {
- event_loop.exit();
+ self.quit(event_loop, None);
} else {
self.windows.remove(&target_window_id);
}
}
+ scene::SceneCommand::Quit(hook) => {
+ log::debug!("Caught SceneCommand::Quit command!");
+ self.quit(event_loop, hook);
+ }
scene::SceneCommand::SetFPS(new_fps) => {
self.set_target_fps(new_fps);
}
diff --git a/dropbear-engine/src/panic.rs b/dropbear-engine/src/panic.rs
index ca7ebc5..28f1b55 100644
--- a/dropbear-engine/src/panic.rs
+++ b/dropbear-engine/src/panic.rs
@@ -1,8 +1,6 @@
use std::panic;
#[cfg(not(target_os = "android"))]
-use arboard::Clipboard;
-#[cfg(not(target_os = "android"))]
use rfd::{MessageDialog, MessageLevel};
/// Creates a new panic hook for crash detection.
@@ -34,9 +32,9 @@ pub fn set_hook() {
#[cfg(not(target_os = "android"))]
{
- if let Ok(mut clipboard) = Clipboard::new() {
- let _ = clipboard.set_text(full_text.clone());
- }
+ // if let Ok(mut clipboard) = Clipboard::new() {
+ // let _ = clipboard.set_text(full_text.clone());
+ // }
let _ = MessageDialog::new()
.set_title("Panic!")
diff --git a/dropbear-engine/src/scene.rs b/dropbear-engine/src/scene.rs
index 9058d3e..141f08c 100644
--- a/dropbear-engine/src/scene.rs
+++ b/dropbear-engine/src/scene.rs
@@ -137,12 +137,7 @@ impl Manager {
}
}
SceneCommand::Quit(hook) => {
- if let Some(h) = hook {
- log::debug!("App has a pre-exit hook, executing...");
- h()
- }
- log::info!("Exiting app!");
- event_loop.exit();
+ return vec![SceneCommand::Quit(hook)];
}
SceneCommand::None => {}
SceneCommand::DebugMessage(msg) => log::debug!("{}", msg),
diff --git a/eucalyptus-editor/src/editor/input.rs b/eucalyptus-editor/src/editor/input.rs
index 81b8ab7..925bf63 100644
--- a/eucalyptus-editor/src/editor/input.rs
+++ b/eucalyptus-editor/src/editor/input.rs
@@ -146,7 +146,6 @@ impl Keyboard for Editor {
.status()
.ok();
log::debug!("Stopping gradle threads");
- std::process::exit(0);
}
Err(_) => {
Command::new("gradlew")
@@ -177,7 +176,9 @@ impl Keyboard for Editor {
}
});
};
+
self.scene_command = SceneCommand::Quit(Some(commands));
+ log::debug!("Sent quit command");
} else if is_playing {
warn!(
"Unable to save-quit project, please pause your playing state, then try again"
diff --git a/eucalyptus-editor/src/editor/mod.rs b/eucalyptus-editor/src/editor/mod.rs
index ac1b977..912206c 100644
--- a/eucalyptus-editor/src/editor/mod.rs
+++ b/eucalyptus-editor/src/editor/mod.rs
@@ -876,7 +876,7 @@ impl Editor {
match self.save_project_config() {
Ok(_) => {
log::info!("Saved, quitting...");
- std::process::exit(0);
+ self.scene_command = SceneCommand::Quit(None);
}
Err(e) => {
fatal!("Error saving project: {}", e);
diff --git a/eucalyptus-editor/src/editor/scene.rs b/eucalyptus-editor/src/editor/scene.rs
index ff6d8b7..ff26b5c 100644
--- a/eucalyptus-editor/src/editor/scene.rs
+++ b/eucalyptus-editor/src/editor/scene.rs
@@ -172,7 +172,9 @@ impl Scene for Editor {
{
if let Some(fps) = EDITOR_SETTINGS.read().target_fps.get() {
log_once::debug_once!("setting new fps for editor: {}", fps);
- self.scene_command = SceneCommand::SetFPS(*fps);
+ if matches!(self.scene_command, SceneCommand::None) {
+ self.scene_command = SceneCommand::SetFPS(*fps);
+ }
}
}
diff --git a/eucalyptus-editor/src/main.rs b/eucalyptus-editor/src/main.rs
index 7d18fd8..f7de1fd 100644
--- a/eucalyptus-editor/src/main.rs
+++ b/eucalyptus-editor/src/main.rs
@@ -8,8 +8,8 @@ use eucalyptus_editor::{build, editor, menu};
use parking_lot::RwLock;
use std::sync::Arc;
use std::{fs, path::{Path, PathBuf}, rc::Rc};
-use winit::window::WindowAttributes;
-use dropbear_engine::DropbearWindowBuilder;
+use winit::window::{Icon, WindowAttributes};
+use dropbear_engine::{DropbearWindowBuilder};
use eucalyptus_core::config::ProjectConfig;
use eucalyptus_core::scripting::jni::{RuntimeMode, RUNTIME_MODE};
use eucalyptus_core::scripting::{AWAIT_JDB, JVM_ARGS};
@@ -269,6 +269,12 @@ async fn main() -> anyhow::Result<()> {
panic!("Unable to initialise Eucalyptus Editor: {}", e)
})));
+ let img = dropbear_engine::gen_logo()?;
+
+ let window_icon = Icon::from_rgba(img.0, img.1, img.2)
+ .inspect_err(|e| log::warn!("Unable to set logo: {}", e))
+ .ok();
+
let window = DropbearWindowBuilder::new()
.with_attributes(
WindowAttributes::default().with_title(
@@ -279,6 +285,7 @@ async fn main() -> anyhow::Result<()> {
)
)
.with_maximized(true)
+ .with_window_icon(window_icon)
)
.add_scene_with_input(editor, "editor")
.add_scene_with_input(main_menu, "main_menu")
diff --git a/eucalyptus-editor/src/menu.rs b/eucalyptus-editor/src/menu.rs
index c07b2f1..a99a983 100644
--- a/eucalyptus-editor/src/menu.rs
+++ b/eucalyptus-editor/src/menu.rs
@@ -493,9 +493,9 @@ impl Scene for MainMenu {
}
impl Keyboard for MainMenu {
- fn key_down(&mut self, key: KeyCode, event_loop: &ActiveEventLoop) {
+ fn key_down(&mut self, key: KeyCode, _event_loop: &ActiveEventLoop) {
if key == KeyCode::Escape && !self.show_new_project && !self.is_in_file_dialogue {
- event_loop.exit();
+ self.scene_command = SceneCommand::Quit(None);
}
}
diff --git a/eucalyptus-editor/src/runtime/command.rs b/eucalyptus-editor/src/runtime/command.rs
index 81e7355..074bf5c 100644
--- a/eucalyptus-editor/src/runtime/command.rs
+++ b/eucalyptus-editor/src/runtime/command.rs
@@ -1,4 +1,4 @@
-use dropbear_engine::graphics::RenderContext;
+use dropbear_engine::{graphics::RenderContext, scene::SceneCommand};
use eucalyptus_core::command::{CommandBufferPoller, COMMAND_BUFFER, CommandBuffer, WindowCommand};
use winit::window::CursorGrabMode;
use crate::runtime::PlayMode;
@@ -12,13 +12,13 @@ impl CommandBufferPoller for PlayMode {
CommandBuffer::WindowCommand(w_cmd) => match w_cmd {
WindowCommand::WindowGrab(lock) => {
if lock {
- if let Err(e) = graphics.shared.window
- .set_cursor_grab(CursorGrabMode::Confined)
- .or_else(|_| graphics.shared.window.set_cursor_grab(CursorGrabMode::Locked))
- {
- log_once::warn_once!("Failed to grab cursor: {:?}", e);
- } else {
- log_once::info_once!("Grabbed cursor");
+ let window = &graphics.shared.window;
+ window.set_cursor_visible(false);
+ if let Err(e) = window.set_cursor_grab(CursorGrabMode::Locked).or_else(|_| {
+ log_once::warn_once!("Using cursor grab fallback: CursorGrabMode::Confined");
+ window.set_cursor_grab(CursorGrabMode::Confined)
+ }) {
+ log_once::error_once!("Unable to grab mouse: {}", e);
}
} else if let Err(e) = graphics.shared.window.set_cursor_grab(CursorGrabMode::None) {
log_once::warn_once!("Failed to release cursor: {:?}", e);
@@ -35,7 +35,7 @@ impl CommandBufferPoller for PlayMode {
}
},
CommandBuffer::Quit => {
- self.scene_command = dropbear_engine::scene::SceneCommand::Quit(None);
+ self.scene_command = SceneCommand::CloseWindow(graphics.shared.window.id());
},
CommandBuffer::SwitchSceneImmediate(scene_name) => {
log::debug!("Immediate scene switch requested: {}", scene_name);
@@ -50,7 +50,7 @@ impl CommandBufferPoller for PlayMode {
CommandBuffer::SwitchToAsync(handle) => {
if let Some(ref progress) = self.scene_progress {
if progress.requested_scene == handle.scene_name && progress.is_everything_loaded() {
- self.switch_to(progress.clone(), graphics);
+ self.switch_to(progress.clone(), graphics);
}
}
}
diff --git a/eucalyptus-editor/src/runtime/scene.rs b/eucalyptus-editor/src/runtime/scene.rs
index e76902e..915e0dd 100644
--- a/eucalyptus-editor/src/runtime/scene.rs
+++ b/eucalyptus-editor/src/runtime/scene.rs
@@ -231,7 +231,9 @@ impl Scene for PlayMode {
{
if let Some(fps) = PROJECT.read().runtime_settings.target_fps.get() {
log_once::debug_once!("setting new fps for play mode session: {}", fps);
- self.scene_command = SceneCommand::SetFPS(*fps);
+ if matches!(self.scene_command, SceneCommand::None) {
+ self.scene_command = SceneCommand::SetFPS(*fps);
+ }
}
}
diff --git a/resources/eucalyptus-editor.png b/resources/eucalyptus-editor.png
new file mode 100644
index 0000000..bdd598f
Binary files /dev/null and b/resources/eucalyptus-editor.png differ