initial commit

This commit is contained in:
Rowan 2024-12-10 00:17:59 -06:00
commit 7e3350739a
9 changed files with 5411 additions and 0 deletions

13
.cargo/config.toml Normal file
View file

@ -0,0 +1,13 @@
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold", "-Zshare-generics=y"]
[unstable]
codegen-backend = true
[profile.dev]
codegen-backend = "cranelift"
[profile.dev.package."*"]
codegen-backend = "llvm"

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
target/

4737
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

18
Cargo.toml Normal file
View file

@ -0,0 +1,18 @@
[package]
name = "bevy-blender"
version = "0.1.0"
edition = "2021"
[lib]
name = "bevy_blender"
path = "src/lib.rs"
[dependencies]
bevy = "0.15.0"
ron = "0.8.1"
serde = { version = "1.0.215", features = ["derive"] }
serde_json = "1.0.133"
[dev-dependencies]
bevy = { version = "0.15.0", features = ["dynamic_linking"] }

BIN
assets/gltf_extras.glb Normal file

Binary file not shown.

3
rust-toolchain.toml Normal file
View file

@ -0,0 +1,3 @@
[toolchain]
channel = "nightly"

50
src/lib.rs Normal file
View file

@ -0,0 +1,50 @@
use bevy::prelude::*;
use std::path::PathBuf;
use self::registry::CreateRegistryPlugin;
mod registry;
#[derive(Debug, Resource)]
pub struct BevyBlenderConfig {
pub create_registry: bool,
pub registry_path: PathBuf,
pub type_filter: SceneFilter,
}
impl From<&BevyBlenderPlugin> for BevyBlenderConfig {
fn from(value: &BevyBlenderPlugin) -> Self {
Self {
create_registry: value.create_registry,
registry_path: value.registry_path.clone(),
type_filter: value.type_filter.clone(),
}
}
}
pub struct BevyBlenderPlugin {
create_registry: bool,
registry_path: PathBuf,
type_filter: SceneFilter,
}
impl Default for BevyBlenderPlugin {
fn default() -> Self {
Self {
create_registry: true,
registry_path: "registry.json".into(),
type_filter: SceneFilter::default(),
}
}
}
impl Plugin for BevyBlenderPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
#[cfg(debug_assertions)]
if self.create_registry {
app.add_plugins(CreateRegistryPlugin);
}
app.insert_resource(BevyBlenderConfig::from(self));
}
}

159
src/main.rs Normal file
View file

