feat(blenvy):

* improvements to assets ui
 * assets ui now specific to per level data, not based on selection anymore
 * blueprints ui now presents assets per blueprint
 * a lot of tweaks & improvements in the areas above
This commit is contained in:
kaosat.dev 2024-05-13 23:36:13 +02:00
parent f3dbf76ce6
commit b8a7eba71d
11 changed files with 185 additions and 90 deletions

View File

@ -53,7 +53,7 @@ from .gltf_auto_export.ui.operators import (OT_OpenFolderbrowser, SCENES_LIST_OT
# asset management
from .assets.ui import GLTF_PT_auto_export_assets
from .assets.assets_registry import AssetsRegistry
from .assets.operators import OT_add_bevy_asset, OT_remove_bevy_asset
from .assets.operators import OT_Add_asset_filebrowser, OT_add_bevy_asset, OT_remove_bevy_asset
# blueprints management
from .blueprints.ui import GLTF_PT_auto_export_blueprints_list
@ -143,6 +143,7 @@ classes = [
AssetsRegistry,
OT_add_bevy_asset,
OT_remove_bevy_asset,
OT_Add_asset_filebrowser,
GLTF_PT_auto_export_assets,
BlueprintsRegistry,

View File

@ -68,6 +68,7 @@ class AssetsRegistry(PropertyGroup):
('MODEL', "Model", ""),
('AUDIO', "Audio", ""),
('IMAGE', "Image", ""),
('TEXT', "Text", ""),
)
) # type: ignore

View File

