tirbofish/dropbear · commit
060c236f3f92d75a8b55d31a979217fc1025d799
feature: multisampling with MSAA4
feature: increase active camera speed with mouse wheel scroll
fix: when TRS animation was run, it would rotate the entire model, making it look like it was standing on its nose
jarvis, run github actions.
Signature present but could not be verified.
Unverified
@@ -18,12 +18,18 @@ use egui::Ui; pub struct EntityTransform { local: Transform, world: Transform, + #[serde(default)] + animation: Transform, } impl EntityTransform { /// Creates a new [EntityTransform] from a local and world [Transform] pub fn new(local: Transform, world: Transform) -> Self { - Self { local, world } + Self { + local, + world, + animation: Transform::default(), + } } /// Creates a new [EntityTransform] from a world [Transform] and a default local transform. @@ -33,6 +39,7 @@ impl EntityTransform { Self { world, local: Transform::default(), + animation: Transform::default(), } } @@ -59,22 +66,26 @@ impl EntityTransform { /// Combines both transforms into one, propagating the local transform /// to the world transform and returning a uniform [Transform] pub fn sync(&self) -> Transform { - let scaled_pos = self.local.position * self.world.scale; - let rotated_pos = self.world.rotation * scaled_pos; - let position = self.world.position + rotated_pos; + let combined = self.world.matrix() * self.local.matrix() * self.animation.matrix(); + let (scale, rotation, position) = combined.to_scale_rotation_translation(); Transform { position, - rotation: self.world.rotation * self.local.rotation, - scale: self.world.scale * self.local.scale, + rotation, + scale, } } /// Applies a node transform for TRS animation as an absolute local transform. pub fn apply_animation(&mut self, node_transform: &NodeTransform) { - self.local.position = node_transform.translation.as_dvec3(); - self.local.rotation = node_transform.rotation.as_dquat(); - self.local.scale = node_transform.scale.as_dvec3(); + self.animation.position = node_transform.translation.as_dvec3(); + self.animation.rotation = node_transform.rotation.as_dquat(); + self.animation.scale = node_transform.scale.as_dvec3(); + } + + /// Clears the animation contribution to the local transform. + pub fn clear_animation(&mut self) { + self.animation = Transform::default(); } } @@ -183,6 +194,9 @@ impl Transform { .fixed_decimals(2), ); }); + if ui.button("Reset Position").clicked() { + self.position = DVec3::ZERO; + } ui.add_space(4.0); @@ -231,6 +245,10 @@ impl Transform { }) .inner; + if ui.button("Reset Rotation").clicked() { + self.rotation = DQuat::IDENTITY; + } + if changed { self.rotation = DQuat::from_euler( glam::EulerRot::XYZ, @@ -269,6 +287,10 @@ impl Transform { .fixed_decimals(3), ); }); + + if ui.button("Reset Scale").clicked() { + self.scale = DVec3::ONE; + } } } @@ -32,8 +32,6 @@ pub struct SharedGraphicsContext { pub mipmapper: Arc<MipMapper>, pub hdr: Arc<RwLock<HdrPipeline>>, pub antialiasing: Arc<RwLock<AntiAliasingMode>>, - // pub yakui_renderer: Arc<Mutex<yakui_wgpu::YakuiWgpu>>, - // pub yakui_texture: yakui::TextureId, } impl SharedGraphicsContext { @@ -1,4 +1,6 @@ -#[derive(Debug, Clone, Copy, PartialEq, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize, Deserialize)] pub enum AntiAliasingMode { #[default] None, @@ -60,14 +60,28 @@ impl Component for AnimationComponent { let target_node = self .active_animation_index .and_then(|index| model.animations.get(index)) - .and_then(|animation| animation.channels.first()) - .map(|channel| channel.target_node); + .and_then(|animation| { + let root_node = model + .skins + .first() + .and_then(|skin| skin.skeleton_root) + .or_else(|| model.nodes.iter().position(|n| n.parent.is_none())); + + root_node.or_else(|| animation.channels.first().map(|channel| channel.target_node)) + }); - if let Some(node_idx) = target_node { - if let Some(node_transform) = self.local_pose.get(&node_idx) { - if let Ok(mut entity_transform) = world.get::<&mut EntityTransform>(entity) { - entity_transform.apply_animation(node_transform); - } + let node_transform = target_node.and_then(|node_idx| { + self.local_pose + .get(&node_idx) + .cloned() + .or_else(|| model.nodes.get(node_idx).map(|n| n.transform.clone())) + }); + + if let Ok(mut entity_transform) = world.get::<&mut EntityTransform>(entity) { + if let Some(node_transform) = node_transform.as_ref() { + entity_transform.apply_animation(node_transform); + } else { + entity_transform.clear_animation(); } } @@ -16,7 +16,6 @@ use std::sync::Arc; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CameraComponent { - pub settings: CameraSettings, pub camera_type: CameraType, pub starting_camera: bool, } @@ -39,10 +38,10 @@ impl Component for Camera { } } - fn init<'a>( - ser: &'a Self::SerializedForm, + fn init( + ser: &'_ Self::SerializedForm, graphics: Arc<SharedGraphicsContext>, - ) -> ComponentInitFuture<'a, Self> { + ) -> ComponentInitFuture<'_, Self> { Box::pin(async move { let label = ser.label.clone(); let builder = CameraBuilder::from(ser.clone()); @@ -196,15 +195,10 @@ impl Default for CameraComponent { impl CameraComponent { pub fn new() -> Self { Self { - settings: CameraSettings::default(), camera_type: CameraType::Normal, starting_camera: false, } } - - pub fn update(&mut self, camera: &mut Camera) { - camera.settings = self.settings; - } } impl From<SerializableCamera> for CameraBuilder { @@ -234,13 +228,7 @@ impl From<SerializableCamera> for CameraBuilder { impl From<SerializableCamera> for CameraComponent { fn from(value: SerializableCamera) -> Self { - let settings = CameraSettings::new( - value.speed as f64, - value.sensitivity as f64, - value.fov as f64, - ); Self { - settings, camera_type: value.camera_type, starting_camera: value.starting_camera, } @@ -9,7 +9,7 @@ use crate::component::{ use crate::config::{ProjectConfig, ResourceConfig, SourceConfig}; use crate::properties::Value; use crate::scene::SceneConfig; -use dropbear_engine::camera::Camera; +use dropbear_engine::camera::{Camera, CameraSettings}; use dropbear_engine::entity::Transform; use dropbear_engine::graphics::SharedGraphicsContext; use dropbear_engine::lighting::LightComponent; @@ -252,7 +252,7 @@ pub struct SerializableCamera { impl Default for SerializableCamera { fn default() -> Self { - let default = CameraComponent::new(); + let settings = CameraSettings::default(); Self { transform: Transform::default(), aspect: 16.0 / 9.0, @@ -261,8 +261,8 @@ impl Default for SerializableCamera { far: 100.0, label: String::new(), camera_type: CameraType::Normal, - speed: default.settings.speed as f32, - sensitivity: default.settings.sensitivity as f32, + speed: settings.speed as f32, + sensitivity: settings.sensitivity as f32, starting_camera: false, } } @@ -28,6 +28,7 @@ use std::{ }; use wgpu::util::DeviceExt; use winit::{event::WindowEvent, event_loop::ActiveEventLoop, keyboard::KeyCode}; +use winit::event::{MouseScrollDelta, TouchPhase}; impl Scene for Editor { fn load(&mut self, graphics: std::sync::Arc<dropbear_engine::graphics::SharedGraphicsContext>) { @@ -838,6 +839,23 @@ impl Scene for Editor { WindowEvent::HoveredFileCancelled => { log_once::debug_once!("Hover cancelled"); } + WindowEvent::MouseWheel { delta, phase, .. } => { + if matches!(self.viewport_mode, ViewportMode::CameraMove) + && !matches!(phase, TouchPhase::Cancelled) + { + let active = { self.active_camera.lock().clone() }; + if let Some(e) = active { + if let Ok(mut cam) = self.world.get::<&mut Camera>(e) { + let speed_delta = match delta { + MouseScrollDelta::LineDelta(_, y) => *y as f64 * 2.0, + MouseScrollDelta::PixelDelta(pos) => pos.y * 0.015, + }; + + cam.settings.speed = (cam.settings.speed + speed_delta).max(0.1); + } + } + } + } _ => {} } } @@ -3,7 +3,7 @@ use app_dirs2::AppDataType; use dropbear_engine::input::{Controller, Keyboard, Mouse}; use dropbear_engine::scene::{Scene, SceneCommand}; -use egui::{CentralPanel, Id, Slider, SliderClamping}; +use egui::{CentralPanel, ComboBox, Id, Slider, SliderClamping}; use egui_dock::DockState; use egui_ltreeview::{Action, NodeBuilder}; use eucalyptus_core::input::InputState; @@ -19,6 +19,7 @@ use winit::event::MouseButton; use winit::event_loop::ActiveEventLoop; use winit::keyboard::KeyCode; use winit::window::WindowId; +use dropbear_engine::multisampling::AntiAliasingMode; pub static EDITOR_SETTINGS: Lazy<RwLock<EditorSettings>> = Lazy::new(|| RwLock::new(EditorSettings::new())); @@ -35,6 +36,9 @@ pub struct EditorSettings { #[serde(default)] pub target_fps: HistoricalOption<u32>, + #[serde(default)] + pub anti_aliasing_mode: AntiAliasingMode, + /// Is the debug menu shown? /// /// Primarily used internally for testing out features of the editor, however @@ -52,6 +56,7 @@ impl EditorSettings { dock_layout: None, is_debug_menu_shown: false, target_fps: HistoricalOption::none(), + anti_aliasing_mode: AntiAliasingMode::MSAA4, } } @@ -220,6 +225,24 @@ impl Scene for EditorSettingsWindow { ); } }); + { + let mut antialiasing = graphics.antialiasing.write(); + ui.label("Anti-aliasing mode:"); + ComboBox::from_id_salt("anti-aliasing-mode-combobox") + .selected_text(match *antialiasing { + AntiAliasingMode::None => "None", + AntiAliasingMode::MSAA4 => "MSAA4" + }) + .show_ui(ui, |ui| { + ui.selectable_value(&mut *antialiasing, AntiAliasingMode::None, "None"); + ui.selectable_value(&mut *antialiasing, AntiAliasingMode::MSAA4, "MSAA4"); + }); + + if editor.anti_aliasing_mode != *antialiasing { + editor.anti_aliasing_mode = *antialiasing; + } + } + } _ => {} }); @@ -25,7 +25,7 @@ use eucalyptus_core::rapier3d::prelude::QueryFilter; use eucalyptus_core::scene::loading::{IsSceneLoaded, SCENE_LOADER, SceneLoadResult}; use eucalyptus_core::states::SCENES; use eucalyptus_core::states::{Label, PROJECT}; -use glam::{DQuat, DVec3, Mat4, Quat, Vec2}; +use glam::{DVec3, Mat4, Quat, Vec2}; use hecs::Entity; // use kino_ui::widgets::rect::Rectangle; // use kino_ui::widgets::{Border, Fill}; @@ -263,18 +263,10 @@ impl Scene for PlayMode { let base = entity_transform.world_mut(); base.position = new_local_pos; base.rotation = new_local_rot; - - let offset = entity_transform.local_mut(); - offset.position = DVec3::ZERO; - offset.rotation = DQuat::IDENTITY; } else { let base = entity_transform.world_mut(); base.position = new_world_pos; base.rotation = new_world_rot; - - let offset = entity_transform.local_mut(); - offset.position = DVec3::ZERO; - offset.rotation = DQuat::IDENTITY; } } }