mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-24 04:40:53 +00:00
Compare commits
20 Commits
6755414374
...
c18659139c
Author | SHA1 | Date | |
---|---|---|---|
|
c18659139c | ||
|
d5f14bc037 | ||
|
20f37715e4 | ||
|
e47fe1a4bd | ||
|
3e24601f1d | ||
|
4aa2ef382c | ||
|
3e14cc06bf | ||
|
4d9c451de8 | ||
|
cc71436187 | ||
|
1b6dec8f5a | ||
|
0ad9f13f1d | ||
|
72681ee9f0 | ||
|
4e50af2453 | ||
|
2bc47ad624 | ||
|
7f4c8d34f3 | ||
|
0e62da4d19 | ||
|
bf075b41ef | ||
|
ec42c6d2bd | ||
|
2ffadc19eb | ||
|
6b39b5f2b1 |
291
crates/blenvy/src/components/fake_entity.rs
Normal file
291
crates/blenvy/src/components/fake_entity.rs
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
use std::{alloc::Layout, cell::Cell, num::NonZeroU32};
|
||||||
|
|
||||||
|
use bevy::{
|
||||||
|
core::Name,
|
||||||
|
ecs::world::DeferredWorld,
|
||||||
|
gltf::GltfExtras,
|
||||||
|
log::{info, warn},
|
||||||
|
prelude::{HierarchyQueryExt, Parent, QueryState, With, World},
|
||||||
|
reflect::ReflectDeserialize,
|
||||||
|
scene::{InstanceId, SceneInstance},
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
pub(crate) struct BadWorldAccess {
|
||||||
|
world: *mut World,
|
||||||
|
names: QueryState<(bevy::ecs::entity::Entity, &'static Name), With<GltfExtras>>,
|
||||||
|
hierarchy: QueryState<&'static Parent, ()>,
|
||||||
|
scene_instances: QueryState<&'static SceneInstance, ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BadWorldAccess {
|
||||||
|
pub unsafe fn new(world: &mut World) -> Self {
|
||||||
|
BadWorldAccess {
|
||||||
|
world,
|
||||||
|
// We have to check that we focus on a node, not a mesh with the same name.
|
||||||
|
// Currently, the only possible way of checking this is with `GltfExtras`, so selected entities must at least have one component.
|
||||||
|
names: world.query_filtered::<(bevy::ecs::entity::Entity, &Name), With<GltfExtras>>(),
|
||||||
|
hierarchy: world.query::<&Parent>(),
|
||||||
|
scene_instances: world.query::<&SceneInstance>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub(crate) static BAD_WORLD_ACCESS: Cell<Option<BadWorldAccess>> = Cell::new(None);
|
||||||
|
pub(crate) static INSTANCE_ID: Cell<Option<InstanceId>> = Cell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
let real = Layout::new::<bevy::ecs::entity::Entity>();
|
||||||
|
let fake = Layout::new::<Entity>();
|
||||||
|
assert!(real.size() == fake.size());
|
||||||
|
assert!(real.align() == fake.align());
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[repr(C, align(8))]
|
||||||
|
pub(crate) struct Entity {
|
||||||
|
// Do not reorder the fields here. The ordering is equivalent to bevy's `Entity`
|
||||||
|
#[cfg(target_endian = "little")]
|
||||||
|
index: u32,
|
||||||
|
generation: NonZeroU32,
|
||||||
|
#[cfg(target_endian = "big")]
|
||||||
|
index: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Entity {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename = "Entity")]
|
||||||
|
struct EntityData {
|
||||||
|
name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let entity_data = EntityData::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
let entity = if let Some(name) = entity_data.name {
|
||||||
|
info!("Found name {name}");
|
||||||
|
let BadWorldAccess {
|
||||||
|
world,
|
||||||
|
mut names,
|
||||||
|
mut hierarchy,
|
||||||
|
mut scene_instances,
|
||||||
|
} = BAD_WORLD_ACCESS.take().expect("No bad world access :c");
|
||||||
|
let instance = INSTANCE_ID.get().expect("No instance id set :c");
|
||||||
|
|
||||||
|
let mut target = None;
|
||||||
|
let w = unsafe { &*world.cast_const() };
|
||||||
|
'search: for (e, n) in names.iter(w) {
|
||||||
|
if !name.eq(n.as_str()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dw = DeferredWorld::from(unsafe { &mut *world });
|
||||||
|
let hierarchy = dw.query(&mut hierarchy);
|
||||||
|
|
||||||
|
for parent in hierarchy.iter_ancestors(e) {
|
||||||
|
let Ok(id) = scene_instances.get(w, parent) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if instance.eq(id) {
|
||||||
|
target = Some(e);
|
||||||
|
break 'search;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BAD_WORLD_ACCESS.set(Some(BadWorldAccess {
|
||||||
|
world,
|
||||||
|
names,
|
||||||
|
hierarchy,
|
||||||
|
scene_instances,
|
||||||
|
}));
|
||||||
|
|
||||||
|
target.unwrap_or_else(|| {
|
||||||
|
warn!("No entity found for '{name}' - perhaps it doesn't contain any components from blender?");
|
||||||
|
bevy::ecs::entity::Entity::PLACEHOLDER
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
warn!("No object was specified for Entity relation, using `Entity::PLACEHOLDER`.");
|
||||||
|
bevy::ecs::entity::Entity::PLACEHOLDER
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(unsafe {
|
||||||
|
// SAFETY: both have the same layout
|
||||||
|
core::mem::transmute(entity)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is expanded and modified from
|
||||||
|
// ```
|
||||||
|
// #[derive(Clone, Reflect)]
|
||||||
|
// #[reflect_value(Deserialize)]
|
||||||
|
// ```
|
||||||
|
const _: () = {
|
||||||
|
use bevy::reflect as bevy_reflect;
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
impl bevy_reflect::GetTypeRegistration for Entity
|
||||||
|
where
|
||||||
|
Self: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
|
||||||
|
{
|
||||||
|
fn get_type_registration() -> bevy_reflect::TypeRegistration {
|
||||||
|
let mut registration = bevy_reflect::TypeRegistration::of::<Self>();
|
||||||
|
registration
|
||||||
|
.insert::<
|
||||||
|
bevy_reflect::ReflectFromPtr,
|
||||||
|
>(bevy_reflect::FromType::<Self>::from_type());
|
||||||
|
registration.insert::<bevy_reflect::ReflectFromReflect>(
|
||||||
|
bevy_reflect::FromType::<Self>::from_type(),
|
||||||
|
);
|
||||||
|
registration.insert::<ReflectDeserialize>(bevy_reflect::FromType::<Self>::from_type());
|
||||||
|
registration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl bevy_reflect::TypePath for Entity
|
||||||
|
where
|
||||||
|
Self: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
|
||||||
|
{
|
||||||
|
fn type_path() -> &'static str {
|
||||||
|
"bevy_ecs::entity::Entity" // this is changed
|
||||||
|
}
|
||||||
|
fn short_type_path() -> &'static str {
|
||||||
|
"Entity"
|
||||||
|
}
|
||||||
|
fn type_ident() -> Option<&'static str> {
|
||||||
|
::core::option::Option::Some("Entity")
|
||||||
|
}
|
||||||
|
fn crate_name() -> Option<&'static str> {
|
||||||
|
// this is changed
|
||||||
|
::core::option::Option::Some("bevy_ecs::entity".split(':').next().unwrap())
|
||||||
|
}
|
||||||
|
fn module_path() -> Option<&'static str> {
|
||||||
|
::core::option::Option::Some("bevy_ecs::entity") // this is changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl bevy_reflect::Typed for Entity
|
||||||
|
where
|
||||||
|
Self: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
|
||||||
|
{
|
||||||
|
fn type_info() -> &'static bevy_reflect::TypeInfo {
|
||||||
|
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
|
||||||
|
bevy_reflect::utility::NonGenericTypeInfoCell::new();
|
||||||
|
CELL.get_or_set(|| {
|
||||||
|
let info = bevy_reflect::ValueInfo::new::<bevy::ecs::entity::Entity>(); // this is changed
|
||||||
|
bevy_reflect::TypeInfo::Value(info)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl bevy_reflect::Reflect for Entity
|
||||||
|
where
|
||||||
|
Self: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn get_represented_type_info(
|
||||||
|
&self,
|
||||||
|
) -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
|
||||||
|
::core::option::Option::Some(<Self as bevy_reflect::Typed>::type_info())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn ::core::any::Any> {
|
||||||
|
// this is changed
|
||||||
|
unsafe {
|
||||||
|
core::mem::transmute::<
|
||||||
|
::std::boxed::Box<Entity>,
|
||||||
|
::std::boxed::Box<bevy::ecs::entity::Entity>,
|
||||||
|
>(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn as_any(&self) -> &dyn ::core::any::Any {
|
||||||
|
// this is changed
|
||||||
|
unsafe { core::mem::transmute::<&Entity, &bevy::ecs::entity::Entity>(self) }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
|
||||||
|
// this is changed
|
||||||
|
unsafe { core::mem::transmute::<&mut Entity, &mut bevy::ecs::entity::Entity>(self) }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn into_reflect(
|
||||||
|
self: ::std::boxed::Box<Self>,
|
||||||
|
) -> ::std::boxed::Box<dyn bevy_reflect::Reflect> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn clone_value(&self) -> ::std::boxed::Box<dyn bevy_reflect::Reflect> {
|
||||||
|
::std::boxed::Box::new(::core::clone::Clone::clone(self))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn try_apply(
|
||||||
|
&mut self,
|
||||||
|
value: &dyn bevy_reflect::Reflect,
|
||||||
|
) -> ::core::result::Result<(), bevy_reflect::ApplyError> {
|
||||||
|
let any = bevy_reflect::Reflect::as_any(value);
|
||||||
|
if let ::core::option::Option::Some(value) =
|
||||||
|
<dyn ::core::any::Any>::downcast_ref::<Self>(any)
|
||||||
|
{
|
||||||
|
*self = ::core::clone::Clone::clone(value);
|
||||||
|
} else {
|
||||||
|
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedTypes {
|
||||||
|
from_type: ::core::convert::Into::into(
|
||||||
|
bevy_reflect::DynamicTypePath::reflect_type_path(value),
|
||||||
|
),
|
||||||
|
to_type: ::core::convert::Into::into(
|
||||||
|
<Self as bevy_reflect::TypePath>::type_path(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
::core::result::Result::Ok(())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn set(
|
||||||
|
&mut self,
|
||||||
|
value: ::std::boxed::Box<dyn bevy_reflect::Reflect>,
|
||||||
|
) -> ::core::result::Result<(), ::std::boxed::Box<dyn bevy_reflect::Reflect>> {
|
||||||
|
*self = <dyn bevy_reflect::Reflect>::take(value)?;
|
||||||
|
::core::result::Result::Ok(())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
|
||||||
|
bevy_reflect::ReflectKind::Value
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
|
||||||
|
bevy_reflect::ReflectRef::Value(self)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
|
||||||
|
bevy_reflect::ReflectMut::Value(self)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn reflect_owned(self: ::std::boxed::Box<Self>) -> bevy_reflect::ReflectOwned {
|
||||||
|
bevy_reflect::ReflectOwned::Value(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl bevy_reflect::FromReflect for Entity
|
||||||
|
where
|
||||||
|
Self: ::core::any::Any + ::core::marker::Send + ::core::marker::Sync,
|
||||||
|
{
|
||||||
|
fn from_reflect(reflect: &dyn bevy_reflect::Reflect) -> ::core::option::Option<Self> {
|
||||||
|
::core::option::Option::Some(::core::clone::Clone::clone(
|
||||||
|
<dyn ::core::any::Any>::downcast_ref::<Entity>(
|
||||||
|
<dyn bevy_reflect::Reflect>::as_any(reflect),
|
||||||
|
)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -7,6 +7,8 @@ pub use ronstring_to_reflect_component::*;
|
|||||||
pub mod process_gltfs;
|
pub mod process_gltfs;
|
||||||
pub use process_gltfs::*;
|
pub use process_gltfs::*;
|
||||||
|
|
||||||
|
mod fake_entity;
|
||||||
|
|
||||||
pub mod blender_settings;
|
pub mod blender_settings;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
|
@ -1,20 +1,26 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
core::Name,
|
core::Name,
|
||||||
ecs::{
|
ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Added, Without},
|
query::{Added, Without},
|
||||||
reflect::{AppTypeRegistry, ReflectComponent},
|
reflect::{AppTypeRegistry, ReflectComponent},
|
||||||
world::World,
|
world::{DeferredWorld, World},
|
||||||
},
|
},
|
||||||
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
|
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
|
||||||
hierarchy::Parent,
|
hierarchy::Parent,
|
||||||
log::{debug, warn},
|
log::{debug, warn},
|
||||||
|
prelude::HierarchyQueryExt,
|
||||||
reflect::{Reflect, TypeRegistration},
|
reflect::{Reflect, TypeRegistration},
|
||||||
|
scene::SceneInstance,
|
||||||
utils::HashMap,
|
utils::HashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{ronstring_to_reflect_component, GltfProcessed};
|
use crate::{ronstring_to_reflect_component, GltfProcessed};
|
||||||
|
|
||||||
|
use super::fake_entity::{self, BadWorldAccess};
|
||||||
|
|
||||||
// , mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>>
|
// , mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>>
|
||||||
fn find_entity_components(
|
fn find_entity_components(
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
@ -57,77 +63,136 @@ fn find_entity_components(
|
|||||||
|
|
||||||
/// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection
|
/// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection
|
||||||
pub fn add_components_from_gltf_extras(world: &mut World) {
|
pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
let mut extras = world.query_filtered::<(Entity, Option<&Name>, &GltfExtras, Option<&Parent>), (Added<GltfExtras>, Without<GltfProcessed>)>();
|
let mut extras = world.query_filtered::<(Entity, Option<&Name>, &GltfExtras), (Added<GltfExtras>, Without<GltfProcessed>)>();
|
||||||
let mut scene_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfSceneExtras, Option<&Parent>), (Added<GltfSceneExtras>, Without<GltfProcessed>)>();
|
let mut scene_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfSceneExtras), (Added<GltfSceneExtras>, Without<GltfProcessed>)>();
|
||||||
let mut mesh_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMeshExtras, Option<&Parent>), (Added<GltfMeshExtras>, Without<GltfProcessed>)>();
|
let mut mesh_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMeshExtras), (Added<GltfMeshExtras>, Without<GltfProcessed>)>();
|
||||||
let mut material_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMaterialExtras, Option<&Parent>), (Added<GltfMaterialExtras>, Without<GltfProcessed>)>();
|
let mut material_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMaterialExtras), (Added<GltfMaterialExtras>, Without<GltfProcessed>)>();
|
||||||
|
|
||||||
|
let mut scene_instances = world.query::<&SceneInstance>();
|
||||||
|
|
||||||
|
let mut hierarchy_state = world.query::<&Parent>();
|
||||||
|
let mut __unsafe_dw = DeferredWorld::from(unsafe { &mut *(world as *mut _) });
|
||||||
|
let hierarchy = __unsafe_dw.query(&mut hierarchy_state);
|
||||||
|
|
||||||
let mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>> =
|
let mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>> =
|
||||||
HashMap::new();
|
HashMap::new();
|
||||||
|
|
||||||
// let gltf_components_config = world.resource::<GltfComponentsConfig>();
|
// let gltf_components_config = world.resource::<GltfComponentsConfig>();
|
||||||
|
|
||||||
for (entity, name, extra, parent) in extras.iter(world) {
|
unsafe {
|
||||||
|
// SAFETY: we don't do anything harmful until taking this, and have full world access
|
||||||
|
fake_entity::BAD_WORLD_ACCESS.set(Some(BadWorldAccess::new(world)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entity, name, extra) in extras.iter(world) {
|
||||||
|
let parent = hierarchy.get(entity).ok();
|
||||||
debug!(
|
debug!(
|
||||||
"Gltf Extra: Name: {:?}, entity {:?}, parent: {:?}, extras {:?}",
|
"Gltf Extra: Name: {:?}, entity {:?}, parent: {:?}, extras {:?}",
|
||||||
name, entity, parent, extra
|
name, entity, parent, extra
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(instance) = hierarchy
|
||||||
|
.iter_ancestors(entity)
|
||||||
|
.find_map(|p| scene_instances.get(world, p).ok())
|
||||||
|
{
|
||||||
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
|
} else {
|
||||||
|
warn!("Can't find higher-hierarchy `SceneInstance` for entity '{name:?}'");
|
||||||
|
fake_entity::INSTANCE_ID.set(None);
|
||||||
|
};
|
||||||
|
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
let type_registry: &AppTypeRegistry = world.resource();
|
||||||
let type_registry = type_registry.read();
|
let mut type_registry = type_registry.write();
|
||||||
let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry);
|
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);
|
||||||
// let name = name.unwrap_or(&Name::new(""));
|
// let name = name.unwrap_or(&Name::new(""));
|
||||||
|
|
||||||
let (target_entity, updated_components) =
|
let (target_entity, updated_components) =
|
||||||
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
||||||
|
|
||||||
entity_components.insert(target_entity, updated_components);
|
entity_components.insert(target_entity, updated_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, name, extra, parent) in scene_extras.iter(world) {
|
for (entity, name, extra) in scene_extras.iter(world) {
|
||||||
|
let parent = hierarchy.get(entity).ok();
|
||||||
debug!(
|
debug!(
|
||||||
"Gltf Scene Extra: Name: {:?}, entity {:?}, parent: {:?}, scene_extras {:?}",
|
"Gltf Scene Extra: Name: {:?}, entity {:?}, parent: {:?}, scene_extras {:?}",
|
||||||
name, entity, parent, extra
|
name, entity, parent, extra
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(instance) = hierarchy
|
||||||
|
.iter_ancestors(entity)
|
||||||
|
.find_map(|p| scene_instances.get(world, p).ok())
|
||||||
|
{
|
||||||
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
|
} else {
|
||||||
|
warn!("Can't find higher-hierarchy `SceneInstance` for entity '{name:?}'");
|
||||||
|
fake_entity::INSTANCE_ID.set(None);
|
||||||
|
};
|
||||||
|
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
let type_registry: &AppTypeRegistry = world.resource();
|
||||||
let type_registry = type_registry.read();
|
let mut type_registry = type_registry.write();
|
||||||
let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry);
|
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);
|
||||||
|
|
||||||
let (target_entity, updated_components) =
|
let (target_entity, updated_components) =
|
||||||
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
||||||
entity_components.insert(target_entity, updated_components);
|
entity_components.insert(target_entity, updated_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, name, extra, parent) in mesh_extras.iter(world) {
|
for (entity, name, extra) in mesh_extras.iter(world) {
|
||||||
|
let parent = hierarchy.get(entity).ok();
|
||||||
debug!(
|
debug!(
|
||||||
"Gltf Mesh Extra: Name: {:?}, entity {:?}, parent: {:?}, mesh_extras {:?}",
|
"Gltf Mesh Extra: Name: {:?}, entity {:?}, parent: {:?}, mesh_extras {:?}",
|
||||||
name, entity, parent, extra
|
name, entity, parent, extra
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(instance) = hierarchy
|
||||||
|
.iter_ancestors(entity)
|
||||||
|
.find_map(|p| scene_instances.get(world, p).ok())
|
||||||
|
{
|
||||||
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
|
} else {
|
||||||
|
warn!("Can't find higher-hierarchy `SceneInstance` for entity '{name:?}'");
|
||||||
|
fake_entity::INSTANCE_ID.set(None);
|
||||||
|
};
|
||||||
|
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
let type_registry: &AppTypeRegistry = world.resource();
|
||||||
let type_registry = type_registry.read();
|
let mut type_registry = type_registry.write();
|
||||||
let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry);
|
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);
|
||||||
|
|
||||||
let (target_entity, updated_components) =
|
let (target_entity, updated_components) =
|
||||||
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
||||||
entity_components.insert(target_entity, updated_components);
|
entity_components.insert(target_entity, updated_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, name, extra, parent) in material_extras.iter(world) {
|
for (entity, name, extra) in material_extras.iter(world) {
|
||||||
|
let parent = hierarchy.get(entity).ok();
|
||||||
debug!(
|
debug!(
|
||||||
"Name: {:?}, entity {:?}, parent: {:?}, material_extras {:?}",
|
"Name: {:?}, entity {:?}, parent: {:?}, material_extras {:?}",
|
||||||
name, entity, parent, extra
|
name, entity, parent, extra
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(instance) = hierarchy
|
||||||
|
.iter_ancestors(entity)
|
||||||
|
.find_map(|p| scene_instances.get(world, p).ok())
|
||||||
|
{
|
||||||
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
|
} else {
|
||||||
|
warn!("Can't find higher-hierarchy `SceneInstance` for entity '{name:?}'");
|
||||||
|
fake_entity::INSTANCE_ID.set(None);
|
||||||
|
};
|
||||||
|
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
let type_registry: &AppTypeRegistry = world.resource();
|
||||||
let type_registry = type_registry.read();
|
let mut type_registry = type_registry.write();
|
||||||
let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry);
|
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);
|
||||||
|
|
||||||
let (target_entity, updated_components) =
|
let (target_entity, updated_components) =
|
||||||
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
||||||
entity_components.insert(target_entity, updated_components);
|
entity_components.insert(target_entity, updated_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fake_entity::BAD_WORLD_ACCESS.set(None);
|
||||||
|
fake_entity::INSTANCE_ID.set(None);
|
||||||
|
|
||||||
for (entity, components) in entity_components {
|
for (entity, components) in entity_components {
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
let type_registry: &AppTypeRegistry = world.resource();
|
||||||
let type_registry = type_registry.clone();
|
let type_registry = type_registry.clone();
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
use bevy::log::{debug, warn};
|
use std::any::TypeId;
|
||||||
use bevy::reflect::serde::ReflectDeserializer;
|
|
||||||
use bevy::reflect::{Reflect, TypeRegistration, TypeRegistry};
|
use bevy::log::{debug, info, warn};
|
||||||
|
use bevy::reflect::serde::{ReflectDeserializer, ReflectSerializer};
|
||||||
|
use bevy::reflect::{GetTypeRegistration, Reflect, TypeRegistration, TypeRegistry};
|
||||||
use bevy::utils::HashMap;
|
use bevy::utils::HashMap;
|
||||||
use ron::Value;
|
use ron::Value;
|
||||||
use serde::de::DeserializeSeed;
|
use serde::de::DeserializeSeed;
|
||||||
|
|
||||||
use super::capitalize_first_letter;
|
use super::{capitalize_first_letter, fake_entity};
|
||||||
|
|
||||||
pub fn ronstring_to_reflect_component(
|
pub fn ronstring_to_reflect_component(
|
||||||
ron_string: &str,
|
ron_string: &str,
|
||||||
type_registry: &TypeRegistry,
|
type_registry: &mut TypeRegistry,
|
||||||
) -> Vec<(Box<dyn Reflect>, TypeRegistration)> {
|
) -> Vec<(Box<dyn Reflect>, TypeRegistration)> {
|
||||||
let lookup: HashMap<String, Value> = ron::from_str(ron_string).unwrap();
|
let lookup: HashMap<String, Value> = ron::from_str(ron_string).unwrap();
|
||||||
let mut components: Vec<(Box<dyn Reflect>, TypeRegistration)> = Vec::new();
|
let mut components: Vec<(Box<dyn Reflect>, TypeRegistration)> = Vec::new();
|
||||||
@ -96,10 +98,16 @@ fn components_string_to_components(
|
|||||||
|
|
||||||
fn bevy_components_string_to_components(
|
fn bevy_components_string_to_components(
|
||||||
parsed_value: String,
|
parsed_value: String,
|
||||||
type_registry: &TypeRegistry,
|
type_registry: &mut TypeRegistry,
|
||||||
components: &mut Vec<(Box<dyn Reflect>, TypeRegistration)>,
|
components: &mut Vec<(Box<dyn Reflect>, TypeRegistration)>,
|
||||||
) {
|
) {
|
||||||
let lookup: HashMap<String, Value> = ron::from_str(&parsed_value).unwrap();
|
let lookup: HashMap<String, Value> = ron::from_str(&parsed_value).unwrap();
|
||||||
|
|
||||||
|
let recovery_entity_type = type_registry
|
||||||
|
.get(TypeId::of::<bevy::ecs::entity::Entity>())
|
||||||
|
.cloned();
|
||||||
|
type_registry.overwrite_registration(fake_entity::Entity::get_type_registration());
|
||||||
|
|
||||||
for (key, value) in lookup.into_iter() {
|
for (key, value) in lookup.into_iter() {
|
||||||
let parsed_value: String = match value.clone() {
|
let parsed_value: String = match value.clone() {
|
||||||
Value::String(str) => str,
|
Value::String(str) => str,
|
||||||
@ -121,10 +129,10 @@ fn bevy_components_string_to_components(
|
|||||||
let reflect_deserializer = ReflectDeserializer::new(type_registry);
|
let reflect_deserializer = ReflectDeserializer::new(type_registry);
|
||||||
let component = reflect_deserializer
|
let component = reflect_deserializer
|
||||||
.deserialize(&mut deserializer)
|
.deserialize(&mut deserializer)
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|e| {
|
||||||
panic!(
|
panic!(
|
||||||
"failed to deserialize component {} with value: {:?}",
|
"failed to deserialize component '{}' with value '{:?}': {:?}",
|
||||||
key, value
|
key, value, e
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -136,4 +144,10 @@ fn bevy_components_string_to_components(
|
|||||||
warn!("no type registration for {}", key);
|
warn!("no type registration for {}", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(original_entity) = recovery_entity_type {
|
||||||
|
type_registry.overwrite_registration(original_entity);
|
||||||
|
} else {
|
||||||
|
warn!("There isn't an original type registration for `bevy_ecs::entity::Entity` but it was overwriten. Stuff may break and/or panic. Make sure that you register it!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
10
examples/relations/Cargo.toml
Normal file
10
examples/relations/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "blenvy_relations_example"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy = { version = "0.14", features = ["dynamic_linking"] }
|
||||||
|
bevy-inspector-egui = "0.25.2"
|
||||||
|
blenvy = { path = "../../crates/blenvy" }
|
41
examples/relations/README.md
Normal file
41
examples/relations/README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Basic relations example/demo
|
||||||
|
|
||||||
|
This example showcases how to refer to another `Entity` inside Bevy components added to objects/ blueprints/ meshes and materials extracted from the gltf files
|
||||||
|
|
||||||
|
## Running this example
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo run --features bevy/dynamic_linking
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wasm instructions
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
as per the bevy documentation:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rustup target add wasm32-unknown-unknown
|
||||||
|
cargo install wasm-bindgen-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building this example
|
||||||
|
|
||||||
|
navigate to the current folder , and then
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo build --release --target wasm32-unknown-unknown --target-dir ./target
|
||||||
|
wasm-bindgen --out-name wasm_example \
|
||||||
|
--out-dir ./target/wasm \
|
||||||
|
--target web target/wasm32-unknown-unknown/release/bevy_gltf_blueprints_basic_wasm_example.wasm
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running this example
|
||||||
|
|
||||||
|
run a web server in the current folder, and navigate to the page, you should see the example in your browser
|
||||||
|
|
||||||
|
## Additional notes
|
||||||
|
|
||||||
|
- You usually define either the Components directly or use `Proxy components` that get replaced in Bevy systems with the actual Components that you want (usually when for some reason, ie external crates with unregistered components etc) you cannot use the components directly.
|
BIN
examples/relations/art/untitled.blend
Normal file
BIN
examples/relations/art/untitled.blend
Normal file
Binary file not shown.
BIN
examples/relations/assets/levels/World.glb
Normal file
BIN
examples/relations/assets/levels/World.glb
Normal file
Binary file not shown.
5
examples/relations/assets/levels/World.meta.ron
Normal file
5
examples/relations/assets/levels/World.meta.ron
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
(
|
||||||
|
assets:
|
||||||
|
[
|
||||||
|
]
|
||||||
|
)
|
BIN
examples/relations/assets/materials/Dots Stroke.glb
Normal file
BIN
examples/relations/assets/materials/Dots Stroke.glb
Normal file
Binary file not shown.
BIN
examples/relations/assets/materials/Material.glb
Normal file
BIN
examples/relations/assets/materials/Material.glb
Normal file
Binary file not shown.
14582
examples/relations/assets/registry.json
Normal file
14582
examples/relations/assets/registry.json
Normal file
File diff suppressed because it is too large
Load Diff
50
examples/relations/src/main.rs
Normal file
50
examples/relations/src/main.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||||
|
use blenvy::{BlenvyPlugin, BlueprintInfo, GameWorldTag, HideUntilReady, SpawnBlueprint};
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct TupleRelations(Entity);
|
||||||
|
|
||||||
|
#[derive(Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct BigRelations {
|
||||||
|
main: Entity,
|
||||||
|
other: Vec<Entity>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins((
|
||||||
|
DefaultPlugins.set(AssetPlugin::default()),
|
||||||
|
BlenvyPlugin::default(),
|
||||||
|
WorldInspectorPlugin::new(),
|
||||||
|
))
|
||||||
|
.register_type::<TupleRelations>()
|
||||||
|
.register_type::<BigRelations>()
|
||||||
|
.add_systems(Startup, setup_game)
|
||||||
|
.add_systems(Update, (print_names, print_tuple_relations))
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_game(mut commands: Commands) {
|
||||||
|
// here we actually spawn our game world/level
|
||||||
|
commands.spawn((
|
||||||
|
BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info...
|
||||||
|
SpawnBlueprint, // and spawnblueprint to tell blenvy to spawn the blueprint now
|
||||||
|
HideUntilReady, // only reveal the level once it is ready
|
||||||
|
GameWorldTag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_names(query: Query<(Entity, &Name), Added<Name>>) {
|
||||||
|
for (entity, name) in &query {
|
||||||
|
info!("[EXAMPLE] {name} is {entity}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_tuple_relations(query: Query<(&Name, &TupleRelations), Added<TupleRelations>>) {
|
||||||
|
for (name, r) in &query {
|
||||||
|
info!("[EXAMPLE] {name} has the relation {r:?}")
|
||||||
|
}
|
||||||
|
}
|
@ -10,21 +10,23 @@ conversion_tables = {
|
|||||||
|
|
||||||
"glam::Vec2": lambda value: "Vec2(x:"+str(value[0])+ ", y:"+str(value[1])+")",
|
"glam::Vec2": lambda value: "Vec2(x:"+str(value[0])+ ", y:"+str(value[1])+")",
|
||||||
"glam::DVec2": lambda value: "DVec2(x:"+str(value[0])+ ", y:"+str(value[1])+")",
|
"glam::DVec2": lambda value: "DVec2(x:"+str(value[0])+ ", y:"+str(value[1])+")",
|
||||||
"glam::UVec2": lambda value: "UVec2(x:"+str(value[0])+ ", y:"+str(value[1])+")",
|
"glam::UVec2": lambda value: "UVec2(x:"+str(int(value[0]))+ ", y:"+str(int(value[1]))+")",
|
||||||
|
|
||||||
"glam::Vec3": lambda value: "Vec3(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+")",
|
"glam::Vec3": lambda value: "Vec3(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+")",
|
||||||
"glam::Vec3A": lambda value: "Vec3A(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+")",
|
"glam::Vec3A": lambda value: "Vec3A(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+")",
|
||||||
"glam::UVec3": lambda value: "UVec3(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+")",
|
"glam::UVec3": lambda value: "UVec3(x:"+str(int(value[0]))+ ", y:"+str(int(value[1]))+ ", z:"+str(int(value[2]))+")",
|
||||||
|
|
||||||
"glam::Vec4": lambda value: "Vec4(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+ ", w:"+str(value[3])+")",
|
"glam::Vec4": lambda value: "Vec4(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+ ", w:"+str(value[3])+")",
|
||||||
"glam::DVec4": lambda value: "DVec4(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+ ", w:"+str(value[3])+")",
|
"glam::DVec4": lambda value: "DVec4(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+ ", w:"+str(value[3])+")",
|
||||||
"glam::UVec4": lambda value: "UVec4(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+ ", w:"+str(value[3])+")",
|
"glam::UVec4": lambda value: "UVec4(x:"+str(int(value[0]))+ ", y:"+str(int(value[1]))+ ", z:"+str(int(value[2]))+ ", w:"+str(int(value[3]))+")",
|
||||||
|
|
||||||
"glam::Quat": lambda value: "Quat(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+ ", w:"+str(value[3])+")",
|
"glam::Quat": lambda value: "Quat(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+ ", w:"+str(value[3])+")",
|
||||||
|
|
||||||
"bevy_color::srgba::Srgba": lambda value: "Srgba(red:"+str(value[0])+ ", green:"+str(value[1])+ ", blue:"+str(value[2])+ ", alpha:"+str(value[3])+ ")",
|
"bevy_color::srgba::Srgba": lambda value: "Srgba(red:"+str(value[0])+ ", green:"+str(value[1])+ ", blue:"+str(value[2])+ ", alpha:"+str(value[3])+ ")",
|
||||||
"bevy_color::linear_rgba::LinearRgba": lambda value: "LinearRgba(red:"+str(value[0])+ ", green:"+str(value[1])+ ", blue:"+str(value[2])+ ", alpha:"+str(value[3])+ ")",
|
"bevy_color::linear_rgba::LinearRgba": lambda value: "LinearRgba(red:"+str(value[0])+ ", green:"+str(value[1])+ ", blue:"+str(value[2])+ ", alpha:"+str(value[3])+ ")",
|
||||||
"bevy_color::hsva::Hsva": lambda value: "Hsva(hue:"+str(value[0])+ ", saturation:"+str(value[1])+ ", value:"+str(value[2])+ ", alpha:"+str(value[3])+ ")",
|
"bevy_color::hsva::Hsva": lambda value: "Hsva(hue:"+str(value[0])+ ", saturation:"+str(value[1])+ ", value:"+str(value[2])+ ", alpha:"+str(value[3])+ ")",
|
||||||
|
|
||||||
|
"bevy_ecs::entity::Entity": lambda value: 'Entity(name: ' + (('Some("' + str(value.name) + '")') if value is not None else "None") + ')',
|
||||||
}
|
}
|
||||||
|
|
||||||
#converts the value of a property group(no matter its complexity) into a single custom property value
|
#converts the value of a property group(no matter its complexity) into a single custom property value
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import bpy
|
||||||
from bpy_types import PropertyGroup
|
from bpy_types import PropertyGroup
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@ -126,6 +127,16 @@ def parse_color_hsva(value, caster, typeName):
|
|||||||
parsed = parse_struct_string(value.replace(typeName,"").replace("(", "").replace(")","") )
|
parsed = parse_struct_string(value.replace(typeName,"").replace("(", "").replace(")","") )
|
||||||
return [caster(parsed['hue']), caster(parsed['saturation']), caster(parsed['value']), caster(parsed['alpha'])]
|
return [caster(parsed['hue']), caster(parsed['saturation']), caster(parsed['value']), caster(parsed['alpha'])]
|
||||||
|
|
||||||
|
def parse_entity(value):
|
||||||
|
# strip 'Entity(name: <VAL>)' to just '<VAL>'
|
||||||
|
value = value[13:-1]
|
||||||
|
if value.startswith("Some"):
|
||||||
|
# strip 'Some("<VAL>")' to just '<VAL>'
|
||||||
|
value = value[6:-2]
|
||||||
|
return bpy.context.scene.objects[value]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def to_int(input):
|
def to_int(input):
|
||||||
return int(float(input))
|
return int(float(input))
|
||||||
|
|
||||||
@ -171,7 +182,7 @@ type_mappings = {
|
|||||||
"bevy_color::linear_rgba::LinearRgba": lambda value: parse_color_rgba(value, float, "LinearRgba"),
|
"bevy_color::linear_rgba::LinearRgba": lambda value: parse_color_rgba(value, float, "LinearRgba"),
|
||||||
"bevy_color::hsva::Hsva": lambda value: parse_color_hsva(value, float, "Hsva"),
|
"bevy_color::hsva::Hsva": lambda value: parse_color_hsva(value, float, "Hsva"),
|
||||||
|
|
||||||
'bevy_ecs::entity::Entity': lambda value: int(value),
|
"bevy_ecs::entity::Entity": parse_entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
def is_def_value_type(definition, registry):
|
def is_def_value_type(definition, registry):
|
||||||
|
@ -3,6 +3,7 @@ from .utils import generate_wrapper_propertyGroup
|
|||||||
from . import process_component
|
from . import process_component
|
||||||
|
|
||||||
def process_list(registry, definition, update, nesting_long_names=[]):
|
def process_list(registry, definition, update, nesting_long_names=[]):
|
||||||
|
blender_property_mapping = registry.blender_property_mapping
|
||||||
value_types_defaults = registry.value_types_defaults
|
value_types_defaults = registry.value_types_defaults
|
||||||
type_infos = registry.type_infos
|
type_infos = registry.type_infos
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ def process_list(registry, definition, update, nesting_long_names=[]):
|
|||||||
|
|
||||||
item_definition = type_infos[ref_name]
|
item_definition = type_infos[ref_name]
|
||||||
item_long_name = item_definition["long_name"]
|
item_long_name = item_definition["long_name"]
|
||||||
is_item_value_type = item_long_name in value_types_defaults
|
is_item_value_type = item_long_name in blender_property_mapping
|
||||||
|
|
||||||
property_group_class = None
|
property_group_class = None
|
||||||
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
||||||
|
@ -3,6 +3,7 @@ from .utils import generate_wrapper_propertyGroup
|
|||||||
from . import process_component
|
from . import process_component
|
||||||
|
|
||||||
def process_map(registry, definition, update, nesting_long_names=[]):
|
def process_map(registry, definition, update, nesting_long_names=[]):
|
||||||
|
blender_property_mapping = registry.blender_property_mapping
|
||||||
value_types_defaults = registry.value_types_defaults
|
value_types_defaults = registry.value_types_defaults
|
||||||
type_infos = registry.type_infos
|
type_infos = registry.type_infos
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ def process_map(registry, definition, update, nesting_long_names=[]):
|
|||||||
if key_ref_name in type_infos:
|
if key_ref_name in type_infos:
|
||||||
key_definition = type_infos[key_ref_name]
|
key_definition = type_infos[key_ref_name]
|
||||||
original_long_name = key_definition["long_name"]
|
original_long_name = key_definition["long_name"]
|
||||||
is_key_value_type = original_long_name in value_types_defaults
|
is_key_value_type = original_long_name in blender_property_mapping
|
||||||
definition_link = definition["keyType"]["type"]["$ref"]
|
definition_link = definition["keyType"]["type"]["$ref"]
|
||||||
|
|
||||||
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
||||||
@ -38,7 +39,7 @@ def process_map(registry, definition, update, nesting_long_names=[]):
|
|||||||
if value_ref_name in type_infos:
|
if value_ref_name in type_infos:
|
||||||
value_definition = type_infos[value_ref_name]
|
value_definition = type_infos[value_ref_name]
|
||||||
original_long_name = value_definition["long_name"]
|
original_long_name = value_definition["long_name"]
|
||||||
is_value_value_type = original_long_name in value_types_defaults
|
is_value_value_type = original_long_name in blender_property_mapping
|
||||||
definition_link = definition["valueType"]["type"]["$ref"]
|
definition_link = definition["valueType"]["type"]["$ref"]
|
||||||
|
|
||||||
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
||||||
|
@ -17,12 +17,15 @@ def process_structs(registry, definition, properties, update, nesting_long_names
|
|||||||
if ref_name in type_infos:
|
if ref_name in type_infos:
|
||||||
original = type_infos[ref_name]
|
original = type_infos[ref_name]
|
||||||
original_long_name = original["long_name"]
|
original_long_name = original["long_name"]
|
||||||
is_value_type = original_long_name in value_types_defaults
|
|
||||||
value = value_types_defaults[original_long_name] if is_value_type else None
|
is_value_type = original_long_name in blender_property_mapping
|
||||||
|
has_default_value = original_long_name in value_types_defaults
|
||||||
|
|
||||||
|
value = value_types_defaults[original_long_name] if has_default_value else None
|
||||||
default_values[property_name] = value
|
default_values[property_name] = value
|
||||||
|
|
||||||
if is_value_type:
|
if is_value_type:
|
||||||
if original_long_name in blender_property_mapping:
|
if has_default_value:
|
||||||
blender_property_def = blender_property_mapping[original_long_name]
|
blender_property_def = blender_property_mapping[original_long_name]
|
||||||
blender_property = blender_property_def["type"](
|
blender_property = blender_property_def["type"](
|
||||||
**blender_property_def["presets"],# we inject presets first
|
**blender_property_def["presets"],# we inject presets first
|
||||||
@ -31,6 +34,14 @@ def process_structs(registry, definition, properties, update, nesting_long_names
|
|||||||
update = update
|
update = update
|
||||||
)
|
)
|
||||||
__annotations__[property_name] = blender_property
|
__annotations__[property_name] = blender_property
|
||||||
|
else:
|
||||||
|
blender_property_def = blender_property_mapping[original_long_name]
|
||||||
|
blender_property = blender_property_def["type"](
|
||||||
|
**blender_property_def["presets"],# we inject presets first
|
||||||
|
name = property_name,
|
||||||
|
update = update
|
||||||
|
)
|
||||||
|
__annotations__[property_name] = blender_property
|
||||||
else:
|
else:
|
||||||
original_long_name = original["long_name"]
|
original_long_name = original["long_name"]
|
||||||
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting_long_names+[property_name])
|
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting_long_names+[property_name])
|
||||||
|
@ -20,14 +20,16 @@ def process_tupples(registry, definition, prefixItems, update, nesting_long_name
|
|||||||
if ref_name in type_infos:
|
if ref_name in type_infos:
|
||||||
original = type_infos[ref_name]
|
original = type_infos[ref_name]
|
||||||
original_long_name = original["long_name"]
|
original_long_name = original["long_name"]
|
||||||
is_value_type = original_long_name in value_types_defaults
|
|
||||||
|
|
||||||
value = value_types_defaults[original_long_name] if is_value_type else None
|
is_value_type = original_long_name in blender_property_mapping
|
||||||
|
has_default_value = original_long_name in value_types_defaults
|
||||||
|
|
||||||
|
value = value_types_defaults[original_long_name] if has_default_value else None
|
||||||
default_values.append(value)
|
default_values.append(value)
|
||||||
prefix_infos.append(original)
|
prefix_infos.append(original)
|
||||||
|
|
||||||
if is_value_type:
|
if is_value_type:
|
||||||
if original_long_name in blender_property_mapping:
|
if has_default_value:
|
||||||
blender_property_def = blender_property_mapping[original_long_name]
|
blender_property_def = blender_property_mapping[original_long_name]
|
||||||
blender_property = blender_property_def["type"](
|
blender_property = blender_property_def["type"](
|
||||||
**blender_property_def["presets"],# we inject presets first
|
**blender_property_def["presets"],# we inject presets first
|
||||||
@ -36,6 +38,15 @@ def process_tupples(registry, definition, prefixItems, update, nesting_long_name
|
|||||||
update= update
|
update= update
|
||||||
)
|
)
|
||||||
|
|
||||||
|
__annotations__[property_name] = blender_property
|
||||||
|
else:
|
||||||
|
blender_property_def = blender_property_mapping[original_long_name]
|
||||||
|
blender_property = blender_property_def["type"](
|
||||||
|
**blender_property_def["presets"],# we inject presets first
|
||||||
|
name = property_name,
|
||||||
|
update= update
|
||||||
|
)
|
||||||
|
|
||||||
__annotations__[property_name] = blender_property
|
__annotations__[property_name] = blender_property
|
||||||
else:
|
else:
|
||||||
original_long_name = original["long_name"]
|
original_long_name = original["long_name"]
|
||||||
|
@ -11,7 +11,9 @@ from bpy_types import PropertyGroup
|
|||||||
def generate_wrapper_propertyGroup(wrapped_type_long_name, item_long_name, definition_link, registry, update, nesting_long_names=[]):
|
def generate_wrapper_propertyGroup(wrapped_type_long_name, item_long_name, definition_link, registry, update, nesting_long_names=[]):
|
||||||
value_types_defaults = registry.value_types_defaults
|
value_types_defaults = registry.value_types_defaults
|
||||||
blender_property_mapping = registry.blender_property_mapping
|
blender_property_mapping = registry.blender_property_mapping
|
||||||
is_item_value_type = item_long_name in value_types_defaults
|
|
||||||
|
is_item_value_type = item_long_name in blender_property_mapping
|
||||||
|
has_item_default_value = item_long_name in value_types_defaults
|
||||||
|
|
||||||
|
|
||||||
wrapper_name = "wrapper_" + wrapped_type_long_name
|
wrapper_name = "wrapper_" + wrapped_type_long_name
|
||||||
@ -42,15 +44,23 @@ def generate_wrapper_propertyGroup(wrapped_type_long_name, item_long_name, defin
|
|||||||
|
|
||||||
|
|
||||||
blender_property = StringProperty(default="", update=update)
|
blender_property = StringProperty(default="", update=update)
|
||||||
if item_long_name in blender_property_mapping:
|
if is_item_value_type:
|
||||||
value = value_types_defaults[item_long_name] if is_item_value_type else None
|
value = value_types_defaults[item_long_name] if has_item_default_value else None
|
||||||
blender_property_def = blender_property_mapping[item_long_name]
|
if has_item_default_value:
|
||||||
blender_property = blender_property_def["type"](
|
blender_property_def = blender_property_mapping[item_long_name]
|
||||||
**blender_property_def["presets"],# we inject presets first
|
blender_property = blender_property_def["type"](
|
||||||
name = "property_name",
|
**blender_property_def["presets"],# we inject presets first
|
||||||
default = value,
|
name = "property_name",
|
||||||
update = update
|
default = value,
|
||||||
)
|
update = update
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
blender_property_def = blender_property_mapping[item_long_name]
|
||||||
|
blender_property = blender_property_def["type"](
|
||||||
|
**blender_property_def["presets"],# we inject presets first
|
||||||
|
name = "property_name",
|
||||||
|
update = update
|
||||||
|
)
|
||||||
|
|
||||||
wrapper_annotations = {
|
wrapper_annotations = {
|
||||||
'0' : blender_property
|
'0' : blender_property
|
||||||
|
@ -25,6 +25,9 @@ def property_group_from_infos(property_group_name, property_group_parameters):
|
|||||||
|
|
||||||
return (property_group_pointer, property_group_class)
|
return (property_group_pointer, property_group_class)
|
||||||
|
|
||||||
|
def is_entity_poll(self, object):
|
||||||
|
return bpy.context.scene in object.users_scene # TODO: only select `object.type`s that get converted to entities and maybe something against other collection(instances)?
|
||||||
|
|
||||||
# this is where we store the information for all available components
|
# this is where we store the information for all available components
|
||||||
class ComponentsRegistry(PropertyGroup):
|
class ComponentsRegistry(PropertyGroup):
|
||||||
registry: bpy.props. StringProperty(
|
registry: bpy.props. StringProperty(
|
||||||
@ -50,7 +53,6 @@ class ComponentsRegistry(PropertyGroup):
|
|||||||
"u32": dict(type=IntProperty, presets=dict(min=0)),
|
"u32": dict(type=IntProperty, presets=dict(min=0)),
|
||||||
"u64": dict(type=IntProperty, presets=dict(min=0)),
|
"u64": dict(type=IntProperty, presets=dict(min=0)),
|
||||||
"u128": dict(type=IntProperty, presets=dict(min=0)),
|
"u128": dict(type=IntProperty, presets=dict(min=0)),
|
||||||
"u64": dict(type=IntProperty, presets=dict(min=0)),
|
|
||||||
"usize": dict(type=IntProperty, presets=dict(min=0)),
|
"usize": dict(type=IntProperty, presets=dict(min=0)),
|
||||||
|
|
||||||
"i8": dict(type=IntProperty, presets=dict()),
|
"i8": dict(type=IntProperty, presets=dict()),
|
||||||
@ -65,17 +67,17 @@ class ComponentsRegistry(PropertyGroup):
|
|||||||
|
|
||||||
"glam::Vec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
|
"glam::Vec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
|
||||||
"glam::DVec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
|
"glam::DVec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
|
||||||
"glam::UVec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
|
"glam::UVec2": {"type": IntVectorProperty, "presets": {"size": 2, "min": 0} },
|
||||||
|
|
||||||
"glam::Vec3": {"type": FloatVectorProperty, "presets": {"size":3} },
|
"glam::Vec3": {"type": FloatVectorProperty, "presets": {"size":3} },
|
||||||
"glam::Vec3A":{"type": FloatVectorProperty, "presets": {"size":3} },
|
"glam::Vec3A":{"type": FloatVectorProperty, "presets": {"size":3} },
|
||||||
"glam::DVec3":{"type": FloatVectorProperty, "presets": {"size":3} },
|
"glam::DVec3":{"type": FloatVectorProperty, "presets": {"size":3} },
|
||||||
"glam::UVec3":{"type": FloatVectorProperty, "presets": {"size":3} },
|
"glam::UVec3":{"type": IntVectorProperty, "presets": {"size":3, "min":0} },
|
||||||
|
|
||||||
"glam::Vec4": {"type": FloatVectorProperty, "presets": {"size":4} },
|
"glam::Vec4": {"type": FloatVectorProperty, "presets": {"size":4} },
|
||||||
"glam::Vec4A": {"type": FloatVectorProperty, "presets": {"size":4} },
|
"glam::Vec4A": {"type": FloatVectorProperty, "presets": {"size":4} },
|
||||||
"glam::DVec4": {"type": FloatVectorProperty, "presets": {"size":4} },
|
"glam::DVec4": {"type": FloatVectorProperty, "presets": {"size":4} },
|
||||||
"glam::UVec4":{"type": FloatVectorProperty, "presets": {"size":4, "min":0.0} },
|
"glam::UVec4":{"type": IntVectorProperty, "presets": {"size":4, "min":0} },
|
||||||
|
|
||||||
"glam::Quat": {"type": FloatVectorProperty, "presets": {"size":4} },
|
"glam::Quat": {"type": FloatVectorProperty, "presets": {"size":4} },
|
||||||
|
|
||||||
@ -90,19 +92,19 @@ class ComponentsRegistry(PropertyGroup):
|
|||||||
|
|
||||||
"enum": dict(type=EnumProperty, presets=dict()),
|
"enum": dict(type=EnumProperty, presets=dict()),
|
||||||
|
|
||||||
'bevy_ecs::entity::Entity': {"type": IntProperty, "presets": {"min":0} },
|
"bevy_ecs::entity::Entity": dict(type = PointerProperty, presets=dict(type = bpy.types.Object, poll = is_entity_poll)),
|
||||||
'bevy_utils::Uuid': dict(type=StringProperty, presets=dict()),
|
"bevy_utils::Uuid": dict(type = StringProperty, presets=dict()),
|
||||||
}
|
}
|
||||||
|
|
||||||
value_types_defaults = {
|
value_types_defaults = {
|
||||||
"string":" ",
|
"string":" ",
|
||||||
"boolean": True,
|
"boolean": False,
|
||||||
"float": 0.0,
|
"float": 0.0,
|
||||||
"uint": 0,
|
"uint": 0,
|
||||||
"int":0,
|
"int":0,
|
||||||
|
|
||||||
# todo : we are re-doing the work of the bevy /rust side here, but it seems more pratical to alway look for the same field name on the blender side for matches
|
# todo : we are re-doing the work of the bevy /rust side here, but it seems more pratical to alway look for the same field name on the blender side for matches
|
||||||
"bool": True,
|
"bool": False,
|
||||||
|
|
||||||
"u8": 0,
|
"u8": 0,
|
||||||
"u16":0,
|
"u16":0,
|
||||||
@ -144,8 +146,7 @@ class ComponentsRegistry(PropertyGroup):
|
|||||||
"bevy_color::linear_rgba::LinearRgba": [1.0, 1.0, 0.0, 1.0],
|
"bevy_color::linear_rgba::LinearRgba": [1.0, 1.0, 0.0, 1.0],
|
||||||
"bevy_color::hsva::Hsva": [1.0, 1.0, 0.0, 1.0],
|
"bevy_color::hsva::Hsva": [1.0, 1.0, 0.0, 1.0],
|
||||||
|
|
||||||
'bevy_ecs::entity::Entity': 0,#4294967295, # this is the same as Bevy's Entity::Placeholder, too big for Blender..sigh
|
"bevy_utils::Uuid": '"'+str(uuid.uuid4())+'"'
|
||||||
'bevy_utils::Uuid': '"'+str(uuid.uuid4())+'"'
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user