@ -2,7 +2,9 @@ import os
import json
import bpy
from bpy_types import (Operator)
from bpy.props import (StringProperty, EnumProperty)
from bpy.props import (BoolProperty, StringProperty, EnumProperty)
from ..settings import load_settings
class OT_add_bevy_asset(Operator):
"""Add asset"""
@ -20,6 +22,7 @@ class OT_add_bevy_asset(Operator):
('MODEL', "Model", ""),
('AUDIO', "Audio", ""),
('IMAGE', "Image", ""),
('TEXT', "Text", ""),
)
) # type: ignore
@ -29,26 +32,39 @@ class OT_add_bevy_asset(Operator):
subtype='FILE_PATH'
) # type: ignore
def execute(self, context):
assets_list = []
blueprint_assets = False
if context.collection is not None and context.collection.name == 'Scene Collection':
assets_list = json.loads(context.scene.get('assets'))
blueprint_assets = False
else:
if 'assets' in context.collection:
assets_list = json.loads(context.collection.get('assets'))
blueprint_assets = True
# what are we targetting
target_type: EnumProperty(
name="target type",
description="type of the target: scene or blueprint to add an asset to",
items=(
('SCENE', "Scene", ""),
('BLUEPRINT', "Blueprint", ""),
),
) # type: ignore
in_list = [asset for asset in assets_list if (asset["path"] == self.asset_path)]
target_name: StringProperty(
name="target name",
description="name of the target blueprint or scene to add asset to"
) # type: ignore
def execute(self, context):
assets = []
blueprint_assets = self.target_type == 'BLUEPRINT'
print("FOOO", self.target_name, self.target_type)
if blueprint_assets:
assets = json.loads(bpy.data.collections[self.target_name].get('assets')) if 'assets' in bpy.data.collections[self.target_name] else []
else:
assets = json.loads(bpy.data.scenes[self.target_name].get('assets')) if 'assets' in bpy.data.scenes[self.target_name] else []
in_list = [asset for asset in assets if (asset["path"] == self.asset_path)]
in_list = len(in_list) > 0
if not in_list:
assets_list.append({"name": self.asset_name, "type": self.asset_type, "path": self.asset_path, "internal": False})
assets.append({"name": self.asset_name, "type": self.asset_type, "path": self.asset_path, "internal": False})
if blueprint_assets:
context.collection["assets"] = json.dumps(assets_list)
bpy.data.collections[self.target_name]["assets"] = json.dumps(assets)
else:
context.scene["assets"] = json.dumps(assets_list)
bpy.data.scenes[self.target_name]["assets"] = json.dumps(assets)
#context.window_manager.assets_registry.add_asset(self.asset_name, self.asset_type, self.asset_path, False)
return {'FINISHED'}
@ -65,21 +81,72 @@ class OT_remove_bevy_asset(Operator):
subtype='FILE_PATH'
) # type: ignore
def execute(self, context):
assets_list = []
blueprint_assets = False
if context.collection is not None and context.collection.name == 'Scene Collection':
assets_list = json.loads(context.scene.get('assets'))
blueprint_assets = False
else:
if 'assets' in context.collection:
assets_list = json.loads(context.collection.get('assets'))
blueprint_assets = True
assets_list = [asset for asset in assets_list if (asset["path"] != self.asset_path)]
clear_all: BoolProperty (
name="clear all assets",
description="clear all assets",
default=False
) # type: ignore
# what are we targetting
target_type: EnumProperty(
name="target type",
description="type of the target: scene or blueprint to add an asset to",
items=(
('SCENE', "Scene", ""),
('BLUEPRINT', "Blueprint", ""),
),
) # type: ignore
target_name: StringProperty(
name="target name",
description="name of the target blueprint or scene to add asset to"
) # type: ignore
def execute(self, context):
assets = []
blueprint_assets = self.target_type == 'BLUEPRINT'
if blueprint_assets:
context.collection["assets"] = json.dumps(assets_list)
assets = json.loads(bpy.data.collections[self.target_name].get('assets')) if 'assets' in bpy.data.collections[self.target_name] else []
else:
context.scene["assets"] = json.dumps(assets_list)
assets = json.loads(bpy.data.scenes[self.target_name].get('assets')) if 'assets' in bpy.data.scenes[self.target_name] else []
assets = [asset for asset in assets if (asset["path"] != self.asset_path)]
if blueprint_assets:
bpy.data.collections[self.target_name]["assets"] = json.dumps(assets)
else:
bpy.data.scenes[self.target_name]["assets"] = json.dumps(assets)
#context.window_manager.assets_registry.remove_asset(self.asset_path)
return {'FINISHED'}
import os
from bpy_extras.io_utils import ImportHelper
class OT_Add_asset_filebrowser(Operator, ImportHelper):
"""Browse for asset files"""
bl_idname = "asset.open_filebrowser"
bl_label = "Select asset file"
# Define this to tell 'fileselect_add' that we want a directoy
filepath: bpy.props.StringProperty(
name="asset Path",
description="selected file",
subtype='FILE_PATH',
) # type: ignore
# Filters files
filter_glob: StringProperty(options={'HIDDEN'}, default='*.jpg;*.jpeg;*.png;*.bmp') # type: ignore
def execute(self, context):
current_auto_settings = load_settings(".gltf_auto_export_settings")
export_root_folder = current_auto_settings.get("export_root_folder")
asset_path = os.path.relpath(self.filepath, export_root_folder)
assets_registry = context.window_manager.assets_registry
assets_registry.asset_path_selector = asset_path
print("SELECTED ASSET PATH", asset_path)
return {'FINISHED'}

View File