@ -0,0 +1,159 @@
mod registry;
use bevy::{
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
prelude::*,
};
pub use bevy_blender::{BevyBlenderConfig, BevyBlenderPlugin};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(BevyBlenderPlugin::default())
.add_systems(Startup, setup)
.add_systems(Update, read_gltfs)
.run();
}
//#[derive(Deserialize, Debug, Serialize)]
//struct NestedStruct(String, usize);
//
//#[derive(Deserialize, Debug, Serialize)]
//struct TestStruct {
// pub number: usize,
// pub pair: (char, i32),
// nested: NestedStruct,
//}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
//let cfg = ron::ser::PrettyConfig::new().struct_names(true);
//let r = ron::ser::to_string_pretty(
// &TestStruct {
// number: 11,
// pair: ('r', 69),
// nested: NestedStruct("aeraaraaa".to_string(), 44),
// },
// cfg,
//)
//.unwrap();
//let awera: TestStruct = ron::de::from_str(&r).unwrap();
commands.spawn((
Camera3d::default(),
Transform::from_xyz(2.0, 2.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
));
commands.spawn(DirectionalLight {
shadows_enabled: true,
..default()
});
commands.spawn(SceneRoot(
asset_server.load(GltfAssetLabel::Scene(0).from_asset("gltf_extras.glb")),
));
}
fn read_gltfs(
mut commands: Commands,
extras_q: Query<(Entity, &GltfExtras), Added<GltfExtras>>,
scene_extras_q: Query<(Entity, &GltfSceneExtras), Added<GltfSceneExtras>>,
mesh_extras_q: Query<(Entity, &GltfMeshExtras), Added<GltfMeshExtras>>,
material_extras_q: Query<(Entity, &GltfMaterialExtras), Added<GltfMaterialExtras>>,
) {
for (entity, extras) in extras_q.iter() {
println!("{:?}", extras);
}
for (entity, extras) in scene_extras_q.iter() {
println!("{:?}", extras);
}
for (entity, extras) in mesh_extras_q.iter() {
println!("{:?}", extras);
}
for (entity, extras) in material_extras_q.iter() {
println!("{:?}", extras);
}
}
//#[derive(Component)]
//struct ExampleDisplay;
//
//fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// commands.spawn((
// Camera3d::default(),
// Transform::from_xyz(2.0, 2.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
// ));
//
// commands.spawn(DirectionalLight {
// shadows_enabled: true,
// ..default()
// });
//
// // a barebones scene containing one of each gltf_extra type
// commands.spawn(SceneRoot(
// asset_server.load(GltfAssetLabel::Scene(0).from_asset("gltf_extras.glb")),
// ));
//
// // a place to display the extras on screen
// commands.spawn((
// Text::default(),
// TextFont {
// font_size: 15.,
// ..default()
// },
// Node {
// position_type: PositionType::Absolute,
// top: Val::Px(12.0),
// left: Val::Px(12.0),
// ..default()
// },
// ExampleDisplay,
// ));
//}
//
//fn check_for_gltf_extras(
// gltf_extras_per_entity: Query<
// (
// Entity,
// Option<&Name>,
// Option<&GltfSceneExtras>,
// Option<&GltfExtras>,
// Option<&GltfMeshExtras>,
// Option<&GltfMaterialExtras>,
// ),
// Added<Mesh3d>,
// >,
// mut display: Single<&mut Text, With<ExampleDisplay>>,
//) {
// let mut gltf_extra_infos_lines: Vec<String> = vec![];
//
// for (id, name, scene_extras, extras, mesh_extras, material_extras) in
// gltf_extras_per_entity.iter()
// {
// if scene_extras.is_some()
// || extras.is_some()
// || mesh_extras.is_some()
// || material_extras.is_some()
// {
// let formatted_extras = format!(
// "Extras per entity {} ('Name: {}'):
// - scene extras: {:?}
// - primitive extras: {:?}
// - mesh extras: {:?}
// - material extras: {:?}
// ",
// id,
// name.unwrap_or(&Name::default()),
// scene_extras,
// extras,
// mesh_extras,
// material_extras
// );
// gltf_extra_infos_lines.push(formatted_extras);
// }
// display.0 = gltf_extra_infos_lines.join("\n");
// }
//}

429
src/registry.rs Normal file
View file

