mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
Merge branch 'main' into add-persistance
This commit is contained in:
+2
-1
@@ -26,6 +26,7 @@ node_modules
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/.nx
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
@@ -37,4 +38,4 @@ testem.log
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
/target
|
||||
/target
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
TransformSpace,
|
||||
TransformType,
|
||||
SceneState,
|
||||
StudioMode,
|
||||
} from "@storyteller/studio";
|
||||
import { CanvasProvider } from "@storyteller/studio-web/canvas-provider";
|
||||
import { match } from "@storyteller/utility";
|
||||
@@ -43,6 +44,8 @@ export class AppElement extends LitElement {
|
||||
@state() sceneObjects: SceneObject[] = [];
|
||||
@state() selection?: string | null;
|
||||
|
||||
@state() mode?: StudioMode;
|
||||
|
||||
#sceneObjects: studio.SceneObject[] = [];
|
||||
#entityMap = new Map<string, SceneObject>();
|
||||
#canvasProvider: Ref<CanvasProvider> = createRef();
|
||||
@@ -54,6 +57,18 @@ export class AppElement extends LitElement {
|
||||
return document.getElementById(provider.canvasId) as HTMLCanvasElement | null;
|
||||
}
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
const params = new URLSearchParams(document.location.search);
|
||||
|
||||
this.mode = match (params.get("mode"), {
|
||||
"studio": () => StudioMode.Editor,
|
||||
"viewer": () => StudioMode.Viewer,
|
||||
_: () => StudioMode.Viewer,
|
||||
});
|
||||
}
|
||||
|
||||
protected override createRenderRoot(): Element | ShadowRoot {
|
||||
return this;
|
||||
}
|
||||
@@ -169,9 +184,14 @@ export class AppElement extends LitElement {
|
||||
class="app-root"
|
||||
${ref(this.#canvasProvider as any)}
|
||||
>
|
||||
${
|
||||
// TODO: See notes in studio-web/src/lib/viewer.element.ts
|
||||
nothing
|
||||
}
|
||||
<sts-viewer
|
||||
objectId="sample-room"
|
||||
skyboxId="test_scene"
|
||||
.mode=${this.mode}
|
||||
@scene-state=${this.onSceneStateChange}
|
||||
></sts-viewer>
|
||||
|
||||
@@ -187,13 +207,15 @@ export class AppElement extends LitElement {
|
||||
</sts-toolbar-group>
|
||||
</sts-toolbar>
|
||||
|
||||
<sts-transform-toolbar
|
||||
class="v-start h-center"
|
||||
.type=${this.transformType}
|
||||
@type-change=${this.onTransformTypeChange}
|
||||
.space=${this.transformSpace}
|
||||
@space-change=${this.onTransformSpaceChange}
|
||||
></sts-transform-toolbar>
|
||||
${this.mode === StudioMode.Editor ? html`
|
||||
<sts-transform-toolbar
|
||||
class="v-start h-center"
|
||||
.type=${this.transformType}
|
||||
@type-change=${this.onTransformTypeChange}
|
||||
.space=${this.transformSpace}
|
||||
@space-change=${this.onTransformSpaceChange}
|
||||
></sts-transform-toolbar>
|
||||
` : nothing}
|
||||
|
||||
<div class="hierarchy v-start h-end">
|
||||
${this.sceneObjects.map(obj => html`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { ViewportSize } from "@storyteller/studio";
|
||||
import { StudioMode, ViewportSize } from "@storyteller/studio";
|
||||
import { inject } from "@storyteller/framework";
|
||||
import { LitElement, PropertyValues, html, unsafeCSS } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
@@ -12,8 +12,18 @@ import styles from "./viewer.element.scss?inline";
|
||||
export class ViewerElement extends LitElement {
|
||||
static override styles = unsafeCSS(styles);
|
||||
|
||||
// TODO: `<sts-viewer />` and `<sts-studio />` should be separate element
|
||||
// types with different inputs. `<sts-viewer />` should take a BVH
|
||||
// animation and load a simple mannequin asset playing the given
|
||||
// animation in a loop, while `<sts-studio />` should take a scene
|
||||
// asset handle and load it with full editing capabilities.
|
||||
//
|
||||
// Both elements should share most of the core functionality here,
|
||||
// which could easily be extracted to a base class for inheritance by
|
||||
// making `#startViewer` an abstract method.
|
||||
@property() objectId?: string;
|
||||
@property() skyboxId?: string;
|
||||
@property({ type: Number }) mode?: StudioMode;
|
||||
|
||||
@inject(CANVAS_PROVIDER)
|
||||
_canvasProvider?: CanvasProvider;
|
||||
@@ -68,15 +78,17 @@ export class ViewerElement extends LitElement {
|
||||
if (!this.#canvas) return;
|
||||
if (!this.objectId) return;
|
||||
if (!this.skyboxId) return;
|
||||
if (this.mode == null) return;
|
||||
|
||||
const { width, height } = this.getBoundingClientRect();
|
||||
try {
|
||||
studio.startViewer(
|
||||
studio.start(
|
||||
this.objectId,
|
||||
this.skyboxId,
|
||||
`#${this._canvasProvider!.canvasId}`,
|
||||
"Storyteller Studio",
|
||||
new ViewportSize(width, height),
|
||||
this.mode,
|
||||
);
|
||||
} catch (err) {
|
||||
if (!(err as Error).message?.startsWith("Using exceptions for control flow"))
|
||||
|
||||
+4
-2
@@ -8,7 +8,7 @@ use space_editor::{space_editor_ui::{EditorPluginGroup, EditorPickingPlugin, Edi
|
||||
use crate::{
|
||||
camera_controller::{CameraController, CameraMotionSystem},
|
||||
input::{Action, InputAction, Lifecycle},
|
||||
MainCamera, interaction::gizmos::camera::GizmoCamera,
|
||||
is_editor, MainCamera,
|
||||
};
|
||||
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
@@ -36,7 +36,9 @@ impl Plugin for DebugPlugin {
|
||||
Update,
|
||||
(
|
||||
toggle_debug_mode,
|
||||
update_debug_picking_mode.run_if(resource_changed::<DebugMode>()),
|
||||
update_debug_picking_mode
|
||||
.run_if(is_editor)
|
||||
.run_if(resource_changed::<DebugMode>()),
|
||||
update_gizmo_line_thickness,
|
||||
(draw_world_axes, draw_debug_points)
|
||||
.after(CameraMotionSystem)
|
||||
|
||||
+3
-1
@@ -5,6 +5,8 @@ use bevy::{
|
||||
};
|
||||
use space_editor::prelude::space_undo::UndoRedo;
|
||||
|
||||
use crate::is_editor;
|
||||
|
||||
#[derive(SystemSet, Hash, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct StudioInputSystem;
|
||||
|
||||
@@ -31,7 +33,7 @@ impl Plugin for StudioInputPlugin {
|
||||
translate_debug_toggle,
|
||||
translate_dcc_camera_events,
|
||||
translate_fps_camera_events,
|
||||
send_undo_event,
|
||||
send_undo_event.run_if(is_editor),
|
||||
)
|
||||
.in_set(StudioInputSystem)
|
||||
.after(bevy::input::InputSystem)
|
||||
|
||||
+96
-18
@@ -1,6 +1,6 @@
|
||||
#![allow(clippy::type_complexity, clippy::too_many_arguments)]
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::{app::PluginGroupBuilder, prelude::*};
|
||||
use bevy_mod_picking::DefaultPickingPlugins;
|
||||
|
||||
use space_editor::{
|
||||
@@ -44,6 +44,46 @@ mod wasm;
|
||||
#[derive(Component)]
|
||||
pub(crate) struct MainCamera;
|
||||
|
||||
#[cfg_attr(feature = "wasm", wasm_bindgen)]
|
||||
#[derive(Resource, Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum StudioMode {
|
||||
Editor,
|
||||
Viewer,
|
||||
}
|
||||
|
||||
pub(crate) fn is_editor(r_studio_mode: Res<StudioMode>) -> bool {
|
||||
matches!(*r_studio_mode, StudioMode::Editor)
|
||||
}
|
||||
|
||||
/// The collection of plugins that should be loaded for both viewer-mode and
|
||||
/// editor-mode instances of the app.
|
||||
struct CommonPlugins;
|
||||
impl PluginGroup for CommonPlugins {
|
||||
fn build(self) -> PluginGroupBuilder {
|
||||
PluginGroupBuilder::start::<Self>()
|
||||
.add(CameraControllerPlugin)
|
||||
.add(DebugPlugin)
|
||||
.add(InspectorPlugin)
|
||||
.add(InterpolationPlugin)
|
||||
.add(ScenePlugin)
|
||||
.add(SkyboxPlugin)
|
||||
.add(StudioInputPlugin)
|
||||
.add(UiLayerPlugin)
|
||||
.add(WorldGridPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
/// The collection of plugins that should be loaded only for editor-mode
|
||||
/// instances of the app.
|
||||
struct EditorPlugins;
|
||||
impl PluginGroup for EditorPlugins {
|
||||
fn build(self) -> PluginGroupBuilder {
|
||||
PluginGroupBuilder::start::<Self>()
|
||||
.add(InteractionPlugin)
|
||||
.add(UndoPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "wasm", wasm_bindgen)]
|
||||
pub fn init(viewport_size: ViewportSize) {
|
||||
#[cfg(feature = "wasm")]
|
||||
@@ -119,6 +159,46 @@ pub fn start_viewer(
|
||||
canvas_selector: &str,
|
||||
canvas_alt: &str,
|
||||
viewport_size: ViewportSize,
|
||||
) {
|
||||
start_internal(
|
||||
object_id,
|
||||
skybox_id,
|
||||
canvas_selector,
|
||||
canvas_alt,
|
||||
viewport_size,
|
||||
StudioMode::Viewer,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "wasm", wasm_bindgen(js_name = startEditor))]
|
||||
pub fn start_editor(
|
||||
object_id: &str,
|
||||
skybox_id: &str,
|
||||
canvas_selector: &str,
|
||||
canvas_alt: &str,
|
||||
viewport_size: ViewportSize,
|
||||
) {
|
||||
start_internal(
|
||||
object_id,
|
||||
skybox_id,
|
||||
canvas_selector,
|
||||
canvas_alt,
|
||||
viewport_size,
|
||||
StudioMode::Editor,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: These `start_` functiions should be refactored to better support the
|
||||
// needs of the "reaodnly viewer" vs "full studio editor" use cases. See
|
||||
// notes in `studio-web/src/lib/viewer.element.ts` for more info.
|
||||
#[cfg_attr(feature = "wasm", wasm_bindgen(js_name = start))]
|
||||
pub fn start_internal(
|
||||
object_id: &str,
|
||||
skybox_id: &str,
|
||||
canvas_selector: &str,
|
||||
canvas_alt: &str,
|
||||
viewport_size: ViewportSize,
|
||||
studio_mode: StudioMode,
|
||||
) {
|
||||
#[cfg(feature = "wasm")]
|
||||
console_error_panic_hook::set_once();
|
||||
@@ -127,6 +207,9 @@ pub fn start_viewer(
|
||||
let skybox_id = skybox_id.to_string();
|
||||
|
||||
let mut app = App::new();
|
||||
|
||||
app.insert_resource(studio_mode);
|
||||
|
||||
app.add_plugins((
|
||||
#[cfg(feature = "wasm")]
|
||||
viewport::wasm::ViewportPlugin,
|
||||
@@ -139,19 +222,18 @@ pub fn start_viewer(
|
||||
}),
|
||||
..default()
|
||||
}),
|
||||
DefaultPickingPlugins,
|
||||
DebugPlugin,
|
||||
InteractionPlugin,
|
||||
InspectorPlugin,
|
||||
StudioInputPlugin,
|
||||
InterpolationPlugin,
|
||||
CameraControllerPlugin,
|
||||
ScenePlugin,
|
||||
SkyboxPlugin,
|
||||
UiLayerPlugin,
|
||||
WorldGridPlugin,
|
||||
))
|
||||
.add_systems(
|
||||
CommonPlugins,
|
||||
));
|
||||
|
||||
if matches!(studio_mode, StudioMode::Editor) {
|
||||
app.add_plugins((DefaultPickingPlugins, EditorPlugins));
|
||||
|
||||
// Only for registering components for undo
|
||||
use space_editor::prelude::space_undo::AppAutoUndo;
|
||||
app.auto_reflected_undo::<Transform>();
|
||||
}
|
||||
|
||||
app.add_systems(
|
||||
Startup,
|
||||
move |mut cmd: Commands, mut ew: EventWriter<LoadSceneEvent>| {
|
||||
cmd.insert_resource(SkyboxId(skybox_id.clone()));
|
||||
@@ -159,10 +241,6 @@ pub fn start_viewer(
|
||||
},
|
||||
);
|
||||
|
||||
// Only for registering components for undo
|
||||
use space_editor::prelude::space_undo::AppAutoUndo;
|
||||
app.auto_reflected_undo::<Transform>();
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
wasm::initialize();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user