mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-28 08:58:07 +00:00
Finished persistance prototype
This commit is contained in:
Generated
+8
-9
@@ -3787,7 +3787,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_bevy_xpbd_plugin"
|
name = "space_bevy_xpbd_plugin"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_xpbd_3d",
|
"bevy_xpbd_3d",
|
||||||
@@ -3797,7 +3797,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_editor"
|
name = "space_editor"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"space_bevy_xpbd_plugin",
|
"space_bevy_xpbd_plugin",
|
||||||
@@ -3808,7 +3808,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_editor_core"
|
name = "space_editor_core"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"space_persistence",
|
"space_persistence",
|
||||||
@@ -3820,7 +3820,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_editor_ui"
|
name = "space_editor_ui"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_debug_grid",
|
"bevy_debug_grid",
|
||||||
@@ -3841,7 +3841,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_persistence"
|
name = "space_persistence"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"ron",
|
"ron",
|
||||||
@@ -3851,7 +3851,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_prefab"
|
name = "space_prefab"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy-inspector-egui",
|
"bevy-inspector-egui",
|
||||||
@@ -3865,7 +3865,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_shared"
|
name = "space_shared"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy-inspector-egui",
|
"bevy-inspector-egui",
|
||||||
@@ -3875,11 +3875,10 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "space_undo"
|
name = "space_undo"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/rewin123/space_editor?rev=b56d81222cbf59448ecda5064bf1b37ca90b84f1#b56d81222cbf59448ecda5064bf1b37ca90b84f1"
|
source = "git+https://github.com/rewin123/space_editor?rev=ce83f86dc902787ab16213f3209276a784654df6#ce83f86dc902787ab16213f3209276a784654df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"pretty-type-name",
|
"pretty-type-name",
|
||||||
"space_shared",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Binary file not shown.
+21
-14
@@ -1,9 +1,15 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bevy::{prelude::*, window::PrimaryWindow};
|
use bevy::{prelude::*, window::PrimaryWindow};
|
||||||
use bevy_inspector_egui::{quick::WorldInspectorPlugin, bevy_egui::EguiPlugin, DefaultInspectorConfigPlugin};
|
use bevy_inspector_egui::{bevy_egui::EguiPlugin, DefaultInspectorConfigPlugin};
|
||||||
use bevy_mod_picking::debug::DebugPickingMode;
|
use bevy_mod_picking::debug::DebugPickingMode;
|
||||||
use space_editor::{space_editor_ui::{EditorPluginGroup, EditorPickingPlugin, EditorDefaultCameraPlugin, bottom_menu::BottomMenuPlugin, EditorUiCore, tools::gizmo::GizmoToolPlugin, ShowEditorUi}, prelude::{EditorCameraMarker, space_undo::UndoPlugin}};
|
use space_editor::{
|
||||||
|
prelude::EditorCameraMarker,
|
||||||
|
space_editor_ui::{
|
||||||
|
bottom_menu::BottomMenuPlugin, tools::gizmo::GizmoToolPlugin, EditorDefaultCameraPlugin,
|
||||||
|
EditorPickingPlugin, EditorPluginGroup, EditorUiCore, ShowEditorUi,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera_controller::{CameraController, CameraMotionSystem},
|
camera_controller::{CameraController, CameraMotionSystem},
|
||||||
@@ -46,14 +52,14 @@ impl Plugin for DebugPlugin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
//space_editor stuff
|
//space_editor stuff
|
||||||
// app.add_plugins(UndoPlugin);
|
// app.add_plugins(UndoPlugin);
|
||||||
app.add_plugins(
|
app.add_plugins(
|
||||||
EditorPluginGroup.build()
|
EditorPluginGroup
|
||||||
|
.build()
|
||||||
.disable::<EditorUiCore>()
|
.disable::<EditorUiCore>()
|
||||||
.add_before::<EditorDefaultCameraPlugin, _>(EditorUiCore {
|
.add_before::<EditorDefaultCameraPlugin, _>(EditorUiCore {
|
||||||
disable_no_editor_cams: false
|
disable_no_editor_cams: false,
|
||||||
})
|
})
|
||||||
.disable::<EguiPlugin>()
|
.disable::<EguiPlugin>()
|
||||||
.disable::<DefaultInspectorConfigPlugin>()
|
.disable::<DefaultInspectorConfigPlugin>()
|
||||||
@@ -62,18 +68,19 @@ impl Plugin for DebugPlugin {
|
|||||||
.disable::<BottomMenuPlugin>()
|
.disable::<BottomMenuPlugin>()
|
||||||
.disable::<GizmoToolPlugin>()
|
.disable::<GizmoToolPlugin>()
|
||||||
.set(space_editor::prelude::SelectedPlugin {
|
.set(space_editor::prelude::SelectedPlugin {
|
||||||
show_selected_wireframe: false
|
show_selected_wireframe: false,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_systems(Update, sync_editor_camera);
|
app.add_systems(Update, sync_editor_camera);
|
||||||
app.add_systems(Update, update_editor_ui_mode.run_if(resource_changed::<DebugMode>()));
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
update_editor_ui_mode.run_if(resource_changed::<DebugMode>()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_debug_mode(
|
fn toggle_debug_mode(mut input: EventReader<InputAction>, mut r_debug: ResMut<DebugMode>) {
|
||||||
mut input: EventReader<InputAction>,
|
|
||||||
mut r_debug: ResMut<DebugMode>,) {
|
|
||||||
if input
|
if input
|
||||||
.read()
|
.read()
|
||||||
.any(|action| matches!(action, InputAction(Lifecycle::Stop, Action::ToggleDebug)))
|
.any(|action| matches!(action, InputAction(Lifecycle::Stop, Action::ToggleDebug)))
|
||||||
@@ -164,10 +171,10 @@ pub fn print_mat3(m: &Mat3, label: impl fmt::Display) -> fmt::Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sync_editor_camera(
|
fn sync_editor_camera(
|
||||||
mut cmd : Commands,
|
mut cmd: Commands,
|
||||||
mut q_cam : Query<Entity, (With<MainCamera>, Without<EditorCameraMarker>)>
|
mut q_cam: Query<Entity, (With<MainCamera>, Without<EditorCameraMarker>)>,
|
||||||
) {
|
) {
|
||||||
for ent in q_cam.iter_mut() {
|
for ent in q_cam.iter_mut() {
|
||||||
cmd.entity(ent).insert(EditorCameraMarker);
|
cmd.entity(ent).insert(EditorCameraMarker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -320,12 +320,18 @@ fn read_mouse_delta(
|
|||||||
|
|
||||||
// TODO: Make it configurable
|
// TODO: Make it configurable
|
||||||
fn send_undo_event(mut events: EventWriter<UndoRedo>, keyboard: Res<Input<KeyCode>>) {
|
fn send_undo_event(mut events: EventWriter<UndoRedo>, keyboard: Res<Input<KeyCode>>) {
|
||||||
if keyboard.pressed(KeyCode::ControlLeft) && keyboard.just_pressed(KeyCode::Z) && !keyboard.pressed(KeyCode::ShiftLeft) {
|
if keyboard.pressed(KeyCode::ControlLeft)
|
||||||
|
&& keyboard.just_pressed(KeyCode::Z)
|
||||||
|
&& !keyboard.pressed(KeyCode::ShiftLeft)
|
||||||
|
{
|
||||||
events.send(UndoRedo::Undo);
|
events.send(UndoRedo::Undo);
|
||||||
info!("Undo event sent");
|
info!("Undo event sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyboard.pressed(KeyCode::ControlLeft) && keyboard.just_pressed(KeyCode::Z) && keyboard.pressed(KeyCode::ShiftLeft) {
|
if keyboard.pressed(KeyCode::ControlLeft)
|
||||||
|
&& keyboard.just_pressed(KeyCode::Z)
|
||||||
|
&& keyboard.pressed(KeyCode::ShiftLeft)
|
||||||
|
{
|
||||||
events.send(UndoRedo::Redo);
|
events.send(UndoRedo::Redo);
|
||||||
info!("Redo event sent");
|
info!("Redo event sent");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pub(super) fn spawn_gizmo_camera(
|
|||||||
},
|
},
|
||||||
RenderLayers::layer(GIZMO_RENDER_LAYER),
|
RenderLayers::layer(GIZMO_RENDER_LAYER),
|
||||||
Fxaa::default(),
|
Fxaa::default(),
|
||||||
NotShowCamera
|
NotShowCamera,
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ impl Plugin for SelectionPlugin {
|
|||||||
.chain()
|
.chain()
|
||||||
.after(SceneSpawnerSystem),
|
.after(SceneSpawnerSystem),
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_systems(Update, tag_scene_elements);
|
app.add_systems(Update, tag_scene_elements);
|
||||||
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
@@ -35,10 +35,7 @@ impl Plugin for SelectionPlugin {
|
|||||||
.run_if(resource_changed_or_removed::<Selection>()),
|
.run_if(resource_changed_or_removed::<Selection>()),
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_systems(
|
app.add_systems(Update, sync_editor_selected);
|
||||||
Update,
|
|
||||||
sync_editor_selected
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,11 +53,15 @@ fn sync_editor_selected(
|
|||||||
q_new_selected: Query<Entity, (Added<Selected>, Without<space_editor::prelude::Selected>)>,
|
q_new_selected: Query<Entity, (Added<Selected>, Without<space_editor::prelude::Selected>)>,
|
||||||
q_editor_selected: Query<Entity, With<space_editor::prelude::Selected>>,
|
q_editor_selected: Query<Entity, With<space_editor::prelude::Selected>>,
|
||||||
q_selected: Query<Entity, With<Selected>>,
|
q_selected: Query<Entity, With<Selected>>,
|
||||||
q_added_editor_selected: Query<Entity, (Without<Selected>, Added<space_editor::prelude::Selected>)>,
|
q_added_editor_selected: Query<
|
||||||
|
Entity,
|
||||||
|
(Without<Selected>, Added<space_editor::prelude::Selected>),
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
for ent in q_new_selected.iter() {
|
for ent in q_new_selected.iter() {
|
||||||
for ed_ent in q_editor_selected.iter() {
|
for ed_ent in q_editor_selected.iter() {
|
||||||
cmd.entity(ed_ent).remove::<space_editor::prelude::Selected>();
|
cmd.entity(ed_ent)
|
||||||
|
.remove::<space_editor::prelude::Selected>();
|
||||||
}
|
}
|
||||||
cmd.entity(ent).insert(space_editor::prelude::Selected);
|
cmd.entity(ent).insert(space_editor::prelude::Selected);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-10
@@ -3,10 +3,6 @@
|
|||||||
use bevy::{app::PluginGroupBuilder, prelude::*};
|
use bevy::{app::PluginGroupBuilder, prelude::*};
|
||||||
use bevy_mod_picking::DefaultPickingPlugins;
|
use bevy_mod_picking::DefaultPickingPlugins;
|
||||||
|
|
||||||
use space_editor::{
|
|
||||||
prelude::{space_undo::UndoPlugin, PersistencePlugin},
|
|
||||||
space_editor_ui::{EditorPluginGroup, ext::{bevy_egui::EguiPlugin, bevy_inspector_egui::DefaultInspectorConfigPlugin}, EditorPickingPlugin},
|
|
||||||
};
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
@@ -17,12 +13,12 @@ mod input;
|
|||||||
mod inspector;
|
mod inspector;
|
||||||
mod interaction;
|
mod interaction;
|
||||||
mod math;
|
mod math;
|
||||||
|
mod persistance;
|
||||||
mod scene;
|
mod scene;
|
||||||
mod skybox;
|
mod skybox;
|
||||||
mod ui;
|
mod ui;
|
||||||
mod viewport;
|
mod viewport;
|
||||||
mod world_grid;
|
mod world_grid;
|
||||||
mod persistance;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera_controller::CameraControllerPlugin,
|
camera_controller::CameraControllerPlugin,
|
||||||
@@ -79,9 +75,7 @@ impl PluginGroup for CommonPlugins {
|
|||||||
struct EditorPlugins;
|
struct EditorPlugins;
|
||||||
impl PluginGroup for EditorPlugins {
|
impl PluginGroup for EditorPlugins {
|
||||||
fn build(self) -> PluginGroupBuilder {
|
fn build(self) -> PluginGroupBuilder {
|
||||||
PluginGroupBuilder::start::<Self>()
|
PluginGroupBuilder::start::<Self>().add(InteractionPlugin)
|
||||||
.add(InteractionPlugin)
|
|
||||||
.add(UndoPlugin)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +119,7 @@ pub fn init(viewport_size: ViewportSize) {
|
|||||||
SkyboxPlugin,
|
SkyboxPlugin,
|
||||||
UiLayerPlugin,
|
UiLayerPlugin,
|
||||||
WorldGridPlugin,
|
WorldGridPlugin,
|
||||||
persistance::PersistancePlugin
|
persistance::PersistancePlugin,
|
||||||
))
|
))
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
@@ -228,7 +222,8 @@ pub fn start_internal(
|
|||||||
CommonPlugins,
|
CommonPlugins,
|
||||||
));
|
));
|
||||||
|
|
||||||
if matches!(studio_mode, StudioMode::Editor) {
|
if studio_mode == StudioMode::Editor {
|
||||||
|
info!("Starting in editor mode");
|
||||||
app.add_plugins((DefaultPickingPlugins, EditorPlugins));
|
app.add_plugins((DefaultPickingPlugins, EditorPlugins));
|
||||||
|
|
||||||
// Only for registering components for undo
|
// Only for registering components for undo
|
||||||
|
|||||||
@@ -6,17 +6,23 @@ pub struct PersistancePlugin;
|
|||||||
impl Plugin for PersistancePlugin {
|
impl Plugin for PersistancePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
info!("PersistancePlugin::build");
|
info!("PersistancePlugin::build");
|
||||||
app.editor_tab_by_trait(EditorTabName::Other("Persistance".to_string()), DebugPersistanceTab::default());
|
app.editor_tab_by_trait(
|
||||||
|
EditorTabName::Other("Persistance".to_string()),
|
||||||
|
DebugPersistanceTab::default(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct DebugPersistanceTab {
|
pub struct DebugPersistanceTab {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditorTab for DebugPersistanceTab {
|
impl EditorTab for DebugPersistanceTab {
|
||||||
fn ui(&mut self, ui: &mut bevy_inspector_egui::egui::Ui, commands: &mut Commands, world: &mut World) {
|
fn ui(
|
||||||
|
&mut self,
|
||||||
|
ui: &mut bevy_inspector_egui::egui::Ui,
|
||||||
|
commands: &mut Commands,
|
||||||
|
world: &mut World,
|
||||||
|
) {
|
||||||
if ui.button("Save").clicked() {
|
if ui.button("Save").clicked() {
|
||||||
world.send_event(EditorEvent::Save(EditorPrefabPath::MemoryCahce));
|
world.send_event(EditorEvent::Save(EditorPrefabPath::MemoryCahce));
|
||||||
}
|
}
|
||||||
@@ -36,4 +42,4 @@ impl EditorTab for DebugPersistanceTab {
|
|||||||
fn title(&self) -> bevy_inspector_egui::egui::WidgetText {
|
fn title(&self) -> bevy_inspector_egui::egui::WidgetText {
|
||||||
"Persistance".into()
|
"Persistance".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+159
-213
@@ -1,19 +1,19 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
asset::AssetPath,
|
asset::{DependencyLoadState, LoadState, RecursiveDependencyLoadState},
|
||||||
core_pipeline::{
|
core_pipeline::{
|
||||||
bloom::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings},
|
bloom::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings},
|
||||||
fxaa::Fxaa,
|
fxaa::Fxaa,
|
||||||
tonemapping::Tonemapping,
|
tonemapping::Tonemapping,
|
||||||
},
|
},
|
||||||
gltf::{Gltf, GltfLoader},
|
gltf::Gltf,
|
||||||
math::{vec2, vec3},
|
math::vec2,
|
||||||
pbr::ShadowFilteringMethod,
|
pbr::ShadowFilteringMethod,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::primitives::Aabb,
|
render::primitives::Aabb,
|
||||||
scene::InstanceId,
|
scene::InstanceId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use space_editor::{prelude::{space_undo::OneFrameUndoIgnore, PrefabMarker}, space_prefab::component::{SceneAutoChild, SceneAutoRoot}};
|
use space_editor::{prelude::PrefabMarker, space_prefab::component::SceneAutoChild};
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
@@ -40,31 +40,33 @@ impl Plugin for ScenePlugin {
|
|||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
init_scene_loading,
|
init_scene_loading,
|
||||||
tick_scene_loading.run_if(in_state(SceneState::Loading)),
|
|
||||||
tick_scene_spawning.run_if(in_state(SceneState::Spawning)),
|
tick_scene_spawning.run_if(in_state(SceneState::Spawning)),
|
||||||
)
|
)
|
||||||
.in_set(SceneSpawnerSystem),
|
.in_set(SceneSpawnerSystem),
|
||||||
)
|
)
|
||||||
.add_systems(
|
|
||||||
OnEnter(SceneState::Loading),
|
|
||||||
despawn_previous_scene.in_set(SceneSpawnerSystem),
|
|
||||||
)
|
|
||||||
.add_systems(
|
|
||||||
OnEnter(SceneState::Spawning),
|
|
||||||
spawn_next_scene.in_set(SceneSpawnerSystem),
|
|
||||||
)
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
OnEnter(SceneState::Active),
|
OnEnter(SceneState::Active),
|
||||||
(
|
(tag_scene_elements, frame_scene_in_view).in_set(SceneSpawnerSystem),
|
||||||
tag_scene_elements,
|
|
||||||
spawn_main_scene_light,
|
|
||||||
frame_scene_in_view,
|
|
||||||
)
|
|
||||||
.in_set(SceneSpawnerSystem),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_systems(Update, tag_scene_elements);
|
app.add_systems(Update, tag_scene_elements);
|
||||||
|
|
||||||
|
//Auto loading screen
|
||||||
|
//Register handles on which we will look to show loading screen
|
||||||
|
app.init_resource::<LoadingQueue>();
|
||||||
|
app.add_systems(
|
||||||
|
PostUpdate,
|
||||||
|
(
|
||||||
|
check_loading,
|
||||||
|
auto_add_handle::<Scene>,
|
||||||
|
auto_add_handle::<Mesh>,
|
||||||
|
auto_add_handle::<StandardMaterial>,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
//setup default light
|
||||||
|
app.add_systems(Startup, minimal_scene_setup);
|
||||||
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
Update,
|
||||||
@@ -78,6 +80,18 @@ impl Plugin for ScenePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn minimal_scene_setup(mut cmd: Commands) {
|
||||||
|
cmd.spawn(DirectionalLightBundle {
|
||||||
|
directional_light: DirectionalLight {
|
||||||
|
shadows_enabled: false,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
transform: Transform::default().looking_at(Vec3::NEG_ONE, Vec3::Y),
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
.insert(PrefabMarker);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "wasm", wasm_bindgen)]
|
#[cfg_attr(feature = "wasm", wasm_bindgen)]
|
||||||
#[derive(States, Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
|
#[derive(States, Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum SceneState {
|
pub enum SceneState {
|
||||||
@@ -88,9 +102,6 @@ pub enum SceneState {
|
|||||||
Active,
|
Active,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Deref, DerefMut)]
|
|
||||||
struct PendingScene(pub Handle<Gltf>);
|
|
||||||
|
|
||||||
#[derive(Resource, Deref)]
|
#[derive(Resource, Deref)]
|
||||||
pub struct ActiveScene {
|
pub struct ActiveScene {
|
||||||
#[deref]
|
#[deref]
|
||||||
@@ -98,6 +109,51 @@ pub struct ActiveScene {
|
|||||||
pub source: Handle<Gltf>,
|
pub source: Handle<Gltf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Default)]
|
||||||
|
pub struct LoadingQueue {
|
||||||
|
pub queue: Vec<UntypedHandle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_loading(
|
||||||
|
mut loading_queue: ResMut<LoadingQueue>,
|
||||||
|
mut st_next: ResMut<NextState<SceneState>>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
) {
|
||||||
|
if !loading_queue.queue.is_empty() {
|
||||||
|
//filter queue to only include notloaded assets
|
||||||
|
loading_queue.queue.retain(|h| {
|
||||||
|
if let Some((load_state, dep_load_state, rec_load_state)) =
|
||||||
|
asset_server.get_load_states(h.id())
|
||||||
|
{
|
||||||
|
let is_loaded = dep_load_state == DependencyLoadState::Loaded;
|
||||||
|
|
||||||
|
let is_failed = dep_load_state == DependencyLoadState::Failed
|
||||||
|
|| rec_load_state == RecursiveDependencyLoadState::Failed
|
||||||
|
|| load_state == LoadState::Failed;
|
||||||
|
|
||||||
|
!(is_failed || is_loaded)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
info!("Loading {} assets", loading_queue.queue.len());
|
||||||
|
|
||||||
|
st_next.set(SceneState::Loading);
|
||||||
|
} else {
|
||||||
|
st_next.set(SceneState::Active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn auto_add_handle<T: Asset>(
|
||||||
|
mut queue: ResMut<LoadingQueue>,
|
||||||
|
query: Query<&Handle<T>, Added<Handle<T>>>,
|
||||||
|
) {
|
||||||
|
for h in query.iter() {
|
||||||
|
queue.queue.push(h.clone().untyped());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Event, Deref)]
|
#[derive(Event, Deref)]
|
||||||
pub struct LoadSceneEvent(pub String);
|
pub struct LoadSceneEvent(pub String);
|
||||||
|
|
||||||
@@ -115,7 +171,6 @@ pub struct SceneData {
|
|||||||
pub scene_path: String,
|
pub scene_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct SceneRoot;
|
pub struct SceneRoot;
|
||||||
|
|
||||||
@@ -152,8 +207,6 @@ fn initialize(mut cmd: Commands) {
|
|||||||
|
|
||||||
fn init_scene_loading(
|
fn init_scene_loading(
|
||||||
mut cmd: Commands,
|
mut cmd: Commands,
|
||||||
assets: Res<AssetServer>,
|
|
||||||
r_active_scene: Option<Res<ActiveScene>>,
|
|
||||||
mut er: EventReader<LoadSceneEvent>,
|
mut er: EventReader<LoadSceneEvent>,
|
||||||
mut st_next: ResMut<NextState<SceneState>>,
|
mut st_next: ResMut<NextState<SceneState>>,
|
||||||
) {
|
) {
|
||||||
@@ -168,65 +221,9 @@ fn init_scene_loading(
|
|||||||
scene: "Scene0".to_string(),
|
scene: "Scene0".to_string(),
|
||||||
},
|
},
|
||||||
PrefabMarker,
|
PrefabMarker,
|
||||||
SceneRoot
|
|
||||||
));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn despawn_previous_scene(mut cmd: Commands, q_scene_root: Query<Entity, With<SceneRoot>>) {
|
|
||||||
if let Ok(scene_root) = q_scene_root.get_single() {
|
|
||||||
cmd.entity(scene_root).despawn_recursive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick_scene_loading(
|
|
||||||
r_pending_scene: Res<PendingScene>,
|
|
||||||
ra_gltfs: Res<Assets<Gltf>>,
|
|
||||||
mut er_scene_events: EventReader<AssetEvent<Scene>>,
|
|
||||||
mut st_next: ResMut<NextState<SceneState>>,
|
|
||||||
) {
|
|
||||||
for event in er_scene_events.read() {
|
|
||||||
if let AssetEvent::LoadedWithDependencies { id } = event {
|
|
||||||
let gltf = ra_gltfs.get(&**r_pending_scene).unwrap();
|
|
||||||
if gltf.default_scene.is_some() && gltf.default_scene.as_ref().unwrap().id() == *id {
|
|
||||||
st_next.set(SceneState::Spawning);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_next_scene(
|
|
||||||
mut cmd: Commands,
|
|
||||||
ra_gltfs: Res<Assets<Gltf>>,
|
|
||||||
r_pending_scene: Res<PendingScene>,
|
|
||||||
mut r_scene_spawner: ResMut<SceneSpawner>,
|
|
||||||
) {
|
|
||||||
let gltf = ra_gltfs.get(&**r_pending_scene).unwrap();
|
|
||||||
let scene = gltf
|
|
||||||
.default_scene
|
|
||||||
.as_ref()
|
|
||||||
.expect("Expected glTF to include a default scene");
|
|
||||||
|
|
||||||
let parent = cmd
|
|
||||||
.spawn((
|
|
||||||
Name::new("Scene"),
|
|
||||||
SceneRoot,
|
SceneRoot,
|
||||||
SceneElement,
|
));
|
||||||
SpatialBundle::default(),
|
}
|
||||||
PrefabMarker,
|
|
||||||
OneFrameUndoIgnore::default(), //To prevert undo try to register add event
|
|
||||||
))
|
|
||||||
.id();
|
|
||||||
|
|
||||||
let instance = r_scene_spawner.spawn_as_child(scene.clone(), parent);
|
|
||||||
|
|
||||||
cmd.remove_resource::<PendingScene>();
|
|
||||||
cmd.insert_resource(ActiveScene {
|
|
||||||
instance,
|
|
||||||
source: r_pending_scene.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick_scene_spawning(
|
fn tick_scene_spawning(
|
||||||
@@ -251,152 +248,101 @@ fn tag_scene_elements(
|
|||||||
// because they often consist of stuff like a single eyeball, or just the
|
// because they often consist of stuff like a single eyeball, or just the
|
||||||
// leafy parts of a plant. Here we only want to tag the elements that a user
|
// leafy parts of a plant. Here we only want to tag the elements that a user
|
||||||
// might want to individually address when arranging or animating a scene.
|
// might want to individually address when arranging or animating a scene.
|
||||||
q_named_non_primitives: Query<Entity, (With<SceneAutoChild>, With<Name>, Without<Handle<Mesh>>, Without<SceneElement>)>,
|
q_named_non_primitives: Query<
|
||||||
|
Entity,
|
||||||
|
(
|
||||||
|
With<SceneAutoChild>,
|
||||||
|
With<Name>,
|
||||||
|
Without<Handle<Mesh>>,
|
||||||
|
Without<SceneElement>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
for loaded_part in q_named_non_primitives.iter() {
|
for loaded_part in q_named_non_primitives.iter() {
|
||||||
cmd.entity(loaded_part).insert(SceneElement);
|
cmd.entity(loaded_part).insert(SceneElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_main_scene_light(
|
fn frame_scene_in_view(
|
||||||
mut cmd: Commands,
|
mut cmd: Commands,
|
||||||
r_scene_spawner: Res<SceneSpawner>,
|
q_aabbs: Query<(&Aabb, &GlobalTransform), With<SceneAutoChild>>,
|
||||||
// r_active_scene: Res<ActiveScene>,
|
mut q_camera: Query<(&mut CameraController, &mut Transform, &Projection)>,
|
||||||
q_aabbs: Query<(&Aabb, &GlobalTransform)>,
|
|
||||||
q_scene_root: Query<Entity, With<SceneRoot>>,
|
|
||||||
) {
|
) {
|
||||||
let Ok(scene_root) = q_scene_root.get_single() else {
|
let Ok((mut cam, mut cam_xform, cam_proj)) = q_camera.get_single_mut() else {
|
||||||
|
error!("Failed to get camera controller");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// let Some(aabb) = Aabb::combine(
|
let Some(aabb) = Aabb::combine(q_aabbs.iter()) else {
|
||||||
// r_scene_spawner
|
return;
|
||||||
// .iter_instance_entities(**r_active_scene)
|
};
|
||||||
// .filter_map(|ent| q_aabbs.get(ent).ok()),
|
|
||||||
// ) else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let light_offset_base = vec3(0.5, 1., 1.).normalize();
|
let world2cam = cam_xform.compute_matrix().inverse();
|
||||||
// let size = f32::max(
|
let plane_origin = Vec3::from(aabb.center);
|
||||||
// f32::max(aabb.half_extents.x, aabb.half_extents.y),
|
let plane_normal = cam_xform.forward();
|
||||||
// aabb.half_extents.z,
|
|
||||||
// ) * 2.;
|
|
||||||
// let light_pos = Vec3::from(aabb.center) + light_offset_base * size * 2.;
|
|
||||||
|
|
||||||
// cmd.spawn(DebugPoint {
|
let Some((_depth, bounding_rect)) = aabb
|
||||||
// point: light_pos,
|
.extrema()
|
||||||
// color: Color::WHITE,
|
.iter()
|
||||||
// });
|
.copied()
|
||||||
// cmd.entity(scene_root).with_children(|cmd| {
|
.map(|mut p| {
|
||||||
// cmd.spawn((
|
cmd.spawn(DebugPoint {
|
||||||
// Name::new("Light"),
|
point: p,
|
||||||
// SceneElement,
|
color: Color::CYAN,
|
||||||
// SpotLightBundle {
|
});
|
||||||
// spot_light: SpotLight {
|
|
||||||
// color: Color::WHITE,
|
|
||||||
// // TODO: This doesn't scale super well to very large objects
|
|
||||||
// intensity: 200. * size,
|
|
||||||
// radius: 0.1,
|
|
||||||
// shadows_enabled: true,
|
|
||||||
// shadow_normal_bias: 0.2 * size,
|
|
||||||
// outer_angle: f32::to_radians(150.),
|
|
||||||
// inner_angle: f32::to_radians(45.),
|
|
||||||
// ..default()
|
|
||||||
// },
|
|
||||||
// transform: Transform::from_translation(light_pos)
|
|
||||||
// .looking_at(aabb.center.into(), Vec3::Y),
|
|
||||||
// ..default()
|
|
||||||
// },
|
|
||||||
// ));
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame_scene_in_view(
|
// Inflate the combined AABB to give the model some breathing room
|
||||||
// mut cmd: Commands,
|
p *= 1.5;
|
||||||
// r_scene_spawner: Res<SceneSpawner>,
|
|
||||||
// r_active_scene: Res<ActiveScene>,
|
|
||||||
// q_aabbs: Query<(&Aabb, &GlobalTransform)>,
|
|
||||||
// mut q_camera: Query<(&mut CameraController, &mut Transform, &Projection)>,
|
|
||||||
) {
|
|
||||||
// let Ok((mut cam, mut cam_xform, cam_proj)) = q_camera.get_single_mut() else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let Some(aabb) = Aabb::combine(
|
// Project each corner onto the camera plane
|
||||||
// r_scene_spawner
|
let v = p - plane_origin;
|
||||||
// .iter_instance_entities(**r_active_scene)
|
let proj = p - v.project_onto_normalized(plane_normal);
|
||||||
// .filter_map(|ent| q_aabbs.get(ent).ok()),
|
|
||||||
// ) else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let world2cam = cam_xform.compute_matrix().inverse();
|
cmd.spawn(DebugPoint {
|
||||||
// let plane_origin = Vec3::from(aabb.center);
|
point: proj,
|
||||||
// let plane_normal = cam_xform.forward();
|
color: Color::FUCHSIA,
|
||||||
|
});
|
||||||
|
|
||||||
// let Some((_depth, bounding_rect)) = aabb
|
// Transform into the camera's local space
|
||||||
// .extrema()
|
world2cam.transform_point(proj)
|
||||||
// .iter()
|
})
|
||||||
// .copied()
|
// Fold the camera-space plane-projected points into a bounding rect and view depth
|
||||||
// .map(|mut p| {
|
.fold(None, |accum: Option<(f32, Rect)>, p: Vec3| match accum {
|
||||||
// cmd.spawn(DebugPoint {
|
Some((depth, rect)) => Some((depth, rect.union_point(vec2(p.x, p.y)))),
|
||||||
// point: p,
|
None => {
|
||||||
// color: Color::CYAN,
|
let depth = p.z.abs();
|
||||||
// });
|
let p = vec2(p.x, p.y);
|
||||||
|
Some((depth, Rect::from_corners(p, p)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// // Inflate the combined AABB to give the model some breathing room
|
let pproj = match cam_proj {
|
||||||
// p *= 1.5;
|
Projection::Perspective(p) => p,
|
||||||
|
_ => panic!("Expected a perspective projection"),
|
||||||
|
};
|
||||||
|
|
||||||
// // Project each corner onto the camera plane
|
// Formula for the target camera distance
|
||||||
// let v = p - plane_origin;
|
// (c/o https://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene):
|
||||||
// let proj = p - v.project_onto_normalized(plane_normal);
|
//
|
||||||
|
// d = (s/2) / tan(a/2)
|
||||||
|
// where:
|
||||||
|
// d = distance
|
||||||
|
// s = size of the largest camera-aligned axis in world coords
|
||||||
|
// a = field-of-view angle for the same axis
|
||||||
|
let Vec2 {
|
||||||
|
x: width,
|
||||||
|
y: height,
|
||||||
|
} = bounding_rect.size();
|
||||||
|
|
||||||
// cmd.spawn(DebugPoint {
|
let s = f32::max(width, height);
|
||||||
// point: proj,
|
let a = if s == height {
|
||||||
// color: Color::FUCHSIA,
|
pproj.fov
|
||||||
// });
|
} else {
|
||||||
|
f32::atan(pproj.aspect_ratio * f32::tan(pproj.fov / 2.))
|
||||||
// // Transform into the camera's local space
|
};
|
||||||
// world2cam.transform_point(proj)
|
|
||||||
// })
|
|
||||||
// // Fold the camera-space plane-projected points into a bounding rect and view depth
|
|
||||||
// .fold(None, |accum: Option<(f32, Rect)>, p: Vec3| match accum {
|
|
||||||
// Some((depth, rect)) => Some((depth, rect.union_point(vec2(p.x, p.y)))),
|
|
||||||
// None => {
|
|
||||||
// let depth = p.z.abs();
|
|
||||||
// let p = vec2(p.x, p.y);
|
|
||||||
// Some((depth, Rect::from_corners(p, p)))
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let pproj = match cam_proj {
|
|
||||||
// Projection::Perspective(p) => p,
|
|
||||||
// _ => panic!("Expected a perspective projection"),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Formula for the target camera distance
|
|
||||||
// // (c/o https://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene):
|
|
||||||
// //
|
|
||||||
// // d = (s/2) / tan(a/2)
|
|
||||||
// // where:
|
|
||||||
// // d = distance
|
|
||||||
// // s = size of the largest camera-aligned axis in world coords
|
|
||||||
// // a = field-of-view angle for the same axis
|
|
||||||
// let Vec2 {
|
|
||||||
// x: width,
|
|
||||||
// y: height,
|
|
||||||
// } = bounding_rect.size();
|
|
||||||
|
|
||||||
// let s = f32::max(width, height);
|
|
||||||
// let a = if s == height {
|
|
||||||
// pproj.fov
|
|
||||||
// } else {
|
|
||||||
// f32::atan(pproj.aspect_ratio * f32::tan(pproj.fov / 2.))
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // TODO:
|
// // TODO:
|
||||||
// // According to "I eat babies" at the Ars Technica forums
|
// // According to "I eat babies" at the Ars Technica forums
|
||||||
@@ -413,11 +359,11 @@ fn frame_scene_in_view(
|
|||||||
// //
|
// //
|
||||||
// // Unfortunately I'm embarrassingly bad at algebra, but there
|
// // Unfortunately I'm embarrassingly bad at algebra, but there
|
||||||
// // must be some room for simplification here.
|
// // must be some room for simplification here.
|
||||||
// let radius = (s / 2.) / f32::tan(a / 2.);
|
let radius = (s / 2.) / f32::tan(a / 2.);
|
||||||
|
|
||||||
// cam.focus = aabb.center.into();
|
cam.focus = aabb.center.into();
|
||||||
// cam.radius = radius;
|
cam.radius = radius;
|
||||||
// cam_xform.translation = cam.focus + cam_xform.back() * radius;
|
cam_xform.translation = cam.focus + cam_xform.back() * radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
|
|||||||
Reference in New Issue
Block a user