mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-21 07:55:55 +00:00
Expose joints to hierarchy; Add entity type info
This commit is contained in:
@@ -6,7 +6,7 @@ use bevy::{
|
|||||||
};
|
};
|
||||||
use space_editor::space_prefab::editor_registry::EditorRegistryExt;
|
use space_editor::space_prefab::editor_registry::EditorRegistryExt;
|
||||||
|
|
||||||
use crate::hierarchy;
|
use crate::{hierarchy, scene::SceneElement};
|
||||||
pub use retargeting::*;
|
pub use retargeting::*;
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
@@ -131,7 +131,7 @@ fn process_skinned_meshes(
|
|||||||
// skeleton
|
// skeleton
|
||||||
let joints = joints.iter().copied().collect::<Vec<_>>();
|
let joints = joints.iter().copied().collect::<Vec<_>>();
|
||||||
if let Some(root) = hierarchy::nearest_common_ancestor(&joints, &q_parents) {
|
if let Some(root) = hierarchy::nearest_common_ancestor(&joints, &q_parents) {
|
||||||
cmd.entity(root).insert(Skeleton);
|
cmd.entity(root).insert((Skeleton, SceneElement::Skeleton));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag each joint and find its bind poses
|
// Tag each joint and find its bind poses
|
||||||
@@ -141,6 +141,7 @@ fn process_skinned_meshes(
|
|||||||
|
|
||||||
cmd.entity(joint).insert((
|
cmd.entity(joint).insert((
|
||||||
SkeletalJoint(Color::BLACK),
|
SkeletalJoint(Color::BLACK),
|
||||||
|
SceneElement::Bone,
|
||||||
BindPoseLocal(bind_pose_local),
|
BindPoseLocal(bind_pose_local),
|
||||||
BindPoseGlobal(bind_pose_global.affine()),
|
BindPoseGlobal(bind_pose_global.affine()),
|
||||||
InvBindPose(bind_pose_global.affine().inverse()),
|
InvBindPose(bind_pose_global.affine().inverse()),
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ use bevy::{prelude::*, utils::HashSet, window::PrimaryWindow};
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{scene::SceneElement, wasm};
|
||||||
scene::SceneElement,
|
|
||||||
wasm::{self, AsJson},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[wasm_bindgen(typescript_custom_section)]
|
#[wasm_bindgen(typescript_custom_section)]
|
||||||
const TYPE_DECLARATIONS: &str = r#"
|
const TYPE_DECLARATIONS: &str = r#"
|
||||||
@@ -16,6 +13,7 @@ export interface SceneObject {
|
|||||||
id: string;
|
id: string;
|
||||||
/** A user-friendly name for displaying in the UI */
|
/** A user-friendly name for displaying in the UI */
|
||||||
name: string;
|
name: string;
|
||||||
|
type: SceneElement;
|
||||||
/** The IDs of this object's children in the hierarchy */
|
/** The IDs of this object's children in the hierarchy */
|
||||||
children: string[];
|
children: string[];
|
||||||
/** The ID of this object's parent in the hierarchy, if it has one */
|
/** The ID of this object's parent in the hierarchy, if it has one */
|
||||||
@@ -64,50 +62,50 @@ declare global {
|
|||||||
pub(super) struct SceneObject {
|
pub(super) struct SceneObject {
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
type_: SceneElement,
|
||||||
children: Vec<String>,
|
children: Vec<String>,
|
||||||
parent: Option<String>,
|
parent: Option<String>,
|
||||||
transform: serde_json::Value,
|
|
||||||
#[serde(rename(serialize = "globalTransform"))]
|
|
||||||
global_transform: serde_json::Value,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SceneObjectBuilder<'a> {
|
struct SceneObjectBuilder {
|
||||||
id: Entity,
|
id: Entity,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
|
type_: Option<SceneElement>,
|
||||||
children: Option<Vec<Entity>>,
|
children: Option<Vec<Entity>>,
|
||||||
parent: Option<Entity>,
|
parent: Option<Entity>,
|
||||||
transform: Option<&'a Transform>,
|
|
||||||
global_transform: Option<&'a GlobalTransform>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SceneObjectBuilder<'a> {
|
impl SceneObjectBuilder {
|
||||||
fn new(id: Entity) -> Self {
|
fn new(id: Entity) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
name: None,
|
name: None,
|
||||||
|
type_: None,
|
||||||
children: None,
|
children: None,
|
||||||
parent: None,
|
parent: None,
|
||||||
transform: None,
|
|
||||||
global_transform: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn finish(self) -> SceneObject {
|
fn finish(self) -> SceneObject {
|
||||||
SceneObject {
|
SceneObject {
|
||||||
id: format!("{:?}", self.id),
|
id: format!("{:?}", self.id),
|
||||||
name: self.name.unwrap(),
|
name: self.name.unwrap(),
|
||||||
|
type_: self.type_.unwrap(),
|
||||||
children: self
|
children: self
|
||||||
.children
|
.children
|
||||||
.map(|children| children.iter().map(|ent| format!("{ent:?}")).collect())
|
.map(|children| children.iter().map(|ent| format!("{ent:?}")).collect())
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
parent: self.parent.map(|ent| format!("{ent:?}")),
|
parent: self.parent.map(|ent| format!("{ent:?}")),
|
||||||
transform: self.transform.unwrap().as_json(),
|
|
||||||
global_transform: self.global_transform.unwrap().as_json(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn with_name(mut self, name: String) -> Self {
|
fn with_name(mut self, name: String) -> Self {
|
||||||
self.name = Some(name);
|
self.name = Some(name);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
fn with_type(mut self, type_: SceneElement) -> Self {
|
||||||
|
self.type_ = Some(type_);
|
||||||
|
self
|
||||||
|
}
|
||||||
fn with_children(mut self, children: Vec<Entity>) -> Self {
|
fn with_children(mut self, children: Vec<Entity>) -> Self {
|
||||||
self.children = Some(children);
|
self.children = Some(children);
|
||||||
self
|
self
|
||||||
@@ -116,18 +114,10 @@ impl<'a> SceneObjectBuilder<'a> {
|
|||||||
self.parent = Some(parent);
|
self.parent = Some(parent);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
fn with_transform(mut self, transform: &'a Transform) -> Self {
|
|
||||||
self.transform = Some(transform);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn with_global_transform(mut self, global_transform: &'a GlobalTransform) -> Self {
|
|
||||||
self.global_transform = Some(global_transform);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SceneObject {
|
impl SceneObject {
|
||||||
fn build(id: Entity) -> SceneObjectBuilder<'a> {
|
fn build(id: Entity) -> SceneObjectBuilder {
|
||||||
SceneObjectBuilder::new(id)
|
SceneObjectBuilder::new(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,8 +130,8 @@ pub(super) fn notify_entity_spawn_changes(
|
|||||||
mut l_despawned_entities: Local<Vec<Entity>>,
|
mut l_despawned_entities: Local<Vec<Entity>>,
|
||||||
mut l_missing_parents: Local<VecDeque<Entity>>,
|
mut l_missing_parents: Local<VecDeque<Entity>>,
|
||||||
q_window: Query<&Window, With<PrimaryWindow>>,
|
q_window: Query<&Window, With<PrimaryWindow>>,
|
||||||
q_inspectables: Query<(Entity, &Transform, &GlobalTransform), With<SceneElement>>,
|
q_inspectables: Query<(Entity, &SceneElement)>,
|
||||||
q_others: Query<(Entity, &Transform, &GlobalTransform), Without<SceneElement>>,
|
q_others: Query<Entity, Without<SceneElement>>,
|
||||||
q_names: Query<&Name>,
|
q_names: Query<&Name>,
|
||||||
q_parents: Query<&Children>,
|
q_parents: Query<&Children>,
|
||||||
q_children: Query<&Parent>,
|
q_children: Query<&Parent>,
|
||||||
@@ -149,26 +139,21 @@ pub(super) fn notify_entity_spawn_changes(
|
|||||||
l_missing_parents.clear();
|
l_missing_parents.clear();
|
||||||
|
|
||||||
l_new_objects.clear();
|
l_new_objects.clear();
|
||||||
l_new_objects.extend(
|
l_new_objects.extend(q_inspectables.iter().filter_map(|(ent, &type_)| {
|
||||||
q_inspectables
|
build_scene_object(
|
||||||
.iter()
|
&mut l_notified,
|
||||||
.filter_map(|(ent, xform, world_xform)| {
|
&mut l_missing_parents,
|
||||||
build_scene_object(
|
ent,
|
||||||
&mut l_notified,
|
type_,
|
||||||
&mut l_missing_parents,
|
&q_inspectables,
|
||||||
ent,
|
&q_names,
|
||||||
xform,
|
&q_parents,
|
||||||
world_xform,
|
&q_children,
|
||||||
&q_inspectables,
|
)
|
||||||
&q_names,
|
}));
|
||||||
&q_parents,
|
|
||||||
&q_children,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
while let Some(parent) = l_missing_parents.pop_front() {
|
while let Some(parent) = l_missing_parents.pop_front() {
|
||||||
let Ok((ent, xform, world_xform)) = q_others.get(parent) else {
|
let Ok(ent) = q_others.get(parent) else {
|
||||||
error!("Failed to find missing parent: {parent:?}");
|
error!("Failed to find missing parent: {parent:?}");
|
||||||
l_notified.insert(parent);
|
l_notified.insert(parent);
|
||||||
|
|
||||||
@@ -179,8 +164,7 @@ pub(super) fn notify_entity_spawn_changes(
|
|||||||
&mut l_notified,
|
&mut l_notified,
|
||||||
&mut l_missing_parents,
|
&mut l_missing_parents,
|
||||||
ent,
|
ent,
|
||||||
xform,
|
SceneElement::Generic,
|
||||||
world_xform,
|
|
||||||
&q_inspectables,
|
&q_inspectables,
|
||||||
&q_names,
|
&q_names,
|
||||||
&q_parents,
|
&q_parents,
|
||||||
@@ -218,9 +202,8 @@ fn build_scene_object(
|
|||||||
notified: &mut HashSet<Entity>,
|
notified: &mut HashSet<Entity>,
|
||||||
missing_parents: &mut VecDeque<Entity>,
|
missing_parents: &mut VecDeque<Entity>,
|
||||||
ent: Entity,
|
ent: Entity,
|
||||||
xform: &Transform,
|
type_: SceneElement,
|
||||||
world_xform: &GlobalTransform,
|
q_inspectables: &Query<(Entity, &SceneElement)>,
|
||||||
q_inspectables: &Query<(Entity, &Transform, &GlobalTransform), With<SceneElement>>,
|
|
||||||
q_names: &Query<&Name>,
|
q_names: &Query<&Name>,
|
||||||
q_parents: &Query<&Children>,
|
q_parents: &Query<&Children>,
|
||||||
q_children: &Query<&Parent>,
|
q_children: &Query<&Parent>,
|
||||||
@@ -231,9 +214,7 @@ fn build_scene_object(
|
|||||||
|
|
||||||
notified.insert(ent);
|
notified.insert(ent);
|
||||||
|
|
||||||
let mut result = SceneObject::build(ent)
|
let mut result = SceneObject::build(ent).with_type(type_);
|
||||||
.with_transform(xform)
|
|
||||||
.with_global_transform(world_xform);
|
|
||||||
|
|
||||||
if let Ok(children) = q_parents.get(ent) {
|
if let Ok(children) = q_parents.get(ent) {
|
||||||
result = result.with_children(children.iter().cloned().collect());
|
result = result.with_children(children.iter().cloned().collect());
|
||||||
|
|||||||
+19
-5
@@ -12,7 +12,8 @@ use bevy::{
|
|||||||
render::{camera::RenderTarget, primitives::Aabb},
|
render::{camera::RenderTarget, primitives::Aabb},
|
||||||
scene::InstanceId,
|
scene::InstanceId,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "wasm")]
|
||||||
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
use space_editor::{
|
use space_editor::{
|
||||||
prelude::{EditorEvent, EditorPrefabPath, PrefabMarker},
|
prelude::{EditorEvent, EditorPrefabPath, PrefabMarker},
|
||||||
space_prefab::component::SceneAutoChild,
|
space_prefab::component::SceneAutoChild,
|
||||||
@@ -230,8 +231,21 @@ pub struct ImportSceneEvent(pub String);
|
|||||||
// soon.
|
// soon.
|
||||||
/// A tag that identifies its entity as a user-facing scene element like a prop,
|
/// A tag that identifies its entity as a user-facing scene element like a prop,
|
||||||
/// a light, or a camera.
|
/// a light, or a camera.
|
||||||
#[derive(Component)]
|
#[cfg_attr(
|
||||||
pub struct SceneElement;
|
feature = "wasm",
|
||||||
|
repr(u8),
|
||||||
|
wasm_bindgen,
|
||||||
|
derive(Serialize_repr, Deserialize_repr)
|
||||||
|
)]
|
||||||
|
#[derive(Component, Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum SceneElement {
|
||||||
|
Generic,
|
||||||
|
Mesh,
|
||||||
|
Skeleton,
|
||||||
|
Bone,
|
||||||
|
Light,
|
||||||
|
Camera,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct SceneData {
|
pub struct SceneData {
|
||||||
@@ -398,9 +412,9 @@ fn tag_scene_elements(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if has_mesh {
|
if has_mesh {
|
||||||
cmd.entity(e).insert(SceneElement);
|
cmd.entity(e).insert(SceneElement::Mesh);
|
||||||
} else {
|
} else {
|
||||||
cmd.entity(e).insert(NoMeshElement);
|
cmd.entity(e).insert(SceneElement::Generic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user