@ -0,0 +1,429 @@
use bevy::prelude::*;
use bevy::reflect::{
ArrayInfo, EnumInfo, ListInfo, MapInfo, NamedField, OpaqueInfo, SetInfo, StructInfo,
StructVariantInfo, TupleInfo, TupleStructInfo, TupleVariantInfo, Type, TypeInfo,
TypeRegistration, UnitVariantInfo, UnnamedField, VariantInfo,
};
use bevy::utils::HashMap;
use serde::{Deserialize, Serialize};
use crate::BevyBlenderConfig;
pub(crate) struct CreateRegistryPlugin;
impl Plugin for CreateRegistryPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(Startup, create_registry);
}
}
fn create_registry(config: Res<BevyBlenderConfig>, type_registry: Res<AppTypeRegistry>) {
let type_registry = type_registry.read();
let filter = &config.type_filter;
let types: Vec<RegistryEntry> = type_registry
.iter()
.filter(|t| filter.is_allowed_by_id(t.type_id()))
.map(RegistryEntry::from)
.collect();
println!("{types:?}");
}
#[derive(Debug, Serialize, Deserialize)]
enum SchemaType {
Array,
Object,
Value(ValueVariant),
}
impl From<&NativeType> for SchemaType {
fn from(value: &NativeType) -> Self {
match value {
NativeType::Enum { .. } => SchemaType::Object,
NativeType::List { .. } => SchemaType::Array,
NativeType::Map { .. } => SchemaType::Object,
NativeType::Opaque(value) => SchemaType::Value(ValueVariant::from(value)),
NativeType::Set { .. } => SchemaType::Object,
NativeType::Tuple { .. } => SchemaType::Array,
NativeType::Struct { .. } => SchemaType::Object,
NativeType::Unit => SchemaType::Object,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
enum ValueVariant {
Boolean,
UnsignedInteger,
Integer,
Float,
String,
Object,
}
impl From<&OpaqueVariant> for ValueVariant {
fn from(value: &OpaqueVariant) -> Self {
match value {
OpaqueVariant::Boolean => Self::Boolean,
OpaqueVariant::Char => Self::String,
OpaqueVariant::Integer(IntSign::Unsigned, _) => Self::UnsignedInteger,
OpaqueVariant::Integer(IntSign::Signed, _) => Self::Integer,
OpaqueVariant::Float => Self::Float,
OpaqueVariant::String => Self::String,
OpaqueVariant::Struct => Self::Object,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct TypeRef {
#[serde(rename = "$ref")]
ref_type: String,
}
impl TypeRef {
pub fn new<T: std::fmt::Display>(value: T) -> Self {
Self {
ref_type: format!("#/defs/{value}"),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct FieldType {
#[serde(rename = "type")]
type_ref: TypeRef,
}
impl FieldType {
pub fn new<T: std::fmt::Display>(value: T) -> Self {
Self {
type_ref: TypeRef::new(value),
}
}
}
impl From<Type> for FieldType {
fn from(value: Type) -> Self {
Self::new(value.path())
}
}
impl From<&Type> for FieldType {
fn from(value: &Type) -> Self {
Self::new(value.path())
}
}
impl From<&NamedField> for FieldType {
fn from(value: &NamedField) -> Self {
value.ty().into()
}
}
impl From<&UnnamedField> for FieldType {
fn from(value: &UnnamedField) -> Self {
value.ty().into()
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
enum NativeType {
Enum {
one_of: Vec<NativeType>,
},
List {
items: FieldType,
variant: ListVariant,
},
Map {
key_type: FieldType,
value_type: FieldType,
},
Opaque(OpaqueVariant),
Set {
value_type: FieldType,
},
Tuple {
prefix_items: Vec<FieldType>,
variant: TupleVariant,
},
Struct {
properties: HashMap<String, FieldType>,
additional_properties: bool,
required: Vec<String>,
},
Unit,
}
enum StructType<'a> {
Struct(&'a StructInfo),
StructVariant(&'a StructVariantInfo),
}
enum TupleType<'a> {
Tuple(&'a TupleInfo),
TupleVariant(&'a TupleVariantInfo),
}
impl NativeType {
fn from_struct(value: StructType) -> Self {
let iter = match value {
StructType::Struct(info) => info.iter(),
StructType::StructVariant(info) => info.iter(),
};
let properties = iter
.as_ref()
.into_iter()
.map(|field| (field.name().to_string(), field.into()))
.collect();
let option_path = "core::option::Option";
let required = iter
.filter(|field| !field.type_path().starts_with(&option_path))
.map(|field| field.name().to_string())
.collect();
Self::Struct {
properties,
additional_properties: false,
required,
}
}
fn from_tuple(value: TupleType) -> Self {
let iter = match value {
TupleType::Tuple(info) => info.iter(),
TupleType::TupleVariant(info) => info.iter(),
};
let prefix_items = iter.map(FieldType::from).collect();
Self::Tuple {
prefix_items,
variant: TupleVariant::Tuple,
}
}
}
impl From<&VariantInfo> for NativeType {
fn from(value: &VariantInfo) -> Self {
match value {
VariantInfo::Struct(info) => NativeType::from(info),
VariantInfo::Tuple(info) => NativeType::from(info),
VariantInfo::Unit(info) => NativeType::from(info),
}
}
}
impl From<&StructVariantInfo> for NativeType {
fn from(value: &StructVariantInfo) -> Self {
Self::from_struct(StructType::StructVariant(value))
}
}
impl From<&TupleVariantInfo> for NativeType {
fn from(value: &TupleVariantInfo) -> Self {
Self::from_tuple(TupleType::TupleVariant(value))
}
}
impl From<&UnitVariantInfo> for NativeType {
fn from(_value: &UnitVariantInfo) -> Self {
Self::Unit
}
}
impl From<&TypeRegistration> for NativeType {
fn from(value: &TypeRegistration) -> Self {
value.type_info().into()
}
}
impl From<&TypeInfo> for NativeType {
fn from(value: &TypeInfo) -> Self {
match value {
TypeInfo::Struct(info) => NativeType::from(info),
TypeInfo::TupleStruct(info) => NativeType::from(info),
TypeInfo::Tuple(info) => NativeType::from(info),
TypeInfo::List(info) => NativeType::from(info),
TypeInfo::Array(info) => NativeType::from(info),
TypeInfo::Map(info) => NativeType::from(info),
TypeInfo::Set(info) => NativeType::from(info),
TypeInfo::Enum(info) => NativeType::from(info),
TypeInfo::Opaque(info) => NativeType::from(info),
}
}
}
impl From<&ArrayInfo> for NativeType {
fn from(value: &ArrayInfo) -> Self {
Self::List {
items: value.item_ty().into(),
variant: ListVariant::Array,
}
}
}
impl From<&EnumInfo> for NativeType {
fn from(value: &EnumInfo) -> Self {
let one_of = value.iter().map(NativeType::from).collect();
Self::Enum { one_of }
}
}
impl From<&ListInfo> for NativeType {
fn from(value: &ListInfo) -> Self {
Self::List {
items: FieldType::new(value.item_ty().path()),
variant: ListVariant::List,
}
}
}
impl From<&MapInfo> for NativeType {
fn from(value: &MapInfo) -> Self {
Self::Map {
key_type: FieldType::new(value.key_ty().path()),
value_type: FieldType::new(value.value_ty().path()),
}
}
}
impl From<&OpaqueInfo> for NativeType {
fn from(value: &OpaqueInfo) -> Self {
Self::Opaque(OpaqueVariant::from(value))
}
}
impl From<&SetInfo> for NativeType {
fn from(value: &SetInfo) -> Self {
Self::Set {
value_type: value.value_ty().into(),
}
}
}
impl From<&StructInfo> for NativeType {
fn from(value: &StructInfo) -> Self {
Self::from_struct(StructType::Struct(value))
}
}
impl From<&TupleInfo> for NativeType {
fn from(value: &TupleInfo) -> Self {
Self::from_tuple(TupleType::Tuple(value))
}
}
impl From<&TupleStructInfo> for NativeType {
fn from(value: &TupleStructInfo) -> Self {
let prefix_items = value.iter().map(FieldType::from).collect();
Self::Tuple {
prefix_items,
variant: TupleVariant::TupleStruct,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
enum ListVariant {
Array,
List,
}
#[derive(Debug, Serialize, Deserialize)]
enum TupleVariant {
Tuple,
TupleStruct,
}
#[derive(Debug, Serialize, Deserialize)]
enum IntSign {
Signed,
Unsigned,
}
impl IntSign {
fn from_str<T: AsRef<str>>(value: T) -> Self {
if value.as_ref().starts_with('u') {
IntSign::Unsigned
} else {
IntSign::Signed
}
}
}
#[derive(Debug, Serialize, Deserialize)]
enum IntSize {
Sized(u8),
PointerSized,
}
impl IntSize {
fn from_str<T: AsRef<str>>(value: T) -> Self {
let size = &value.as_ref()[1..];
if size == "size" {
Self::PointerSized
} else {
let size = u8::from_str_radix(size, 10).unwrap();
Self::Sized(size)
}
}
}
#[derive(Debug, Serialize, Deserialize)]
enum OpaqueVariant {
Boolean,
Integer(IntSign, IntSize),
Float,
Char,
String,
Struct,
}
impl OpaqueVariant {
fn int_from_str<T: AsRef<str>>(value: T) -> Self {
let sign = IntSign::from_str(&value);
let size = IntSize::from_str(&value);
Self::Integer(sign, size)
}
}
impl From<&OpaqueInfo> for OpaqueVariant {
fn from(value: &OpaqueInfo) -> Self {
match value.type_path() {
"bool" => Self::Boolean,
value @ ("u8" | "u16" | "u32" | "u64" | "u128" | "usize" | "i8" | "i16" | "i32"
| "i64" | "i128" | "isize") => Self::int_from_str(value),
"f32" | "f64" => Self::Float,
"char" | "str" | "alloc::string::String" => Self::String,
_ => Self::Struct,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct RegistryEntry {
#[serde(rename = "type")]
schema_type: SchemaType,
native_type: NativeType,
qualified_type_path: String,
}
impl From<&TypeRegistration> for RegistryEntry {
fn from(value: &TypeRegistration) -> Self {
let type_info = value.type_info();
let native_type = NativeType::from(type_info);
let schema_type = SchemaType::from(&native_type);
Self {
schema_type,
native_type,
qualified_type_path: type_info.type_path().to_string(),
}
}
}