Blender_bevy_components_wor.../tools/bevy_components/registry/registry.py
Mark Moissette cfbda24da7
feat(tools/bevy_blueprints): bevy plugin + blender addon for components UI to more easily create components (#70)
* adds a new crate: ```bevy_registry_export``` to be able to create a json import of the registered component/type definitions
* adds a new Blender addon: ```bevy_components``` that takes that json data to generate custom UIs for components , to be to add & edit components easily in Blender 
   * also adds component metadata per object for more advanced features
   * etc
* updates to bevy_gltf_components & bevy_gltf_blueprints to add legacy_mode to support the "old"/current style component definitions
* same with gltf_auto_export Blender add_on
* closes #60
2024-02-05 23:01:19 +01:00

216 lines
8.0 KiB
Python

import bpy
import json
import os
from pathlib import Path
from bpy_types import (PropertyGroup)
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
from ..components.metadata import ComponentInfos
# helper class to store missing bevy types information
class MissingBevyType(bpy.types.PropertyGroup):
type_name: bpy.props.StringProperty(
name="type",
)
# this is where we store the information for all available components
class ComponentsRegistry(PropertyGroup):
settings_save_path = ".bevy_components_settings" # where to store data in bpy.texts
schemaPath: bpy.props.StringProperty(
name="schema path",
description="path to the registry schema file",
default="registry.json"
)
registry: bpy.props. StringProperty(
name="registry",
description="component registry"
)
missing_type_infos: StringProperty(
name="missing type infos",
description="unregistered/missing type infos"
)
missing_types_list: CollectionProperty(name="missing types list", type=MissingBevyType)
missing_types_list_index: IntProperty(name = "Index for missing types list", default = 0)
blender_property_mapping = {
"bool": dict(type=BoolProperty, presets=dict()),
"u8": dict(type=IntProperty, presets=dict(min=0, max=255)),
"u16": dict(type=IntProperty, presets=dict(min=0, max=65535)),
"u32": dict(type=IntProperty, presets=dict(min=0)),
"u64": 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)),
"i8": dict(type=IntProperty, presets=dict()),
"i16":dict(type=IntProperty, presets=dict()),
"i32":dict(type=IntProperty, presets=dict()),
"i64":dict(type=IntProperty, presets=dict()),
"i128":dict(type=IntProperty, presets=dict()),
"f32": dict(type=FloatProperty, presets=dict()),
"f64": dict(type=FloatProperty, presets=dict()),
"glam::Vec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
"glam::DVec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
"glam::UVec2": {"type": FloatVectorProperty, "presets": dict(size = 2) },
"glam::Vec3": {"type": FloatVectorProperty, "presets": {"size":3} },
"glam::Vec3A":{"type": FloatVectorProperty, "presets": {"size":3} },
"glam::DVec3":{"type": FloatVectorProperty, "presets": {"size":3} },
"glam::UVec3":{"type": FloatVectorProperty, "presets": {"size":3} },
"glam::Vec4": {"type": FloatVectorProperty, "presets": {"size":4} },
"glam::Vec4A": {"type": FloatVectorProperty, "presets": {"size":4} },
"glam::DVec4": {"type": FloatVectorProperty, "presets": {"size":4} },
"glam::UVec4":{"type": FloatVectorProperty, "presets": {"size":4, "min":0.0} },
"glam::Quat": {"type": FloatVectorProperty, "presets": {"size":4} },
"bevy_render::color::Color": dict(type = FloatVectorProperty, presets=dict(subtype='COLOR', size=4)),
"char": dict(type=StringProperty, presets=dict()),
"str": dict(type=StringProperty, presets=dict()),
"alloc::string::String": dict(type=StringProperty, presets=dict()),
"enum": dict(type=EnumProperty, presets=dict()),
#"alloc::vec::Vec<alloc::string::String>": dict(type=CollectionProperty, presets=dict(type=PointerProperty(StringProperty))), #FIXME: we need more generic stuff
}
value_types_defaults = {
"string":" ",
"boolean": True,
"float": 0.0,
"uint": 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
"bool": True,
"u8": 0,
"u16":0,
"u32":0,
"u64":0,
"u128":0,
"i8": 0,
"i16":0,
"i32":0,
"i64":0,
"i128":0,
"f32": 0.0,
"f64":0.0,
"char": " ",
"str": " ",
"alloc::string::String": " ",
"glam::Vec2": [0.0, 0.0],
"glam::DVec2": [0.0, 0.0],
"glam::UVec2": [0, 0],
"glam::Vec3": [0.0, 0.0, 0.0],
"glam::Vec3A":[0.0, 0.0, 0.0],
"glam::UVec3": [0, 0, 0],
"glam::Vec4": [0.0, 0.0, 0.0, 0.0],
"glam::DVec4": [0.0, 0.0, 0.0, 0.0],
"glam::UVec4": [0, 0, 0, 0],
"glam::Quat": [0.0, 0.0, 0.0, 0.0],
"bevy_render::color::Color": [1.0, 1.0, 0.0, 1.0],
}
type_infos = None
type_infos_missing = []
component_propertyGroups = {}
short_names_to_long_names = {}
@classmethod
def register(cls):
bpy.types.WindowManager.components_registry = PointerProperty(type=ComponentsRegistry)
@classmethod
def unregister(cls):
for propgroup_name in cls.component_propertyGroups.keys():
try:
delattr(ComponentInfos, propgroup_name)
print("unregistered propertyGroup", propgroup_name)
except Exception as error:
pass
#print("failed to remove", error, "ComponentInfos")
del bpy.types.WindowManager.components_registry
def load_schema(self):
# cleanup missing types list
self.missing_types_list.clear()
self.type_infos = None
self.type_infos_missing.clear()
file_path = bpy.data.filepath
# Get the folder
folder_path = os.path.dirname(file_path)
path = os.path.join(folder_path, self.schemaPath)
f = Path(bpy.path.abspath(path)) # make a path object of abs path
with open(path) as f:
data = json.load(f)
defs = data["$defs"]
self.registry = json.dumps(defs) # FIXME:meh ?
# we load the json once, so we do not need to do it over & over again
def load_type_infos(self):
ComponentsRegistry.type_infos = json.loads(self.registry)
# we keep a list of component propertyGroup around
def register_component_propertyGroup(self, name, propertyGroup):
self.component_propertyGroups[name] = propertyGroup
#for practicality, we add an entry for a reverse lookup (short => long name, since we already have long_name => short_name with the keys of the raw registry)
def add_shortName_to_longName(self, short_name, long_name):
self.short_names_to_long_names[short_name] = long_name
# to be able to give the user more feedback on any missin/unregistered types in their schema file
def add_missing_typeInfo(self, type_name):
if not type_name in self.type_infos_missing:
self.type_infos_missing.append(type_name)
setattr(self, "missing_type_infos", str(self.type_infos_missing))
item = self.missing_types_list.add()
item.type_name = type_name
custom_types_to_add = {}
def add_custom_type(self, type_name, type_definition):
self.custom_types_to_add[type_name] = type_definition
def process_custom_types(self):
for type_name in self.custom_types_to_add:
self.type_infos[type_name] = self.custom_types_to_add[type_name]
self.custom_types_to_add.clear()
invalid_components = []
def add_invalid_component(self, component_name):
self.invalid_components.append(component_name)
"""
object[component_definition.name] = 0.5
property_manager = object.id_properties_ui(component_definition.name)
property_manager.update(min=-10, max=10, soft_min=-5, soft_max=5)
print("property_manager", property_manager)
object[component_definition.name] = [0.8,0.2,1.0]
property_manager = object.id_properties_ui(component_definition.name)
property_manager.update(subtype='COLOR')
#IDPropertyUIManager
#rna_ui = object[component_definition.name].get('_RNA_UI')
"""