Merge branch 'main' into update-version

This commit is contained in:
rewin
2024-03-29 20:07:42 +03:00
31 changed files with 1197 additions and 464 deletions
+7 -1
View File
@@ -24,6 +24,7 @@ mod hierarchy;
mod input;
mod inspector;
mod interaction;
pub mod material;
pub mod math;
mod mixamo;
mod path;
@@ -36,6 +37,7 @@ mod ui;
pub mod viewport;
mod world_grid;
use crate::material::MaterialPlugin;
pub use crate::{
anim::AnimPlugin,
bvh::BvhPlugin,
@@ -89,6 +91,7 @@ impl PluginGroup for CommonPlugins {
.add(InspectorPlugin)
.add(InterpolationPlugin)
.add(ScenePlugin)
.add(MaterialPlugin)
// .add(SkyboxPlugin)
.add(StudioInputPlugin)
.add(UiLayerPlugin)
@@ -231,7 +234,10 @@ fn init_from_asset(app: &mut App, asset: InitAsset, skybox_id: String) {
}
InitAsset::ImportedScene(scene) => {
app.add_systems(Startup, move |mut ew: EventWriter<ImportSceneEvent>| {
ew.send(ImportSceneEvent(scene.clone()));
ew.send(ImportSceneEvent {
path: scene.clone(),
name: None,
});
});
}
}
+37
View File
@@ -0,0 +1,37 @@
use crate::material::short_material::ShortMaterial;
use bevy::app::{App, Plugin, PostUpdate};
use bevy::asset::{Assets, Handle};
use bevy::pbr::StandardMaterial;
use bevy::prelude::{Commands, Entity, Query, ResMut};
use space_editor::prelude::EditorRegistryExt;
pub mod short_material;
pub struct MaterialPlugin;
impl Plugin for MaterialPlugin {
fn build(&self, app: &mut App) {
app.register_type::<ShortMaterial>()
.editor_registry::<ShortMaterial>();
app.add_systems(PostUpdate, apply_short_materials);
}
}
fn apply_short_materials(
mut commands: Commands,
q_mats: Query<(Entity, &Handle<StandardMaterial>, &ShortMaterial)>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
for (entity, handle, short) in q_mats.iter() {
let Some(material) = materials.get_mut(handle) else {
continue;
};
material.base_color = short.base_color;
material.perceptual_roughness = short.perceptual_roughness;
material.metallic = short.metallic;
material.reflectance = short.reflectance;
commands.entity(entity).remove::<ShortMaterial>();
}
}
+25
View File
@@ -0,0 +1,25 @@
use bevy::pbr::StandardMaterial;
use bevy::prelude::{Color, Component, Reflect};
use bevy::ecs::reflect::ReflectComponent;
use bevy::reflect::std_traits::ReflectDefault;
#[derive(Reflect, Default, Clone, Component)]
#[reflect(Default, Component)]
pub struct ShortMaterial {
pub base_color: Color,
pub perceptual_roughness: f32,
pub metallic: f32,
pub reflectance: f32,
}
impl ShortMaterial {
pub fn new(material: &StandardMaterial) -> Self {
Self {
base_color: material.base_color,
perceptual_roughness: material.perceptual_roughness,
metallic: material.metallic,
reflectance: material.reflectance,
}
}
}
+21 -94
View File
@@ -39,6 +39,9 @@ use crate::{
MainCamera,
};
#[cfg(feature = "wasm")]
mod wasm;
pub struct ScenePlugin;
#[derive(SystemSet, Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -113,7 +116,7 @@ impl Plugin for ScenePlugin {
app.add_systems(
Update,
(
wasm::dispatch_object_load_request,
wasm::handle_spawn_asset_messages,
wasm::notify_state_changes
.map(bevy::utils::error)
.run_if(resource_changed::<State<SceneState>>),
@@ -276,8 +279,11 @@ pub struct LoadSceneEvent(pub String);
/// Request the application to import and process a glTF scene from an arbitrary
/// asset source (e.g., an http path or a Storyteller.ai media token).
#[derive(Event, Deref)]
pub struct ImportSceneEvent(pub String);
#[derive(Event)]
pub struct ImportSceneEvent {
pub path: String,
pub name: Option<String>,
}
/// A tag that identifies its entity as a user-facing scene element like a prop,
/// a light, or a camera.
@@ -409,16 +415,23 @@ fn init_scene_import(
r_assets: Res<AssetServer>,
mut er: EventReader<ImportSceneEvent>,
) {
if let Some(path) = er.read().last() {
info!("Importing asset: {}", path.0);
for event in er.read() {
info!("Importing asset: {}", event.path);
let name = event
.name
.as_ref()
.map(|name| Name::new(name.clone()))
.unwrap_or_else(|| Name::new("Scene"));
cmd.spawn((
Name::new("Scene"), // TODO: Maybe use the "basename" part of the asset path?
name,
SpatialBundle::default(),
space_editor::prelude::GltfPrefab {
path: path.0.clone(),
path: event.path.clone(),
scene: "Scene0".to_string(),
},
r_assets.load::<Gltf>(&path.0),
r_assets.load::<Gltf>(&event.path),
PrefabMarker,
SceneRoot,
));
@@ -630,89 +643,3 @@ fn start_capture(mut captures: Query<&mut ScreenCapture, Added<ScreenCapture>>)
capture.start_capturing();
}
}
#[cfg(feature = "wasm")]
mod wasm {
use bevy::{prelude::*, window::PrimaryWindow};
use wasm_bindgen::prelude::*;
use super::{LoadLibraryObjectEvent, LoadingQueue, SceneState};
use crate::wasm::{self, StaticBuffer, WasmMessageBuffer};
static OBJECT_LOAD_REQUEST: WasmMessageBuffer<String> = WasmMessageBuffer::new();
#[wasm_bindgen(js_name = loadObject)]
pub fn load_object(id: &str) {
OBJECT_LOAD_REQUEST.write_message(id.into());
}
// FIXME: Is it an object or a scene? Inconsistent terminology is
// unnecessarily confusing
pub(super) fn dispatch_object_load_request(
mut ew_load_scene: EventWriter<LoadLibraryObjectEvent>,
) {
if let Some(id) = OBJECT_LOAD_REQUEST.take_message() {
ew_load_scene.send(LoadLibraryObjectEvent(id));
}
}
#[wasm_bindgen(typescript_custom_section)]
const SCENE_STATE_EVENT: &str = r#"
export interface SceneStateEvent extends CustomEvent {
type: "scene-state";
detail: SceneState;
}
declare global {
export interface GlobalEventHandlersEventMap {
"scene-state": SceneStateEvent;
}
}
"#;
pub(super) fn notify_state_changes(
r_state: Res<State<SceneState>>,
q_window: Query<&Window, With<PrimaryWindow>>,
) -> Result<(), String> {
if let Ok(window) = q_window.get_single() {
wasm::dispatch_to_js(window, "scene-state", &(**r_state as u32))?;
}
Ok(())
}
#[wasm_bindgen(typescript_custom_section)]
const LOADING_QUEUE_EVENT: &str = r#"
export interface LoadingQueueEvent extends CustomEvent {
type: "loading-queue";
detail: number;
}
declare global {
export interface GlobalEventHandlersEventMap {
"loading-queue": LoadingQueueEvent;
}
}
"#;
pub(super) fn notify_loading_queue_changes(
mut l_last_sent: Local<Option<usize>>,
r_loading: Res<LoadingQueue>,
q_window: Query<&Window, With<PrimaryWindow>>,
) -> Result<(), String> {
let queue_len = r_loading.queue.len();
if let Some(last_sent) = *l_last_sent {
if last_sent == queue_len {
return Ok(());
}
}
let Ok(window) = q_window.get_single() else {
return Ok(());
};
wasm::dispatch_to_js(window, "loading-queue", &queue_len)?;
*l_last_sent = Some(queue_len);
Ok(())
}
}
+111
View File
@@ -0,0 +1,111 @@
use bevy::{prelude::*, window::PrimaryWindow};
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use super::{ImportSceneEvent, LoadingQueue, SceneState};
use crate::wasm::{self, StaticBuffer, WasmMessageBuffer};
static SPAWN_ASSETS: WasmMessageBuffer<Vec<AssetImport>> = WasmMessageBuffer::new();
#[wasm_bindgen(typescript_custom_section)]
const ASSET_IMPORT_TS: &str = r#"
export interface AssetImport {
path: string;
name?: string;
}
"#;
#[derive(Deserialize, Serialize)]
struct AssetImport {
path: String,
name: Option<String>,
}
#[wasm_bindgen(typescript_custom_section)]
const SPAWN_ASSET_TS: &str = r#"
export function spawnAsset(asset: AssetImport): void;
"#;
#[wasm_bindgen(js_name = spawnAsset, skip_typescript)]
pub fn spawn_asset(asset: JsValue) -> Result<(), JsValue> {
let asset: AssetImport = serde_wasm_bindgen::from_value(asset)?;
SPAWN_ASSETS.write_message(vec![asset]);
Ok(())
}
#[wasm_bindgen(typescript_custom_section)]
const SPAWN_ASSETS_TS: &str = r#"
export function spawnAssets(assets: AssetImport[]): void;
"#;
#[wasm_bindgen(js_name = spawnAssets, skip_typescript)]
pub fn spawn_assets(assets: JsValue) -> Result<(), JsValue> {
let assets: Vec<AssetImport> = serde_wasm_bindgen::from_value(assets)?;
SPAWN_ASSETS.write_message(assets);
Ok(())
}
pub(super) fn handle_spawn_asset_messages(mut ew_import_scene: EventWriter<ImportSceneEvent>) {
if let Some(assets) = SPAWN_ASSETS.take_message() {
for AssetImport { path, name } in assets {
ew_import_scene.send(ImportSceneEvent { path, name });
}
}
}
#[wasm_bindgen(typescript_custom_section)]
const SCENE_STATE_EVENT: &str = r#"
export interface SceneStateEvent extends CustomEvent {
type: "scene-state";
detail: SceneState;
}
declare global {
export interface GlobalEventHandlersEventMap {
"scene-state": SceneStateEvent;
}
}
"#;
pub(super) fn notify_state_changes(
r_state: Res<State<SceneState>>,
q_window: Query<&Window, With<PrimaryWindow>>,
) -> Result<(), String> {
if let Ok(window) = q_window.get_single() {
wasm::dispatch_to_js(window, "scene-state", &(**r_state as u32))?;
}
Ok(())
}
#[wasm_bindgen(typescript_custom_section)]
const LOADING_QUEUE_EVENT: &str = r#"
export interface LoadingQueueEvent extends CustomEvent {
type: "loading-queue";
detail: number;
}
declare global {
export interface GlobalEventHandlersEventMap {
"loading-queue": LoadingQueueEvent;
}
}
"#;
pub(super) fn notify_loading_queue_changes(
mut l_last_sent: Local<Option<usize>>,
r_loading: Res<LoadingQueue>,
q_window: Query<&Window, With<PrimaryWindow>>,
) -> Result<(), String> {
let queue_len = r_loading.queue.len();
if let Some(last_sent) = *l_last_sent {
if last_sent == queue_len {
return Ok(());
}
}
let Ok(window) = q_window.get_single() else {
return Ok(());
};
wasm::dispatch_to_js(window, "loading-queue", &queue_len)?;
*l_last_sent = Some(queue_len);
Ok(())
}
+1 -40
View File
@@ -17,6 +17,7 @@ use space_editor::{
};
use wasm_bindgen::prelude::*;
use crate::material::short_material::ShortMaterial;
use crate::{
interaction::Selection,
wasm::{self, StaticBuffer, WasmMessageBuffer},
@@ -91,7 +92,6 @@ impl Plugin for InspectorPlugin {
.chain()
.before(space_editor::space_prefab::sub_scene::prepare_auto_scene),
);
app.add_systems(PostUpdate, apply_short_materials);
app.world.resource_mut::<InspectGetters>().getters.insert(
StandardMaterial::get_type_registration()
@@ -139,25 +139,6 @@ fn create_short_materials(
}
}
fn apply_short_materials(
mut commands: Commands,
q_mats: Query<(Entity, &Handle<StandardMaterial>, &ShortMaterial)>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
for (entity, handle, short) in q_mats.iter() {
let Some(material) = materials.get_mut(handle) else {
continue;
};
material.base_color = short.base_color;
material.perceptual_roughness = short.perceptual_roughness;
material.metallic = short.metallic;
material.reflectance = short.reflectance;
commands.entity(entity).remove::<ShortMaterial>();
}
}
#[derive(Resource, Default)]
struct InspectGetters {
getters: HashMap<
@@ -588,26 +569,6 @@ fn auto_serialize_asset<T: Asset + Reflect + GetTypeRegistration>(
ev_update_description.send(UpdateEntityDescription);
}
#[derive(Reflect, Default, Clone, Component)]
#[reflect(Default, Component)]
struct ShortMaterial {
pub base_color: Color,
pub perceptual_roughness: f32,
pub metallic: f32,
pub reflectance: f32,
}
impl ShortMaterial {
pub fn new(material: &StandardMaterial) -> Self {
Self {
base_color: material.base_color,
perceptual_roughness: material.perceptual_roughness,
metallic: material.metallic,
reflectance: material.reflectance,
}
}
}
fn serialize_standart_materal(
r_selection: Option<Res<Selection>>,
q_m: Query<&Handle<StandardMaterial>>,