mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-22 20:00:53 +00:00
cfbda24da7
* 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
222 lines
12 KiB
Python
222 lines
12 KiB
Python
import json
|
|
from bpy_types import PropertyGroup
|
|
|
|
|
|
conversion_tables = {
|
|
"bool": lambda value: value,
|
|
|
|
"char": lambda value: '"'+value+'"',
|
|
"str": lambda value: '"'+value+'"',
|
|
"alloc::string::String": lambda value: '"'+value+'"',
|
|
|
|
"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::UVec2": lambda value: "UVec2(x:"+str(value[0])+ ", y:"+str(value[1])+")",
|
|
|
|
"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::UVec3": lambda value: "UVec3(x:"+str(value[0])+ ", y:"+str(value[1])+ ", z:"+str(value[2])+")",
|
|
|
|
"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::UVec4": lambda value: "UVec4(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_render::color::Color": lambda value: "Rgba(red:"+str(value[0])+ ", green:"+str(value[1])+ ", blue:"+str(value[2])+ ", alpha:"+str(value[3])+ ")",
|
|
}
|
|
|
|
#converts the value of a property group(no matter its complexity) into a single custom property value
|
|
# this is more or less a glorified "to_ron()" method (not quite but close to)
|
|
def property_group_value_to_custom_property_value(property_group, definition, registry, parent=None, value=None):
|
|
component_name = definition["short_name"]
|
|
type_info = definition["typeInfo"] if "typeInfo" in definition else None
|
|
type_def = definition["type"] if "type" in definition else None
|
|
type_name = definition["title"]
|
|
is_value_type = type_name in conversion_tables
|
|
#print("computing custom property", component_name, type_info, type_def, type_name)
|
|
|
|
if is_value_type:
|
|
value = conversion_tables[type_name](value)
|
|
elif type_info == "Struct":
|
|
values = {}
|
|
if len(property_group.field_names) ==0:
|
|
value = ''
|
|
else:
|
|
for index, field_name in enumerate(property_group.field_names):
|
|
item_type_name = definition["properties"][field_name]["type"]["$ref"].replace("#/$defs/", "")
|
|
item_definition = registry.type_infos[item_type_name] if item_type_name in registry.type_infos else None
|
|
|
|
value = getattr(property_group, field_name)
|
|
is_property_group = isinstance(value, PropertyGroup)
|
|
child_property_group = value if is_property_group else None
|
|
if item_definition != None:
|
|
value = property_group_value_to_custom_property_value(child_property_group, item_definition, registry, parent=component_name, value=value)
|
|
else:
|
|
value = '""'
|
|
values[field_name] = value
|
|
value = values
|
|
elif type_info == "Tuple":
|
|
values = {}
|
|
for index, field_name in enumerate(property_group.field_names):
|
|
item_type_name = definition["prefixItems"][index]["type"]["$ref"].replace("#/$defs/", "")
|
|
item_definition = registry.type_infos[item_type_name] if item_type_name in registry.type_infos else None
|
|
|
|
value = getattr(property_group, field_name)
|
|
is_property_group = isinstance(value, PropertyGroup)
|
|
child_property_group = value if is_property_group else None
|
|
if item_definition != None:
|
|
value = property_group_value_to_custom_property_value(child_property_group, item_definition, registry, parent=component_name, value=value)
|
|
else:
|
|
value = '""'
|
|
values[field_name] = value
|
|
value = tuple(e for e in list(values.values()))
|
|
|
|
elif type_info == "TupleStruct":
|
|
values = {}
|
|
for index, field_name in enumerate(property_group.field_names):
|
|
item_type_name = definition["prefixItems"][index]["type"]["$ref"].replace("#/$defs/", "")
|
|
item_definition = registry.type_infos[item_type_name] if item_type_name in registry.type_infos else None
|
|
|
|
value = getattr(property_group, field_name)
|
|
is_property_group = isinstance(value, PropertyGroup)
|
|
child_property_group = value if is_property_group else None
|
|
if item_definition != None:
|
|
value = property_group_value_to_custom_property_value(child_property_group, item_definition, registry, parent=component_name, value=value)
|
|
else:
|
|
value = '""'
|
|
values[field_name] = value
|
|
|
|
value = tuple(e for e in list(values.values()))
|
|
elif type_info == "Enum":
|
|
selected = getattr(property_group, component_name)
|
|
|
|
if type_def == "object":
|
|
selection_index = property_group.field_names.index("variant_"+selected)
|
|
variant_name = property_group.field_names[selection_index]
|
|
variant_definition = definition["oneOf"][selection_index-1]
|
|
if "prefixItems" in variant_definition:
|
|
value = getattr(property_group, variant_name)
|
|
is_property_group = isinstance(value, PropertyGroup)
|
|
child_property_group = value if is_property_group else None
|
|
|
|
value = property_group_value_to_custom_property_value(child_property_group, variant_definition, registry, parent=component_name, value=value)
|
|
value = selected + str(value,)
|
|
elif "properties" in variant_definition:
|
|
value = getattr(property_group, variant_name)
|
|
is_property_group = isinstance(value, PropertyGroup)
|
|
child_property_group = value if is_property_group else None
|
|
|
|
value = property_group_value_to_custom_property_value(child_property_group, variant_definition, registry, parent=component_name, value=value)
|
|
value = selected + str(value,)
|
|
else:
|
|
print("basic enum stuff")
|
|
value = selected # here the value of the enum is just the name of the variant
|
|
else:
|
|
value = selected
|
|
|
|
elif type_info == "List":
|
|
item_list = getattr(property_group, "list")
|
|
#item_type = getattr(property_group, "type_name_short")
|
|
value = []
|
|
for item in item_list:
|
|
item_type_name = getattr(item, "type_name")
|
|
definition = registry.type_infos[item_type_name] if item_type_name in registry.type_infos else None
|
|
if definition != None:
|
|
item_value = property_group_value_to_custom_property_value(item, definition, registry, component_name, None)
|
|
if item_type_name.startswith("wrapper_"): #if we have a "fake" tupple for aka for value types, we need to remove one nested level
|
|
item_value = item_value[0]
|
|
else:
|
|
item_value = '""'
|
|
value.append(item_value)
|
|
else:
|
|
value = conversion_tables[type_name](value) if is_value_type else value
|
|
|
|
#print("VALUE", value, type(value))
|
|
#print("generating custom property value", value, type(value))
|
|
if parent == None:
|
|
value = str(value).replace("'", "")
|
|
value = value.replace(",)",")")
|
|
value = value.replace("{", "(").replace("}", ")")
|
|
value = value.replace("True", "true").replace("False", "false")
|
|
return value
|
|
|
|
import re
|
|
#converts the value of a single custom property into a value (values) of a property group
|
|
def property_group_value_from_custom_property_value(property_group, definition, registry, custom_property_value):
|
|
#print(" ")
|
|
#print("setting property group value", property_group, definition, custom_property_value)
|
|
type_infos = registry.type_infos
|
|
value_types_defaults = registry.value_types_defaults
|
|
print("custom_property_value", custom_property_value)
|
|
|
|
def parse_field(item, property_group, definition, field_name):
|
|
type_info = definition["typeInfo"] if "typeInfo" in definition else None
|
|
type_def = definition["type"] if "type" in definition else None
|
|
properties = definition["properties"] if "properties" in definition else {}
|
|
prefixItems = definition["prefixItems"] if "prefixItems" in definition else []
|
|
has_properties = len(properties.keys()) > 0
|
|
has_prefixItems = len(prefixItems) > 0
|
|
is_enum = type_info == "Enum"
|
|
is_list = type_info == "List"
|
|
is_value_type = type_def in value_types_defaults
|
|
|
|
print("parsing field", item, "type infos", type_info, "type_def", type_def)
|
|
if type_info == "Struct":
|
|
print("is object")
|
|
for field_name in property_group.field_names:
|
|
print("field name", field_name)
|
|
# sub field
|
|
if isinstance(getattr(property_group, field_name), PropertyGroup):
|
|
sub_prop_group = getattr(property_group, field_name)
|
|
ref_name = properties[field_name]["type"]["$ref"].replace("#/$defs/", "")
|
|
sub_definition = type_infos[ref_name]
|
|
parse_field(item[field_name], sub_prop_group, sub_definition, field_name)
|
|
else:
|
|
setattr(property_group, field_name, item[field_name])
|
|
|
|
if has_prefixItems:
|
|
if len(property_group.field_names) == 1:
|
|
setattr(property_group, "0", item) # FIXME: not ideal
|
|
else:
|
|
for field_name in property_group.field_names:
|
|
setattr(property_group, field_name, item)
|
|
if is_enum:
|
|
if type_def == "object":
|
|
regexp = re.search('(^[^\(]+)(\((.*)\))', item)
|
|
chosen_variant = regexp.group(1)
|
|
chosen_variant_value = regexp.group(3).replace("'", '"').replace("(", "[").replace(")","]")
|
|
chosen_variant_value = json.loads(chosen_variant_value)
|
|
|
|
# first set chosen selection
|
|
field_name = property_group.field_names[0]
|
|
setattr(property_group, field_name, chosen_variant)
|
|
|
|
# thenlook for the information about the matching variant
|
|
sub_definition= None
|
|
for variant in definition["oneOf"]:
|
|
if variant["title"] == chosen_variant:
|
|
ref_name = variant["prefixItems"][0]["type"]["$ref"].replace("#/$defs/", "")
|
|
sub_definition = type_infos[ref_name]
|
|
break
|
|
variant_name = "variant_"+chosen_variant
|
|
if isinstance(getattr(property_group, variant_name), PropertyGroup):
|
|
sub_prop_group = getattr(property_group, variant_name)
|
|
parse_field(chosen_variant_value, sub_prop_group, sub_definition, variant_name)
|
|
else:
|
|
setattr(property_group, variant_name, chosen_variant_value)
|
|
else:
|
|
field_name = property_group.field_names[0]
|
|
setattr(property_group, field_name, item)
|
|
|
|
if is_list:
|
|
print("is list")
|
|
|
|
if is_value_type:
|
|
print("is value type")
|
|
|
|
try:
|
|
parse_field(custom_property_value, property_group, definition, None)
|
|
except Exception as error:
|
|
print("failed to parse raw custom property data", error)
|