@ -1,66 +1,79 @@
import bpy
import json
def draw_assets(layout, name, title, asset_registry, assets, target_type, target_name):
header, panel = layout.box().panel(f"assets{name}", default_closed=False)
header.label(text=title)
if panel:
row = panel.row()
row.prop(asset_registry, "asset_name_selector", text="")
row.prop(asset_registry, "asset_type_selector", text="")
asset_selector = row.operator(operator="asset.open_filebrowser", text="", icon="FILE_FOLDER")
if asset_registry.asset_type_selector == 'IMAGE':
asset_selector.filter_glob = '*.jpg;*.jpeg;*.png;*.bmp'
if asset_registry.asset_type_selector == 'MODEL':
asset_selector.filter_glob="*.glb;*.gltf"
if asset_registry.asset_type_selector == 'TEXT':
asset_selector.filter_glob="*.txt;*.md;*.ron;*.json"
if asset_registry.asset_type_selector == 'AUDIO':
asset_selector.filter_glob="*.mp3;*.wav;*.flac"
add_asset = row.operator(operator="bevyassets.add", text="", icon="ADD")
add_asset.target_type = target_type
add_asset.target_name = target_name
add_asset.asset_name = asset_registry.asset_name_selector
add_asset.asset_type = asset_registry.asset_type_selector
add_asset.asset_path = asset_registry.asset_path_selector
#assets = json.loads(blueprint.collection["assets"]) if "assets" in blueprint.collection else []
for asset in assets:
row = panel.row()
row.label(text=asset["name"])
row.label(text=asset["type"])
row.label(text=asset["path"])
if not asset["internal"]:
remove_asset = row.operator(operator="bevyassets.remove", text="", icon="TRASH")
remove_asset.target_type = target_type
remove_asset.target_name = target_name
remove_asset.asset_path = asset["path"]
else:
row.label(text="")
class GLTF_PT_auto_export_assets(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = ""
bl_parent_id = "BLENVY_PT_SidePanel"
bl_options = {'DEFAULT_CLOSED'}
bl_options = {'DEFAULT_CLOSED','HIDE_HEADER'}
@classmethod
def poll(cls, context):
return context.window_manager.blenvy.mode == 'ASSETS'
def draw_header(self, context):
"""def draw_header(self, context):
layout = self.layout
name = ""
if context.collection is not None and context.collection.name == 'Scene Collection':
name = f"WORLD/LEVEL: {context.scene.name}"
else:
name = f"BLUEPRINT: {context.collection.name}"
layout.label(text=f"Assets For {name}")
layout.label(text=f"Assets For {name}")"""
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
#if "auto_export_tracker" in context.window_manager:
asset_registry = context.window_manager.assets_registry
name = "world"
header, panel = layout.box().panel(f"assets{name}", default_closed=False)
header.label(text="World/Level Assets")
row = layout.row()
row.prop(asset_registry, "asset_name_selector", text="")
row.prop(asset_registry, "asset_type_selector", text="")
row.prop(asset_registry, "asset_path_selector", text="")
add_assets = row.operator(operator="bevyassets.add", text="Add asset")
add_assets.asset_name = asset_registry.asset_name_selector
add_assets.asset_type = asset_registry.asset_type_selector
add_assets.asset_path = asset_registry.asset_path_selector
layout.separator()
row = layout.row()
row.label(text="Name")
row.label(text="Type")
row.label(text="Path")
row.label(text="Remove")
#print("FOO", json.dumps([{"name":"foo", "type":"MODEL", "path":"bla", "internal":True}]))
# [{"name": "trigger_sound", "type": "AUDIO", "path": "assets/audio/trigger.mp3", "internal": true}]
assets_list = []
if context.collection is not None and context.collection.name == 'Scene Collection':
assets_list = json.loads(context.scene.get('assets')) #asset_registry.assets_list
else:
if 'assets' in context.collection:
assets_list = json.loads(context.collection.get('assets'))
for asset in assets_list:
row = layout.row()
row.label(text=asset["name"])
row.label(text=asset["type"])
row.label(text=asset["path"])
if not asset["internal"]:
remove_asset = row.operator(operator="bevyassets.remove", text="remove")
remove_asset.asset_path = asset["path"]
else:
row.label(text="")
#
if panel:
for scene in bpy.data.scenes:
if scene.name != "Library": # FIXME: hack for testing
assets = json.loads(scene.get('assets')) if 'assets' in scene else []
row = panel.row()
draw_assets(layout=row, name=scene.name, title=f"{scene.name} Assets", asset_registry=asset_registry, assets=assets, target_type="SCENE", target_name=scene.name)

View File

@ -17,14 +17,3 @@ def make_empty(name, location, rotation, scale, collection):
collection.objects.link( empty_obj )
#bpy.context.view_layer.update()
return empty_obj
def upsert_settings(name, data):
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else bpy.data.texts.new(name)
stored_settings.clear()
stored_settings.write(json.dumps(data))
def load_settings(name):
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None
if stored_settings != None:
return json.loads(stored_settings.as_string())
return None

View File

@ -4,7 +4,8 @@ from bpy_types import (Operator)
from bpy.props import (StringProperty)
from bpy_extras.io_utils import ImportHelper
from ..helpers import upsert_settings
from ...settings import upsert_settings
from ..components.metadata import apply_customProperty_values_to_object_propertyGroups, apply_propertyGroup_values_to_object_customProperties, ensure_metadata_for_all_objects
from ..propGroups.prop_groups import generate_propertyGroups_for_components

View File

@ -6,7 +6,7 @@ from pathlib import Path
from bpy_types import (PropertyGroup)
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
from ..helpers import load_settings
from ...settings import load_settings
from ..propGroups.prop_groups import generate_propertyGroups_for_components
from ..components.metadata import ComponentMetadata, ensure_metadata_for_all_objects

View File

@ -33,4 +33,5 @@ class OT_select_blueprint(Operator):
"""for o in collection.objects:
o.select_set(True)"""
return {'FINISHED'}
return {'FINISHED'}

View File

@ -1,11 +1,14 @@
import bpy
import json
from ..assets.ui import draw_assets
class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Blueprints"
bl_parent_id = "BLENVY_PT_SidePanel"
bl_options = {'DEFAULT_CLOSED'}
bl_options = {'DEFAULT_CLOSED','HIDE_HEADER'}
@classmethod
def poll(cls, context):
@ -15,15 +18,22 @@ class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
asset_registry = context.window_manager.assets_registry
for blueprint in context.window_manager.blueprints_registry.blueprints_list:
row = layout.row()
row.label(icon="RIGHTARROW")
row.label(text=blueprint.name)
if blueprint.local:
select_blueprint = row.operator(operator="blueprint.select", text="Select")
select_blueprint = row.operator(operator="blueprint.select", text="", icon="RESTRICT_SELECT_OFF")
select_blueprint.blueprint_collection_name = blueprint.collection.name
select_blueprint.blueprint_scene_name = blueprint.scene.name
assets = json.loads(blueprint.collection["assets"]) if "assets" in blueprint.collection else []
draw_assets(layout=layout, name=blueprint.name, title="Assets", asset_registry=asset_registry, assets=assets, target_type="BLUEPRINT", target_name=blueprint.name)
else:
row.label(text="External")

View File

@ -1,5 +1,5 @@
import bpy
import json
from ..settings import load_settings
######################################################
## ui logic & co
@ -27,11 +27,10 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
library_scene_active = False
active_collection = context.collection
current_auto_settings = bpy.data.texts[".gltf_auto_export_settings"] if ".gltf_auto_export_settings" in bpy.data.texts else None
current_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else None
current_auto_settings = load_settings(".gltf_auto_export_settings")
current_gltf_settings = load_settings(".gltf_auto_export_gltf_settings")
if current_auto_settings is not None:
current_auto_settings = json.loads(current_auto_settings.as_string())
#print("current_auto_settings", current_auto_settings)
main_scene_names = current_auto_settings["main_scene_names"]
library_scene_names = current_auto_settings["library_scene_names"]

13
tools/blenvy/settings.py Normal file
View File

@ -0,0 +1,13 @@
import json
import bpy
def upsert_settings(name, data):
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else bpy.data.texts.new(name)
stored_settings.clear()
stored_settings.write(json.dumps(data))
def load_settings(name):
stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None
if stored_settings != None:
return json.loads(stored_settings.as_string())
return None