mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-26 21:37:01 +00:00
Compare commits
3 Commits
d99a7ccd45
...
f561112704
Author | SHA1 | Date | |
---|---|---|---|
|
f561112704 | ||
|
3aed4ab925 | ||
|
006e3c16f7 |
@ -46,6 +46,9 @@ Blueprints:
|
|||||||
- export path
|
- export path
|
||||||
- [ ] blueprint selection for nested blueprints is broken
|
- [ ] blueprint selection for nested blueprints is broken
|
||||||
|
|
||||||
|
- [ ] scan & inject on load
|
||||||
|
- [ ] scan & inject on save
|
||||||
|
|
||||||
|
|
||||||
General issues:
|
General issues:
|
||||||
- there is no safeguard for naming collisions for naming across blender files
|
- there is no safeguard for naming collisions for naming across blender files
|
||||||
|
@ -15,7 +15,6 @@ import bpy
|
|||||||
from bpy.app.handlers import persistent
|
from bpy.app.handlers import persistent
|
||||||
from bpy.props import (StringProperty)
|
from bpy.props import (StringProperty)
|
||||||
|
|
||||||
|
|
||||||
# components management
|
# components management
|
||||||
from .bevy_components.components.operators import CopyComponentOperator, Fix_Component_Operator, OT_rename_component, RemoveComponentFromAllObjectsOperator, RemoveComponentOperator, GenerateComponent_From_custom_property_Operator, PasteComponentOperator, AddComponentOperator, RenameHelper, Toggle_ComponentVisibility
|
from .bevy_components.components.operators import CopyComponentOperator, Fix_Component_Operator, OT_rename_component, RemoveComponentFromAllObjectsOperator, RemoveComponentOperator, GenerateComponent_From_custom_property_Operator, PasteComponentOperator, AddComponentOperator, RenameHelper, Toggle_ComponentVisibility
|
||||||
|
|
||||||
@ -33,27 +32,15 @@ from .bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel)
|
|||||||
from .gltf_auto_export import gltf_post_export_callback
|
from .gltf_auto_export import gltf_post_export_callback
|
||||||
from .gltf_auto_export.auto_export.operators import AutoExportGLTF
|
from .gltf_auto_export.auto_export.operators import AutoExportGLTF
|
||||||
from .gltf_auto_export.auto_export.tracker import AutoExportTracker
|
from .gltf_auto_export.auto_export.tracker import AutoExportTracker
|
||||||
|
|
||||||
from .gltf_auto_export.auto_export.internals import (SceneLink,
|
|
||||||
SceneLinks,
|
|
||||||
CollectionToExport,
|
|
||||||
BlueprintsToExport,
|
|
||||||
CUSTOM_PG_sceneName
|
|
||||||
)
|
|
||||||
from .gltf_auto_export.ui.main import (GLTF_PT_auto_export_change_detection, GLTF_PT_auto_export_main,
|
from .gltf_auto_export.ui.main import (GLTF_PT_auto_export_change_detection, GLTF_PT_auto_export_main,
|
||||||
GLTF_PT_auto_export_root,
|
GLTF_PT_auto_export_root,
|
||||||
GLTF_PT_auto_export_general,
|
GLTF_PT_auto_export_general,
|
||||||
GLTF_PT_auto_export_scenes,
|
|
||||||
GLTF_PT_auto_export_blueprints,
|
GLTF_PT_auto_export_blueprints,
|
||||||
SCENE_UL_GLTF_auto_export,
|
|
||||||
|
|
||||||
GLTF_PT_auto_export_SidePanel
|
GLTF_PT_auto_export_SidePanel
|
||||||
)
|
)
|
||||||
from .gltf_auto_export.ui.operators import (OT_OpenFolderbrowser, SCENES_LIST_OT_actions)
|
|
||||||
|
|
||||||
# asset management
|
# asset management
|
||||||
from .assets.ui import Blenvy_assets
|
from .assets.ui import Blenvy_assets
|
||||||
from .assets.assets_registry import AssetsRegistry
|
from .assets.assets_registry import Asset, AssetsRegistry
|
||||||
from .assets.operators import OT_Add_asset_filebrowser, OT_add_bevy_asset, OT_remove_bevy_asset, OT_test_bevy_assets
|
from .assets.operators import OT_Add_asset_filebrowser, OT_add_bevy_asset, OT_remove_bevy_asset, OT_test_bevy_assets
|
||||||
|
|
||||||
# blueprints management
|
# blueprints management
|
||||||
@ -62,9 +49,12 @@ from .blueprints.blueprints_registry import BlueprintsRegistry
|
|||||||
from .blueprints.operators import OT_select_blueprint
|
from .blueprints.operators import OT_select_blueprint
|
||||||
|
|
||||||
# blenvy core
|
# blenvy core
|
||||||
from .core.ui import BLENVY_PT_SidePanel
|
|
||||||
from .core.blenvy_manager import BlenvyManager
|
from .core.blenvy_manager import BlenvyManager
|
||||||
from .core.operators import OT_switch_bevy_tooling
|
from .core.operators import OT_switch_bevy_tooling
|
||||||
|
from .core.scene_helpers import (SceneSelector)
|
||||||
|
from .core.ui.ui import (BLENVY_PT_SidePanel)
|
||||||
|
from .core.ui.scenes_list import SCENES_LIST_OT_actions, SCENE_UL_Blenvy
|
||||||
|
from .core.ui.folder_browser import OT_OpenFolderbrowser
|
||||||
|
|
||||||
|
|
||||||
# this needs to be here, as it is how Blender's gltf exporter callbacks are defined, at the add-on root level
|
# this needs to be here, as it is how Blender's gltf exporter callbacks are defined, at the add-on root level
|
||||||
@ -73,6 +63,12 @@ def glTF2_post_export_callback(data):
|
|||||||
|
|
||||||
|
|
||||||
classes = [
|
classes = [
|
||||||
|
# common/core
|
||||||
|
SceneSelector,
|
||||||
|
SCENE_UL_Blenvy,
|
||||||
|
SCENES_LIST_OT_actions,
|
||||||
|
OT_OpenFolderbrowser,
|
||||||
|
|
||||||
# blenvy
|
# blenvy
|
||||||
BLENVY_PT_SidePanel,
|
BLENVY_PT_SidePanel,
|
||||||
|
|
||||||
@ -121,23 +117,13 @@ classes = [
|
|||||||
GENERIC_MAP_OT_actions,
|
GENERIC_MAP_OT_actions,
|
||||||
|
|
||||||
# gltf auto export
|
# gltf auto export
|
||||||
SceneLink,
|
|
||||||
SceneLinks,
|
|
||||||
CUSTOM_PG_sceneName,
|
|
||||||
SCENE_UL_GLTF_auto_export,
|
|
||||||
SCENES_LIST_OT_actions,
|
|
||||||
|
|
||||||
OT_OpenFolderbrowser,
|
|
||||||
AutoExportGLTF,
|
AutoExportGLTF,
|
||||||
|
|
||||||
CollectionToExport,
|
|
||||||
BlueprintsToExport,
|
|
||||||
|
|
||||||
GLTF_PT_auto_export_main,
|
GLTF_PT_auto_export_main,
|
||||||
GLTF_PT_auto_export_root,
|
GLTF_PT_auto_export_root,
|
||||||
GLTF_PT_auto_export_general,
|
GLTF_PT_auto_export_general,
|
||||||
GLTF_PT_auto_export_change_detection,
|
GLTF_PT_auto_export_change_detection,
|
||||||
GLTF_PT_auto_export_scenes,
|
|
||||||
GLTF_PT_auto_export_blueprints,
|
GLTF_PT_auto_export_blueprints,
|
||||||
GLTF_PT_auto_export_SidePanel,
|
GLTF_PT_auto_export_SidePanel,
|
||||||
AutoExportTracker,
|
AutoExportTracker,
|
||||||
@ -146,6 +132,7 @@ classes = [
|
|||||||
BlenvyManager,
|
BlenvyManager,
|
||||||
OT_switch_bevy_tooling,
|
OT_switch_bevy_tooling,
|
||||||
|
|
||||||
|
Asset,
|
||||||
AssetsRegistry,
|
AssetsRegistry,
|
||||||
OT_add_bevy_asset,
|
OT_add_bevy_asset,
|
||||||
OT_remove_bevy_asset,
|
OT_remove_bevy_asset,
|
||||||
|
@ -1,10 +1,30 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
def get_assets(scene_or_collection):
|
def get_user_assets(scene_or_collection):
|
||||||
assets = json.loads(scene_or_collection.get('assets')) if 'assets' in scene_or_collection else []
|
user_assets = getattr(scene_or_collection, 'user_assets', [])
|
||||||
return assets
|
return user_assets
|
||||||
|
|
||||||
def does_asset_exist(assets, asset_path):
|
def get_generated_assets(scene_or_collection):
|
||||||
in_list = [asset for asset in assets if (asset["path"] == asset_path)]
|
generated_assets = []
|
||||||
|
return generated_assets
|
||||||
|
|
||||||
|
def get_user_assets_as_list(scene_or_collection):
|
||||||
|
raw = get_user_assets(scene_or_collection)
|
||||||
|
result = []
|
||||||
|
for asset in raw:
|
||||||
|
result.append({"name": asset.name, "path": asset.path, "type": "MODEL", "internal": False, "parent": None})
|
||||||
|
return result
|
||||||
|
|
||||||
|
def upsert_asset(scene_or_collection, asset):
|
||||||
|
new_asset = scene_or_collection.user_assets.add()
|
||||||
|
new_asset.name = asset["name"]
|
||||||
|
new_asset.path = asset["path"]
|
||||||
|
|
||||||
|
def remove_asset(scene_or_collection, asset):
|
||||||
|
scene_or_collection.user_assets.remove(scene_or_collection.user_assets.find(asset["path"]))
|
||||||
|
|
||||||
|
def does_asset_exist(scene_or_collection, ref_asset):
|
||||||
|
user_assets = getattr(scene_or_collection, 'user_assets', [])
|
||||||
|
in_list = [asset for asset in user_assets if (asset.path == ref_asset["path"])]
|
||||||
in_list = len(in_list) > 0
|
in_list = len(in_list) > 0
|
||||||
return in_list
|
return in_list
|
@ -1,11 +1,12 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import uuid
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from bpy_types import (PropertyGroup)
|
from bpy_types import (PropertyGroup)
|
||||||
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
|
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
|
||||||
|
|
||||||
|
# Asset property group
|
||||||
|
class Asset(PropertyGroup):
|
||||||
|
name: StringProperty(name="asset name") # type: ignore
|
||||||
|
path: StringProperty(name="asset path") # type: ignore
|
||||||
|
|
||||||
# this is where we store the information for all available assets
|
# this is where we store the information for all available assets
|
||||||
#
|
#
|
||||||
@ -34,14 +35,19 @@ class AssetsRegistry(PropertyGroup):
|
|||||||
subtype='FILE_PATH'
|
subtype='FILE_PATH'
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
|
bpy.types.Scene.user_assets = CollectionProperty(name="user assets", type=Asset)
|
||||||
|
bpy.types.Collection.user_assets = CollectionProperty(name="user assets", type=Asset)
|
||||||
bpy.types.WindowManager.assets_registry = PointerProperty(type=AssetsRegistry)
|
bpy.types.WindowManager.assets_registry = PointerProperty(type=AssetsRegistry)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def unregister(cls):
|
def unregister(cls):
|
||||||
del bpy.types.WindowManager.assets_registry
|
del bpy.types.WindowManager.assets_registry
|
||||||
|
del bpy.types.Scene.user_assets
|
||||||
|
del bpy.types.Collection.user_assets
|
||||||
|
|
||||||
def add_asset(self, name, type, path, internal): # internal means it cannot be edited by the user, aka auto generated
|
def add_asset(self, name, type, path, internal): # internal means it cannot be edited by the user, aka auto generated
|
||||||
in_list = [asset for asset in self.assets_list if (asset["path"] == path)]
|
in_list = [asset for asset in self.assets_list if (asset["path"] == path)]
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import json
|
import json
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from .asset_helpers import does_asset_exist, get_assets
|
from .asset_helpers import does_asset_exist, get_user_assets, get_user_assets_as_list
|
||||||
|
|
||||||
def scan_assets(scene, blueprints_data, addon_prefs):
|
def scan_assets(scene, blueprints_data, addon_prefs):
|
||||||
export_root_path = getattr(addon_prefs, "export_root_path")
|
export_root_path = getattr(addon_prefs, "export_root_path")
|
||||||
@ -48,6 +48,19 @@ def scan_assets(scene, blueprints_data, addon_prefs):
|
|||||||
print("blueprint assets", blueprint_assets_list)
|
print("blueprint assets", blueprint_assets_list)
|
||||||
|
|
||||||
|
|
||||||
|
def get_userTextures():
|
||||||
|
# TODO: limit this to the ones actually in use
|
||||||
|
# fetch images/textures
|
||||||
|
# see https://blender.stackexchange.com/questions/139859/how-to-get-absolute-file-path-for-linked-texture-image
|
||||||
|
textures = []
|
||||||
|
for ob in bpy.data.objects:
|
||||||
|
if ob.type == "MESH":
|
||||||
|
for mat_slot in ob.material_slots:
|
||||||
|
if mat_slot.material:
|
||||||
|
if mat_slot.material.node_tree:
|
||||||
|
textures.extend([x.image.filepath for x in mat_slot.material.node_tree.nodes if x.type=='TEX_IMAGE'])
|
||||||
|
print("textures", textures)
|
||||||
|
|
||||||
def get_blueprint_assets_tree(blueprint, blueprints_data, parent, addon_prefs):
|
def get_blueprint_assets_tree(blueprint, blueprints_data, parent, addon_prefs):
|
||||||
export_blueprints_path = getattr(addon_prefs, "export_blueprints_path")
|
export_blueprints_path = getattr(addon_prefs, "export_blueprints_path")
|
||||||
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
|
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
|
||||||
@ -64,15 +77,16 @@ def get_blueprint_assets_tree(blueprint, blueprints_data, parent, addon_prefs):
|
|||||||
# get the injected path of the external blueprints
|
# get the injected path of the external blueprints
|
||||||
blueprint_exported_path = child_blueprint.collection['export_path'] if 'export_path' in child_blueprint.collection else None
|
blueprint_exported_path = child_blueprint.collection['export_path'] if 'export_path' in child_blueprint.collection else None
|
||||||
if blueprint_exported_path is not None:
|
if blueprint_exported_path is not None:
|
||||||
assets_list.append({"name": child_blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "internal": True, "parent": blueprint.name})
|
assets_list.append({"name": child_blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "generated": True,"internal":blueprint.local, "parent": blueprint.name})
|
||||||
|
|
||||||
# and add sub stuff
|
# and add sub stuff
|
||||||
sub_assets_lists = get_blueprint_assets_tree(child_blueprint, blueprints_data, parent=child_blueprint.name, addon_prefs=addon_prefs)
|
sub_assets_lists = get_blueprint_assets_tree(child_blueprint, blueprints_data, parent=child_blueprint.name, addon_prefs=addon_prefs)
|
||||||
assets_list += sub_assets_lists
|
assets_list += sub_assets_lists
|
||||||
|
|
||||||
direct_assets = get_assets(blueprint.collection)
|
direct_assets = get_user_assets_as_list(blueprint.collection)
|
||||||
for asset in direct_assets:
|
for asset in direct_assets:
|
||||||
asset["parent"] = parent
|
asset["parent"] = parent
|
||||||
|
asset["internal"] = blueprint.local
|
||||||
assets_list += direct_assets
|
assets_list += direct_assets
|
||||||
return assets_list
|
return assets_list
|
||||||
|
|
||||||
@ -81,7 +95,7 @@ def get_main_scene_assets_tree(main_scene, blueprints_data, addon_prefs):
|
|||||||
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
|
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
|
||||||
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(main_scene.name, None)
|
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(main_scene.name, None)
|
||||||
|
|
||||||
assets_list = get_assets(main_scene) # FIXME: problem, we already have the blueprint assets stored there
|
assets_list = get_user_assets_as_list(main_scene)
|
||||||
if blueprint_instance_names_for_scene:
|
if blueprint_instance_names_for_scene:
|
||||||
for blueprint_name in blueprint_instance_names_for_scene:
|
for blueprint_name in blueprint_instance_names_for_scene:
|
||||||
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
|
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
|
||||||
@ -93,7 +107,7 @@ def get_main_scene_assets_tree(main_scene, blueprints_data, addon_prefs):
|
|||||||
# get the injected path of the external blueprints
|
# get the injected path of the external blueprints
|
||||||
blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None
|
blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None
|
||||||
if blueprint_exported_path is not None and not does_asset_exist(assets_list, blueprint_exported_path):
|
if blueprint_exported_path is not None and not does_asset_exist(assets_list, blueprint_exported_path):
|
||||||
assets_list.append({"name": blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "internal": True, "parent": None})
|
assets_list.append({"name": blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "generated": True, "internal":blueprint.local, "parent": None})
|
||||||
|
|
||||||
assets_list += get_blueprint_assets_tree(blueprint, blueprints_data, parent=blueprint.name, addon_prefs=addon_prefs)
|
assets_list += get_blueprint_assets_tree(blueprint, blueprints_data, parent=blueprint.name, addon_prefs=addon_prefs)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import bpy
|
|||||||
from bpy_types import (Operator)
|
from bpy_types import (Operator)
|
||||||
from bpy.props import (BoolProperty, StringProperty, EnumProperty)
|
from bpy.props import (BoolProperty, StringProperty, EnumProperty)
|
||||||
|
|
||||||
|
from .asset_helpers import does_asset_exist, get_user_assets, remove_asset, upsert_asset
|
||||||
from .assets_scan import get_main_scene_assets_tree
|
from .assets_scan import get_main_scene_assets_tree
|
||||||
|
|
||||||
from ..core.path_helpers import absolute_path_from_blend_file
|
from ..core.path_helpers import absolute_path_from_blend_file
|
||||||
@ -53,24 +54,26 @@ class OT_add_bevy_asset(Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
assets = []
|
assets = []
|
||||||
blueprint_assets = self.target_type == 'BLUEPRINT'
|
blueprint_assets = self.target_type == 'BLUEPRINT'
|
||||||
|
target = None
|
||||||
if blueprint_assets:
|
if blueprint_assets:
|
||||||
assets = json.loads(bpy.data.collections[self.target_name].get('assets')) if 'assets' in bpy.data.collections[self.target_name] else []
|
target = 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 []
|
target = bpy.data.scenes[self.target_name]
|
||||||
|
assets = get_user_assets(target)
|
||||||
|
asset = {"name": self.asset_name, "type": self.asset_type, "path": self.asset_path}
|
||||||
|
if not does_asset_exist(target, asset):
|
||||||
|
upsert_asset(target, asset)
|
||||||
|
|
||||||
in_list = [asset for asset in assets if (asset["path"] == self.asset_path)]
|
#assets.append({"name": self.asset_name, "type": self.asset_type, "path": self.asset_path, "internal": False})
|
||||||
in_list = len(in_list) > 0
|
|
||||||
if not in_list:
|
|
||||||
assets.append({"name": self.asset_name, "type": self.asset_type, "path": self.asset_path, "internal": False})
|
|
||||||
# reset controls
|
# reset controls
|
||||||
context.window_manager.assets_registry.asset_name_selector = ""
|
context.window_manager.assets_registry.asset_name_selector = ""
|
||||||
context.window_manager.assets_registry.asset_type_selector = "MODEL"
|
context.window_manager.assets_registry.asset_type_selector = "MODEL"
|
||||||
context.window_manager.assets_registry.asset_path_selector = ""
|
context.window_manager.assets_registry.asset_path_selector = ""
|
||||||
|
|
||||||
if blueprint_assets:
|
"""if blueprint_assets:
|
||||||
bpy.data.collections[self.target_name]["assets"] = json.dumps(assets)
|
bpy.data.collections[self.target_name]["assets"] = json.dumps(assets)
|
||||||
else:
|
else:
|
||||||
bpy.data.scenes[self.target_name]["assets"] = json.dumps(assets)
|
bpy.data.scenes[self.target_name]["assets"] = json.dumps(assets)"""
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
@ -114,16 +117,11 @@ class OT_remove_bevy_asset(Operator):
|
|||||||
assets = []
|
assets = []
|
||||||
blueprint_assets = self.target_type == 'BLUEPRINT'
|
blueprint_assets = self.target_type == 'BLUEPRINT'
|
||||||
if blueprint_assets:
|
if blueprint_assets:
|
||||||
assets = json.loads(bpy.data.collections[self.target_name].get('assets')) if 'assets' in bpy.data.collections[self.target_name] else []
|
target = 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 []
|
target = bpy.data.scenes[self.target_name]
|
||||||
|
remove_asset(target, {"path": self.asset_path})
|
||||||
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'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
@ -167,6 +165,33 @@ class OT_Add_asset_filebrowser(Operator, ImportHelper):
|
|||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
|
||||||
|
def write_ron_assets_file(level_name, assets_hierarchy, internal_only=False):
|
||||||
|
# just for testing, this uses the format of bevy_asset_loader's asset files
|
||||||
|
'''
|
||||||
|
({
|
||||||
|
"world":File (path: "models/StartLevel.glb"),
|
||||||
|
"level1":File (path: "models/Level1.glb"),
|
||||||
|
"level2":File (path: "models/Level2.glb"),
|
||||||
|
|
||||||
|
"models": Folder (
|
||||||
|
path: "models/library",
|
||||||
|
),
|
||||||
|
"materials": Folder (
|
||||||
|
path: "materials",
|
||||||
|
),
|
||||||
|
})
|
||||||
|
'''
|
||||||
|
formated_assets = []
|
||||||
|
for asset in assets_hierarchy:
|
||||||
|
if asset["internal"] or not internal_only:
|
||||||
|
bla = f'\n "{asset["name"]}": File ( path: "{asset["path"]}" ),'
|
||||||
|
formated_assets.append(bla)
|
||||||
|
with open(f"testing/bevy_example/assets/assets_{level_name}.assets.ron", "w") as assets_file:
|
||||||
|
assets_file.write("({")
|
||||||
|
assets_file.writelines(formated_assets)
|
||||||
|
assets_file.write("\n})")
|
||||||
|
|
||||||
class OT_test_bevy_assets(Operator):
|
class OT_test_bevy_assets(Operator):
|
||||||
"""Test assets"""
|
"""Test assets"""
|
||||||
bl_idname = "bevyassets.test"
|
bl_idname = "bevyassets.test"
|
||||||
@ -183,5 +208,7 @@ class OT_test_bevy_assets(Operator):
|
|||||||
for scene in bpy.data.scenes:
|
for scene in bpy.data.scenes:
|
||||||
if scene.name != "Library":
|
if scene.name != "Library":
|
||||||
assets_hierarchy = get_main_scene_assets_tree(scene, blueprints_data, settings)
|
assets_hierarchy = get_main_scene_assets_tree(scene, blueprints_data, settings)
|
||||||
scene["assets_hierarchy"] = json.dumps(assets_hierarchy)
|
scene["assets"] = json.dumps(assets_hierarchy)
|
||||||
|
write_ron_assets_file(scene.name, assets_hierarchy, internal_only=False)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
import bpy
|
import bpy
|
||||||
from .assets_scan import get_main_scene_assets_tree
|
from .assets_scan import get_main_scene_assets_tree
|
||||||
from .asset_helpers import get_assets
|
from .asset_helpers import get_user_assets
|
||||||
|
|
||||||
|
|
||||||
def draw_assets(layout, name, title, asset_registry, assets, target_type, target_name, editable=True):
|
def draw_assets(layout, name, title, asset_registry, target_type, target_name, editable=True, user_assets= [], generated_assets = []):
|
||||||
header, panel = layout.box().panel(f"assets{name}", default_closed=False)
|
header, panel = layout.box().panel(f"assets{name}", default_closed=False)
|
||||||
header.label(text=title)
|
header.label(text=title)
|
||||||
if panel:
|
if panel:
|
||||||
@ -29,20 +29,28 @@ def draw_assets(layout, name, title, asset_registry, assets, target_type, target
|
|||||||
add_asset.asset_name = asset_registry.asset_name_selector
|
add_asset.asset_name = asset_registry.asset_name_selector
|
||||||
add_asset.asset_type = asset_registry.asset_type_selector
|
add_asset.asset_type = asset_registry.asset_type_selector
|
||||||
add_asset.asset_path = asset_registry.asset_path_selector
|
add_asset.asset_path = asset_registry.asset_path_selector
|
||||||
|
panel.separator()
|
||||||
|
|
||||||
#assets = json.loads(blueprint.collection["assets"]) if "assets" in blueprint.collection else []
|
for asset in user_assets:
|
||||||
for asset in assets:
|
|
||||||
row = panel.row()
|
row = panel.row()
|
||||||
row.label(text=asset["name"])
|
row.prop(asset, "name", text="")
|
||||||
row.label(text=asset["type"])
|
#row.prop(asset, "path", text="")
|
||||||
row.label(text=asset["path"])
|
row.label(text=asset.path)
|
||||||
if not asset["internal"] and editable:
|
asset_selector = row.operator(operator="asset.open_filebrowser", text="", icon="FILE_FOLDER")
|
||||||
|
|
||||||
|
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
|
||||||
|
"""if not asset["internal"] and editable:
|
||||||
remove_asset = row.operator(operator="bevyassets.remove", text="", icon="TRASH")
|
remove_asset = row.operator(operator="bevyassets.remove", text="", icon="TRASH")
|
||||||
remove_asset.target_type = target_type
|
remove_asset.target_type = target_type
|
||||||
remove_asset.target_name = target_name
|
remove_asset.target_name = target_name
|
||||||
remove_asset.asset_path = asset["path"]
|
remove_asset.asset_path = asset["path"]
|
||||||
else:
|
else:
|
||||||
row.label(text="")
|
row.label(text="")"""
|
||||||
|
for asset in generated_assets:
|
||||||
|
pass
|
||||||
|
|
||||||
return panel
|
return panel
|
||||||
|
|
||||||
@ -78,15 +86,16 @@ class Blenvy_assets(bpy.types.Panel):
|
|||||||
if panel:
|
if panel:
|
||||||
for scene in bpy.data.scenes:
|
for scene in bpy.data.scenes:
|
||||||
if scene.name != "Library": # FIXME: hack for testing
|
if scene.name != "Library": # FIXME: hack for testing
|
||||||
get_main_scene_assets_tree(scene, blueprints_data, settings)
|
#get_main_scene_assets_tree(scene, blueprints_data, settings)
|
||||||
|
|
||||||
direct_assets = get_assets(scene)
|
user_assets = get_user_assets(scene)
|
||||||
row = panel.row()
|
row = panel.row()
|
||||||
scene_assets_panel = draw_assets(layout=row, name=scene.name, title=f"{scene.name} Assets", asset_registry=asset_registry, assets=direct_assets, target_type="SCENE", target_name=scene.name)
|
scene_assets_panel = draw_assets(layout=row, name=scene.name, title=f"{scene.name} Assets", asset_registry=asset_registry, user_assets=user_assets, target_type="SCENE", target_name=scene.name)
|
||||||
if scene.name in blueprints_data.blueprint_instances_per_main_scene:
|
"""if scene.name in blueprints_data.blueprint_instances_per_main_scene:
|
||||||
for blueprint_name in blueprints_data.blueprint_instances_per_main_scene[scene.name].keys():
|
for blueprint_name in blueprints_data.blueprint_instances_per_main_scene[scene.name].keys():
|
||||||
blueprint = blueprints_data.blueprints_per_name[blueprint_name]
|
blueprint = blueprints_data.blueprints_per_name[blueprint_name]
|
||||||
blueprint_assets = get_assets(blueprint.collection)
|
blueprint_assets = get_user_assets(blueprint.collection)
|
||||||
if scene_assets_panel:
|
if scene_assets_panel:
|
||||||
row = scene_assets_panel.row()
|
row = scene_assets_panel.row()
|
||||||
draw_assets(layout=row, name=blueprint.name, title=f"{blueprint.name} Assets", asset_registry=asset_registry, assets=blueprint_assets, target_type="BLUEPRINT", target_name=blueprint.name)
|
draw_assets(layout=row, name=blueprint.name, title=f"{blueprint.name} Assets", asset_registry=asset_registry, assets=blueprint_assets, target_type="BLUEPRINT", target_name=blueprint.name)
|
||||||
|
"""
|
@ -37,19 +37,6 @@ def inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs):
|
|||||||
assets_list_data = {}
|
assets_list_data = {}
|
||||||
|
|
||||||
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(scene.name, None)
|
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(scene.name, None)
|
||||||
# find all blueprints used in a scene
|
|
||||||
blueprints_in_scene = []
|
|
||||||
if blueprint_instance_names_for_scene: # what are the blueprints used in this scene, inject those into the assets list component
|
|
||||||
children_per_blueprint = {}
|
|
||||||
for blueprint_name in blueprint_instance_names_for_scene:
|
|
||||||
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
|
|
||||||
if blueprint:
|
|
||||||
children_per_blueprint[blueprint_name] = blueprint.nested_blueprints
|
|
||||||
blueprints_in_scene += blueprint.nested_blueprints
|
|
||||||
assets_list_data["BlueprintsList"] = f"({json.dumps(dict(children_per_blueprint))})"
|
|
||||||
print(blueprint_instance_names_for_scene)
|
|
||||||
# add_scene_property(scene, assets_list_name, assets_list_data)
|
|
||||||
|
|
||||||
blueprint_assets_list = []
|
blueprint_assets_list = []
|
||||||
if blueprint_instance_names_for_scene:
|
if blueprint_instance_names_for_scene:
|
||||||
for blueprint_name in blueprint_instance_names_for_scene:
|
for blueprint_name in blueprint_instance_names_for_scene:
|
||||||
@ -67,25 +54,15 @@ def inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs):
|
|||||||
blueprint_assets_list.append({"name": blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "internal": True})
|
blueprint_assets_list.append({"name": blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "internal": True})
|
||||||
|
|
||||||
|
|
||||||
# fetch images/textures
|
|
||||||
# see https://blender.stackexchange.com/questions/139859/how-to-get-absolute-file-path-for-linked-texture-image
|
|
||||||
textures = []
|
|
||||||
for ob in bpy.data.objects:
|
|
||||||
if ob.type == "MESH":
|
|
||||||
for mat_slot in ob.material_slots:
|
|
||||||
if mat_slot.material:
|
|
||||||
if mat_slot.material.node_tree:
|
|
||||||
textures.extend([x.image.filepath for x in mat_slot.material.node_tree.nodes if x.type=='TEX_IMAGE'])
|
|
||||||
print("textures", textures)
|
|
||||||
|
|
||||||
assets_list_name = f"assets_{scene.name}"
|
assets_list_name = f"assets_{scene.name}"
|
||||||
assets_list_data = {"blueprints": json.dumps(blueprint_assets_list), "sounds":[], "images":[]}
|
|
||||||
scene["assets"] = json.dumps(blueprint_assets_list)
|
scene["assets"] = json.dumps(blueprint_assets_list)
|
||||||
|
|
||||||
print("blueprint assets", blueprint_assets_list)
|
print("blueprint assets", blueprint_assets_list)
|
||||||
add_scene_property(scene, assets_list_name, assets_list_data)
|
"""add_scene_property(scene, assets_list_name, assets_list_data)
|
||||||
for blueprint in blueprint_assets_list:
|
for blueprint in blueprint_assets_list:
|
||||||
bpy.context.window_manager.assets_registry.add_asset(**blueprint)
|
bpy.context.window_manager.assets_registry.add_asset(**blueprint)"""
|
||||||
|
|
||||||
def remove_blueprints_list_from_main_scene(scene):
|
def remove_blueprints_list_from_main_scene(scene):
|
||||||
assets_list = None
|
assets_list = None
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import bpy
|
import bpy
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from ..assets.asset_helpers import get_user_assets
|
||||||
|
|
||||||
from ..assets.ui import draw_assets
|
from ..assets.ui import draw_assets
|
||||||
|
|
||||||
class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
|
class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
|
||||||
@ -33,11 +35,10 @@ class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
|
|||||||
select_blueprint.blueprint_collection_name = blueprint.collection.name
|
select_blueprint.blueprint_collection_name = blueprint.collection.name
|
||||||
select_blueprint.blueprint_scene_name = blueprint.scene.name
|
select_blueprint.blueprint_scene_name = blueprint.scene.name
|
||||||
|
|
||||||
assets = json.loads(blueprint.collection["assets"]) if "assets" in blueprint.collection else []
|
user_assets = get_user_assets(blueprint.collection)
|
||||||
|
draw_assets(layout=layout, name=blueprint.name, title="Assets", asset_registry=asset_registry, user_assets=user_assets, target_type="BLUEPRINT", target_name=blueprint.name)
|
||||||
draw_assets(layout=layout, name=blueprint.name, title="Assets", asset_registry=asset_registry, assets=assets, target_type="BLUEPRINT", target_name=blueprint.name)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assets = json.loads(blueprint.collection["assets"]) if "assets" in blueprint.collection else []
|
assets = get_user_assets(blueprint.collection)
|
||||||
draw_assets(layout=layout, name=blueprint.name, title="Assets", asset_registry=asset_registry, assets=assets, target_type="BLUEPRINT", target_name=blueprint.name, editable=False)
|
draw_assets(layout=layout, name=blueprint.name, title="Assets", asset_registry=asset_registry, user_assets=user_assets, target_type="BLUEPRINT", target_name=blueprint.name, editable=False)
|
||||||
row.label(text="External")
|
row.label(text="External")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy_types import (PropertyGroup)
|
from bpy_types import (PropertyGroup)
|
||||||
from bpy.props import (EnumProperty, PointerProperty, StringProperty)
|
from bpy.props import (EnumProperty, PointerProperty, StringProperty, CollectionProperty, IntProperty)
|
||||||
|
from .scene_helpers import SceneSelector
|
||||||
|
|
||||||
class BlenvyManager(PropertyGroup):
|
class BlenvyManager(PropertyGroup):
|
||||||
|
|
||||||
@ -46,14 +46,38 @@ class BlenvyManager(PropertyGroup):
|
|||||||
description='path to export the materials libraries to (relative to the assets folder)',
|
description='path to export the materials libraries to (relative to the assets folder)',
|
||||||
default='materials',
|
default='materials',
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
|
main_scenes: CollectionProperty(name="main scenes", type=SceneSelector) # type: ignore
|
||||||
|
main_scenes_index: IntProperty(name = "Index for main scenes list", default = 0) # type: ignore
|
||||||
|
|
||||||
|
library_scenes: CollectionProperty(name="library scenes", type=SceneSelector) # type: ignore
|
||||||
|
library_scenes_index: IntProperty(name = "Index for library scenes list", default = 0) # type: ignore
|
||||||
|
|
||||||
|
def is_scene_ok(self, scene):
|
||||||
|
try:
|
||||||
|
operator = bpy.context.space_data.active_operator
|
||||||
|
return scene.name not in operator.main_scenes and scene.name not in operator.library_scenes
|
||||||
|
except:
|
||||||
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
|
bpy.types.WindowManager.main_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=cls.is_scene_ok)
|
||||||
|
bpy.types.WindowManager.library_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=cls.is_scene_ok)
|
||||||
|
|
||||||
|
bpy.types.WindowManager.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0)
|
||||||
|
bpy.types.WindowManager.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0)
|
||||||
|
|
||||||
bpy.types.WindowManager.blenvy = PointerProperty(type=BlenvyManager)
|
bpy.types.WindowManager.blenvy = PointerProperty(type=BlenvyManager)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def unregister(cls):
|
def unregister(cls):
|
||||||
del bpy.types.WindowManager.blenvy
|
del bpy.types.WindowManager.blenvy
|
||||||
|
del bpy.types.WindowManager.main_scene
|
||||||
|
del bpy.types.WindowManager.library_scene
|
||||||
|
|
||||||
|
del bpy.types.WindowManager.main_scenes_list_index
|
||||||
|
del bpy.types.WindowManager.library_scenes_list_index
|
||||||
|
|
||||||
|
|
||||||
def add_asset(self, name, type, path, internal): # internal means it cannot be edited by the user, aka auto generated
|
def add_asset(self, name, type, path, internal): # internal means it cannot be edited by the user, aka auto generated
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
import bpy
|
||||||
|
from .object_makers import make_empty
|
||||||
|
|
||||||
|
|
||||||
|
class SceneSelector(bpy.types.PropertyGroup):
|
||||||
|
name: bpy.props.StringProperty() # type: ignore
|
||||||
|
display: bpy.props.BoolProperty() # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def add_scene_property(scene, scene_component_name, property_data, limit_to=None):
|
def add_scene_property(scene, scene_component_name, property_data, limit_to=None):
|
||||||
root_collection = scene.collection
|
root_collection = scene.collection
|
||||||
scene_property = None
|
scene_property = None
|
||||||
|
0
tools/blenvy/core/ui/__init__.py
Normal file
0
tools/blenvy/core/ui/__init__.py
Normal file
77
tools/blenvy/core/ui/folder_browser.py
Normal file
77
tools/blenvy/core/ui/folder_browser.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
import bpy
|
||||||
|
import os
|
||||||
|
from bpy_extras.io_utils import ImportHelper
|
||||||
|
from bpy.types import Operator
|
||||||
|
|
||||||
|
class OT_OpenFolderbrowser(Operator, ImportHelper):
|
||||||
|
"""Browse for registry json file"""
|
||||||
|
bl_idname = "generic.open_folderbrowser"
|
||||||
|
bl_label = "Select folder"
|
||||||
|
|
||||||
|
# Define this to tell 'fileselect_add' that we want a directoy
|
||||||
|
directory: bpy.props.StringProperty(
|
||||||
|
name="Outdir Path",
|
||||||
|
description="selected folder"
|
||||||
|
# subtype='DIR_PATH' is not needed to specify the selection mode.
|
||||||
|
# But this will be anyway a directory path.
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
# Filters folders
|
||||||
|
filter_folder: bpy.props.BoolProperty(
|
||||||
|
default=True,
|
||||||
|
options={"HIDDEN"}
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
target_property: bpy.props.StringProperty(
|
||||||
|
name="target_property",
|
||||||
|
options={'HIDDEN'}
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
"""Do something with the selected file(s)."""
|
||||||
|
operator = context.window_manager.blenvy
|
||||||
|
new_path = self.directory
|
||||||
|
target_path_name = self.target_property
|
||||||
|
|
||||||
|
# path to the current blend file
|
||||||
|
blend_file_path = bpy.data.filepath
|
||||||
|
# Get the folder
|
||||||
|
blend_file_folder_path = os.path.dirname(blend_file_path)
|
||||||
|
print("blend_file_folder_path", blend_file_folder_path)
|
||||||
|
print("new_path", self.directory, self.target_property, operator)
|
||||||
|
|
||||||
|
asset_path_names = ['export_assets_path', 'export_blueprints_path', 'export_levels_path', 'export_materials_path']
|
||||||
|
export_root_path = operator.export_root_path
|
||||||
|
export_assets_path = operator.export_assets_path
|
||||||
|
#export_root_path_absolute = os.path.join(blend_file_folder_path, export_root_path)
|
||||||
|
export_assets_path_full = os.path.join(blend_file_folder_path, export_root_path, export_assets_path)
|
||||||
|
print("export_assets_path_full", export_assets_path_full)
|
||||||
|
|
||||||
|
#new_root_path = os.path.join(blend_file_folder_path, new_path)
|
||||||
|
if target_path_name == 'export_root_path':
|
||||||
|
new_root_path_relative = os.path.relpath(new_path, blend_file_folder_path)
|
||||||
|
print("changing root new_path to", self.directory, blend_file_folder_path, new_root_path_relative)
|
||||||
|
# we need to change all other relative paths before setting the new absolute path
|
||||||
|
for path_name in asset_path_names:
|
||||||
|
# get current relative path
|
||||||
|
relative_path = getattr(operator, path_name, None)
|
||||||
|
if relative_path is not None:
|
||||||
|
# and now get absolute path of asset_path
|
||||||
|
absolute_path = os.path.join(export_assets_path_full, relative_path)
|
||||||
|
print("absolute path for", path_name, absolute_path)
|
||||||
|
relative_path = os.path.relpath(absolute_path, new_path)
|
||||||
|
setattr(operator, path_name, relative_path)
|
||||||
|
|
||||||
|
# store the root path as relative to the current blend file
|
||||||
|
setattr(operator, target_path_name, new_path)
|
||||||
|
elif target_path_name == 'export_assets_path':
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
relative_path = os.path.relpath(new_path, export_assets_path_full)
|
||||||
|
setattr(operator, target_path_name, relative_path)
|
||||||
|
|
||||||
|
#filename, extension = os.path.splitext(self.filepath)
|
||||||
|
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
114
tools/blenvy/core/ui/scenes_list.py
Normal file
114
tools/blenvy/core/ui/scenes_list.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import bpy
|
||||||
|
from bpy.types import Operator
|
||||||
|
|
||||||
|
class SCENE_UL_Blenvy(bpy.types.UIList):
|
||||||
|
# The draw_item function is called for each item of the collection that is visible in the list.
|
||||||
|
# data is the RNA object containing the collection,
|
||||||
|
# item is the current drawn item of the collection,
|
||||||
|
# icon is the "computed" icon for the item (as an integer, because some objects like materials or textures
|
||||||
|
# have custom icons ID, which are not available as enum items).
|
||||||
|
# active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the
|
||||||
|
# active item of the collection).
|
||||||
|
# active_propname is the name of the active property (use 'getattr(active_data, active_propname)').
|
||||||
|
# index is index of the current item in the collection.
|
||||||
|
# flt_flag is the result of the filtering process for this item.
|
||||||
|
# Note: as index and flt_flag are optional arguments, you do not have to use/declare them here if you don't
|
||||||
|
# need them.
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
print("DRAW STUFF", self)
|
||||||
|
ob = data
|
||||||
|
# draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
|
||||||
|
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||||
|
# You should always start your row layout by a label (icon + text), or a non-embossed text field,
|
||||||
|
# this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
|
||||||
|
# We use icon_value of label, as our given icon is an integer value, not an enum ID.
|
||||||
|
# Note "data" names should never be translated!
|
||||||
|
#if ma:
|
||||||
|
# layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
|
||||||
|
#else:
|
||||||
|
# layout.label(text="", translate=False, icon_value=icon)
|
||||||
|
layout.label(text=item.name, icon_value=icon)
|
||||||
|
#layout.prop(item, "name", text="", emboss=False, icon_value=icon)
|
||||||
|
# 'GRID' layout type should be as compact as possible (typically a single icon!).
|
||||||
|
elif self.layout_type == 'GRID':
|
||||||
|
layout.alignment = 'CENTER'
|
||||||
|
layout.label(text="", icon_value=icon)
|
||||||
|
|
||||||
|
|
||||||
|
class SCENES_LIST_OT_actions(Operator):
|
||||||
|
"""Move items up and down, add and remove"""
|
||||||
|
bl_idname = "scene_list.list_action"
|
||||||
|
bl_label = "List Actions"
|
||||||
|
bl_description = "Move items up and down, add and remove"
|
||||||
|
bl_options = {'REGISTER'}
|
||||||
|
|
||||||
|
action: bpy.props.EnumProperty(
|
||||||
|
items=(
|
||||||
|
('UP', "Up", ""),
|
||||||
|
('DOWN', "Down", ""),
|
||||||
|
('REMOVE', "Remove", ""),
|
||||||
|
('ADD', "Add", ""))) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
scene_type: bpy.props.StringProperty()# type: ignore #TODO: replace with enum
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
source = context.window_manager.blenvy
|
||||||
|
target_name = "library_scenes"
|
||||||
|
target_index = "library_scenes_index"
|
||||||
|
if self.scene_type == "level":
|
||||||
|
target_name = "main_scenes"
|
||||||
|
target_index = "main_scenes_index"
|
||||||
|
|
||||||
|
target = getattr(source, target_name)
|
||||||
|
idx = getattr(source, target_index)
|
||||||
|
current_index = getattr(source, target_index)
|
||||||
|
|
||||||
|
try:
|
||||||
|
item = target[idx]
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if self.action == 'DOWN' and idx < len(target) - 1:
|
||||||
|
target.move(idx, idx + 1)
|
||||||
|
setattr(source, target_index, current_index +1 )
|
||||||
|
info = 'Item "%s" moved to position %d' % (item.name, current_index + 1)
|
||||||
|
self.report({'INFO'}, info)
|
||||||
|
|
||||||
|
elif self.action == 'UP' and idx >= 1:
|
||||||
|
target.move(idx, idx - 1)
|
||||||
|
setattr(source, target_index, current_index -1 )
|
||||||
|
info = 'Item "%s" moved to position %d' % (item.name, current_index + 1)
|
||||||
|
self.report({'INFO'}, info)
|
||||||
|
|
||||||
|
elif self.action == 'REMOVE':
|
||||||
|
info = 'Item "%s" removed from list' % (target[idx].name)
|
||||||
|
setattr(source, target_index, current_index -1 )
|
||||||
|
target.remove(idx)
|
||||||
|
self.report({'INFO'}, info)
|
||||||
|
|
||||||
|
if self.action == 'ADD':
|
||||||
|
new_scene_name = None
|
||||||
|
if self.scene_type == "level":
|
||||||
|
if context.window_manager.main_scene:
|
||||||
|
new_scene_name = context.window_manager.main_scene.name
|
||||||
|
else:
|
||||||
|
if context.window_manager.library_scene:
|
||||||
|
new_scene_name = context.window_manager.library_scene.name
|
||||||
|
if new_scene_name:
|
||||||
|
item = target.add()
|
||||||
|
item.name = new_scene_name#f"Rule {idx +1}"
|
||||||
|
|
||||||
|
if self.scene_type == "level":
|
||||||
|
context.window_manager.main_scene = None
|
||||||
|
else:
|
||||||
|
context.window_manager.library_scene = None
|
||||||
|
|
||||||
|
#name = f"Rule {idx +1}"
|
||||||
|
#target.append({"name": name})
|
||||||
|
setattr(source, target_index, len(target) - 1)
|
||||||
|
#source[target_index] = len(target) - 1
|
||||||
|
info = '"%s" added to list' % (item.name)
|
||||||
|
self.report({'INFO'}, info)
|
||||||
|
|
||||||
|
return {"FINISHED"}
|
@ -1,7 +1,8 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from ..settings import load_settings
|
from ...settings import load_settings
|
||||||
|
|
||||||
######################################################
|
######################################################
|
||||||
|
|
||||||
## ui logic & co
|
## ui logic & co
|
||||||
def draw_folder_browser(layout, label, prop_origin, target_property):
|
def draw_folder_browser(layout, label, prop_origin, target_property):
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
@ -80,7 +81,6 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
|
|||||||
layout.label(text="Library scene active: "+ str(library_scene_active))
|
layout.label(text="Library scene active: "+ str(library_scene_active))
|
||||||
layout.label(text=blenvy.mode)"""
|
layout.label(text=blenvy.mode)"""
|
||||||
|
|
||||||
|
|
||||||
if blenvy.mode == "SETTINGS":
|
if blenvy.mode == "SETTINGS":
|
||||||
header, panel = layout.panel("auto_export", default_closed=False)
|
header, panel = layout.panel("auto_export", default_closed=False)
|
||||||
header.label(text="Common")
|
header.label(text="Common")
|
||||||
@ -95,6 +95,55 @@ class BLENVY_PT_SidePanel(bpy.types.Panel):
|
|||||||
draw_folder_browser(layout=row, label="Levels Folder", prop_origin=blenvy, target_property="export_levels_path")
|
draw_folder_browser(layout=row, label="Levels Folder", prop_origin=blenvy, target_property="export_levels_path")
|
||||||
row = panel.row()
|
row = panel.row()
|
||||||
draw_folder_browser(layout=row, label="Materials Folder", prop_origin=blenvy, target_property="export_materials_path")
|
draw_folder_browser(layout=row, label="Materials Folder", prop_origin=blenvy, target_property="export_materials_path")
|
||||||
|
|
||||||
|
panel.separator()
|
||||||
|
# scenes selection
|
||||||
|
section = panel
|
||||||
|
rows = 2
|
||||||
|
row = section.row()
|
||||||
|
row.label(text="main scenes")
|
||||||
|
row.prop(context.window_manager, "main_scene", text='')
|
||||||
|
|
||||||
|
row = section.row()
|
||||||
|
row.template_list("SCENE_UL_Blenvy", "level scenes", blenvy, "main_scenes", blenvy, "main_scenes_index", rows=rows)
|
||||||
|
|
||||||
|
col = row.column(align=True)
|
||||||
|
sub_row = col.row()
|
||||||
|
add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="")
|
||||||
|
add_operator.action = 'ADD'
|
||||||
|
add_operator.scene_type = 'level'
|
||||||
|
#add_operator.operator = operator
|
||||||
|
sub_row.enabled = context.window_manager.main_scene is not None
|
||||||
|
|
||||||
|
sub_row = col.row()
|
||||||
|
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="")
|
||||||
|
remove_operator.action = 'REMOVE'
|
||||||
|
remove_operator.scene_type = 'level'
|
||||||
|
col.separator()
|
||||||
|
|
||||||
|
# library scenes
|
||||||
|
row = section.row()
|
||||||
|
row.label(text="library scenes")
|
||||||
|
row.prop(context.window_manager, "library_scene", text='')
|
||||||
|
|
||||||
|
row = section.row()
|
||||||
|
row.template_list("SCENE_UL_Blenvy", "library scenes", blenvy, "library_scenes", blenvy, "library_scenes_index", rows=rows)
|
||||||
|
|
||||||
|
col = row.column(align=True)
|
||||||
|
sub_row = col.row()
|
||||||
|
add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="")
|
||||||
|
add_operator.action = 'ADD'
|
||||||
|
add_operator.scene_type = 'library'
|
||||||
|
sub_row.enabled = context.window_manager.library_scene is not None
|
||||||
|
|
||||||
|
|
||||||
|
sub_row = col.row()
|
||||||
|
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="")
|
||||||
|
remove_operator.action = 'REMOVE'
|
||||||
|
remove_operator.scene_type = 'library'
|
||||||
|
col.separator()
|
||||||
|
|
||||||
|
|
||||||
"""if blenvy.mode == "SETTINGS":
|
"""if blenvy.mode == "SETTINGS":
|
||||||
header, panel = layout.panel("auto_export", default_closed=False)
|
header, panel = layout.panel("auto_export", default_closed=False)
|
||||||
header.label(text="Auto Export")
|
header.label(text="Auto Export")
|
@ -109,10 +109,10 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
|
|||||||
bpy.context.window_manager.auto_export_tracker.exports_total = exports_total
|
bpy.context.window_manager.auto_export_tracker.exports_total = exports_total
|
||||||
bpy.context.window_manager.auto_export_tracker.exports_count = exports_total
|
bpy.context.window_manager.auto_export_tracker.exports_count = exports_total
|
||||||
|
|
||||||
bpy.context.window_manager.exportedCollections.clear()
|
"""bpy.context.window_manager.exportedCollections.clear()
|
||||||
for blueprint in blueprints_to_export:
|
for blueprint in blueprints_to_export:
|
||||||
bla = bpy.context.window_manager.exportedCollections.add()
|
bla = bpy.context.window_manager.exportedCollections.add()
|
||||||
bla.name = blueprint.name
|
bla.name = blueprint.name"""
|
||||||
print("-------------------------------")
|
print("-------------------------------")
|
||||||
#print("collections: all:", collections)
|
#print("collections: all:", collections)
|
||||||
#print("collections: not found on disk:", collections_not_on_disk)
|
#print("collections: not found on disk:", collections_not_on_disk)
|
||||||
|
@ -29,7 +29,7 @@ def export_main_scene(scene, blend_file_path, addon_prefs, blueprints_data):
|
|||||||
if export_blueprints :
|
if export_blueprints :
|
||||||
gltf_output_path = os.path.join(export_levels_path_full, scene.name)
|
gltf_output_path = os.path.join(export_levels_path_full, scene.name)
|
||||||
|
|
||||||
inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs)
|
#inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs)
|
||||||
return
|
return
|
||||||
if export_separate_dynamic_and_static_objects:
|
if export_separate_dynamic_and_static_objects:
|
||||||
#print("SPLIT STATIC AND DYNAMIC")
|
#print("SPLIT STATIC AND DYNAMIC")
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import bpy
|
|
||||||
|
|
||||||
class SceneLink(bpy.types.PropertyGroup):
|
|
||||||
name: bpy.props.StringProperty(name="") # type: ignore
|
|
||||||
scene: bpy.props.PointerProperty(type=bpy.types.Scene) # type: ignore
|
|
||||||
|
|
||||||
class SceneLinks(bpy.types.PropertyGroup):
|
|
||||||
name = bpy.props.StringProperty(name="List of scenes to export", default="Unknown")
|
|
||||||
items: bpy.props.CollectionProperty(type = SceneLink) # type: ignore
|
|
||||||
|
|
||||||
class CUSTOM_PG_sceneName(bpy.types.PropertyGroup):
|
|
||||||
name: bpy.props.StringProperty() # type: ignore
|
|
||||||
display: bpy.props.BoolProperty() # type: ignore
|
|
||||||
|
|
||||||
class CollectionToExport(bpy.types.PropertyGroup):
|
|
||||||
name: bpy.props.StringProperty(name="") # type: ignore
|
|
||||||
|
|
||||||
class BlueprintsToExport(bpy.types.PropertyGroup):
|
|
||||||
name = bpy.props.StringProperty(name="List of collections to export", default="Unknown")
|
|
||||||
items: bpy.props.CollectionProperty(type = CollectionToExport) # type: ignore
|
|
||||||
|
|
||||||
|
|
@ -1,11 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Operator
|
from bpy.types import Operator
|
||||||
from bpy_extras.io_utils import ExportHelper
|
|
||||||
from bpy.props import (IntProperty, StringProperty, BoolProperty)
|
|
||||||
|
|
||||||
from ..ui.operators import OT_OpenFolderbrowser, draw_folder_browser
|
|
||||||
|
|
||||||
#from ..ui.main import GLTF_PT_auto_export_general, GLTF_PT_auto_export_main, GLTF_PT_auto_export_root
|
#from ..ui.main import GLTF_PT_auto_export_general, GLTF_PT_auto_export_main, GLTF_PT_auto_export_root
|
||||||
|
|
||||||
from .preferences import (AutoExportGltfAddonPreferences, AutoExportGltfPreferenceNames)
|
from .preferences import (AutoExportGltfAddonPreferences, AutoExportGltfPreferenceNames)
|
||||||
@ -54,29 +49,11 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
bpy.types.WindowManager.main_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=cls.is_scene_ok)
|
pass
|
||||||
bpy.types.WindowManager.library_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=cls.is_scene_ok)
|
|
||||||
|
|
||||||
bpy.types.WindowManager.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0)
|
|
||||||
bpy.types.WindowManager.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0)
|
|
||||||
|
|
||||||
cls.main_scenes_index = 0
|
|
||||||
cls.library_scenes_index = 0
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def unregister(cls):
|
def unregister(cls):
|
||||||
del bpy.types.WindowManager.main_scene
|
pass
|
||||||
del bpy.types.WindowManager.library_scene
|
|
||||||
|
|
||||||
del bpy.types.WindowManager.main_scenes_list_index
|
|
||||||
del bpy.types.WindowManager.library_scenes_list_index
|
|
||||||
|
|
||||||
def is_scene_ok(self, scene):
|
|
||||||
try:
|
|
||||||
operator = bpy.context.space_data.active_operator
|
|
||||||
return scene.name not in operator.main_scenes and scene.name not in operator.library_scenes
|
|
||||||
except:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def format_settings(self):
|
def format_settings(self):
|
||||||
# find all props to save
|
# find all props to save
|
||||||
@ -362,17 +339,7 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper):
|
|||||||
if self.show_general_settings:
|
if self.show_general_settings:
|
||||||
section = layout.box()
|
section = layout.box()
|
||||||
section.enabled = controls_enabled
|
section.enabled = controls_enabled
|
||||||
|
section.prop(operator, "export_scene_settings")
|
||||||
draw_folder_browser(section, "Export root folder", self.export_root_path, "export_root_path")
|
|
||||||
row = section.row()
|
|
||||||
draw_folder_browser(row, "Assets Folder", self.export_root_path, "export_assets_path")
|
|
||||||
section.prop(operator, "export_scene_settings")
|
|
||||||
|
|
||||||
"""header, panel = layout.panel("my_panel_id", default_closed=False)
|
|
||||||
header.label(text="Hello World")
|
|
||||||
if panel:
|
|
||||||
panel.label(text="Success")"""
|
|
||||||
|
|
||||||
toggle_icon = "TRIA_DOWN" if self.show_change_detection_settings else "TRIA_RIGHT"
|
toggle_icon = "TRIA_DOWN" if self.show_change_detection_settings else "TRIA_RIGHT"
|
||||||
layout.prop(operator, "show_change_detection_settings", text="Change Detection", icon=toggle_icon)
|
layout.prop(operator, "show_change_detection_settings", text="Change Detection", icon=toggle_icon)
|
||||||
if self.show_change_detection_settings:
|
if self.show_change_detection_settings:
|
||||||
@ -380,56 +347,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper):
|
|||||||
section.enabled = controls_enabled
|
section.enabled = controls_enabled
|
||||||
section.prop(operator, "export_change_detection", text="Use change detection")
|
section.prop(operator, "export_change_detection", text="Use change detection")
|
||||||
|
|
||||||
# main/level scenes
|
|
||||||
toggle_icon = "TRIA_DOWN" if self.show_scene_settings else "TRIA_RIGHT"
|
|
||||||
layout.prop(operator, "show_scene_settings", text="Scenes", icon=toggle_icon)
|
|
||||||
if self.show_scene_settings:
|
|
||||||
section = layout.box()
|
|
||||||
section.enabled = controls_enabled
|
|
||||||
rows = 2
|
|
||||||
row = section.row()
|
|
||||||
row.label(text="main scenes")
|
|
||||||
row.prop(context.window_manager, "main_scene", text='')
|
|
||||||
|
|
||||||
row = section.row()
|
|
||||||
row.template_list("SCENE_UL_GLTF_auto_export", "level scenes", operator, "main_scenes", operator, "main_scenes_index", rows=rows)
|
|
||||||
|
|
||||||
col = row.column(align=True)
|
|
||||||
sub_row = col.row()
|
|
||||||
add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="")
|
|
||||||
add_operator.action = 'ADD'
|
|
||||||
add_operator.scene_type = 'level'
|
|
||||||
#add_operator.operator = operator
|
|
||||||
sub_row.enabled = context.window_manager.main_scene is not None
|
|
||||||
|
|
||||||
sub_row = col.row()
|
|
||||||
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="")
|
|
||||||
remove_operator.action = 'REMOVE'
|
|
||||||
remove_operator.scene_type = 'level'
|
|
||||||
col.separator()
|
|
||||||
|
|
||||||
# library scenes
|
|
||||||
row = section.row()
|
|
||||||
row.label(text="library scenes")
|
|
||||||
row.prop(context.window_manager, "library_scene", text='')
|
|
||||||
|
|
||||||
row = section.row()
|
|
||||||
row.template_list("SCENE_UL_GLTF_auto_export", "library scenes", operator, "library_scenes", operator, "library_scenes_index", rows=rows)
|
|
||||||
|
|
||||||
col = row.column(align=True)
|
|
||||||
sub_row = col.row()
|
|
||||||
add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="")
|
|
||||||
add_operator.action = 'ADD'
|
|
||||||
add_operator.scene_type = 'library'
|
|
||||||
sub_row.enabled = context.window_manager.library_scene is not None
|
|
||||||
|
|
||||||
|
|
||||||
sub_row = col.row()
|
|
||||||
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="")
|
|
||||||
remove_operator.action = 'REMOVE'
|
|
||||||
remove_operator.scene_type = 'library'
|
|
||||||
col.separator()
|
|
||||||
|
|
||||||
toggle_icon = "TRIA_DOWN" if self.show_blueprint_settings else "TRIA_RIGHT"
|
toggle_icon = "TRIA_DOWN" if self.show_blueprint_settings else "TRIA_RIGHT"
|
||||||
layout.prop(operator, "show_blueprint_settings", text="Blueprints", icon=toggle_icon)
|
layout.prop(operator, "show_blueprint_settings", text="Blueprints", icon=toggle_icon)
|
||||||
if self.show_blueprint_settings:
|
if self.show_blueprint_settings:
|
||||||
@ -441,15 +358,10 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper):
|
|||||||
section.enabled = controls_enabled and self.export_blueprints
|
section.enabled = controls_enabled and self.export_blueprints
|
||||||
|
|
||||||
# collections/blueprints
|
# collections/blueprints
|
||||||
draw_folder_browser(section, "Blueprints folder", self.export_root_path, "export_blueprints_path")
|
|
||||||
#section.prop(operator, "export_blueprints_path")
|
|
||||||
section.prop(operator, "collection_instances_combine_mode")
|
section.prop(operator, "collection_instances_combine_mode")
|
||||||
section.prop(operator, "export_marked_assets")
|
section.prop(operator, "export_marked_assets")
|
||||||
section.separator()
|
section.separator()
|
||||||
|
|
||||||
draw_folder_browser(section, "Levels folder", self.export_root_path, "export_levels_path")
|
|
||||||
#section.prop(operator, "export_levels_path")
|
|
||||||
|
|
||||||
section.prop(operator, "export_separate_dynamic_and_static_objects")
|
section.prop(operator, "export_separate_dynamic_and_static_objects")
|
||||||
section.separator()
|
section.separator()
|
||||||
|
|
||||||
@ -457,7 +369,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper):
|
|||||||
section.prop(operator, "export_materials_library")
|
section.prop(operator, "export_materials_library")
|
||||||
section = section.box()
|
section = section.box()
|
||||||
section.enabled = controls_enabled and self.export_materials_library
|
section.enabled = controls_enabled and self.export_materials_library
|
||||||
draw_folder_browser(section, 'Materials folder', self.export_root_path, "export_materials_path")
|
|
||||||
#section.prop(operator, "export_materials_path")
|
#section.prop(operator, "export_materials_path")
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ from bpy.props import (BoolProperty,
|
|||||||
CollectionProperty
|
CollectionProperty
|
||||||
)
|
)
|
||||||
|
|
||||||
from .internals import (CUSTOM_PG_sceneName)
|
|
||||||
|
|
||||||
AutoExportGltfPreferenceNames = [
|
AutoExportGltfPreferenceNames = [
|
||||||
'will_save_settings',
|
'will_save_settings',
|
||||||
'direct_mode',# specific to main auto_export operator
|
'direct_mode',# specific to main auto_export operator
|
||||||
@ -201,8 +199,3 @@ class AutoExportGltfAddonPreferences(AddonPreferences):
|
|||||||
default=True
|
default=True
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
main_scenes: CollectionProperty(name="main scenes", type=CUSTOM_PG_sceneName) # type: ignore
|
|
||||||
main_scenes_index: IntProperty(name = "Index for main scenes list", default = 0) # type: ignore
|
|
||||||
|
|
||||||
library_scenes: CollectionProperty(name="library scenes", type=CUSTOM_PG_sceneName) # type: ignore
|
|
||||||
library_scenes_index: IntProperty(name = "Index for library scenes list", default = 0) # type: ignore
|
|
||||||
|
@ -4,12 +4,7 @@ import bpy
|
|||||||
from bpy.types import (PropertyGroup)
|
from bpy.types import (PropertyGroup)
|
||||||
from bpy.props import (PointerProperty, IntProperty, StringProperty)
|
from bpy.props import (PointerProperty, IntProperty, StringProperty)
|
||||||
|
|
||||||
from .get_blueprints_to_export import get_blueprints_to_export
|
|
||||||
|
|
||||||
from ..constants import TEMPSCENE_PREFIX
|
from ..constants import TEMPSCENE_PREFIX
|
||||||
from .internals import BlueprintsToExport
|
|
||||||
from ..helpers.helpers_scenes import (get_scenes)
|
|
||||||
from .preferences import AutoExportGltfAddonPreferences
|
|
||||||
|
|
||||||
class AutoExportTracker(PropertyGroup):
|
class AutoExportTracker(PropertyGroup):
|
||||||
|
|
||||||
@ -36,8 +31,6 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker)
|
bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker)
|
||||||
# register list of exportable collections
|
|
||||||
bpy.types.WindowManager.exportedCollections = bpy.props.CollectionProperty(type=BlueprintsToExport)
|
|
||||||
|
|
||||||
# setup handlers for updates & saving
|
# setup handlers for updates & saving
|
||||||
#bpy.app.handlers.save_post.append(cls.save_handler)
|
#bpy.app.handlers.save_post.append(cls.save_handler)
|
||||||
@ -53,7 +46,6 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
bpy.app.handlers.save_post.remove(cls.save_handler)
|
bpy.app.handlers.save_post.remove(cls.save_handler)
|
||||||
except:pass"""
|
except:pass"""
|
||||||
del bpy.types.WindowManager.auto_export_tracker
|
del bpy.types.WindowManager.auto_export_tracker
|
||||||
del bpy.types.WindowManager.exportedCollections
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def save_handler(cls, scene, depsgraph):
|
def save_handler(cls, scene, depsgraph):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from ..auto_export.export_gltf import export_gltf
|
from ..auto_export.export_gltf import export_gltf
|
||||||
from .helpers_collections import (set_active_collection)
|
from ...core.helpers_collections import (set_active_collection)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
generates a temporary scene, fills it with data, cleans up after itself
|
generates a temporary scene, fills it with data, cleans up after itself
|
||||||
|
@ -2,26 +2,11 @@ import os
|
|||||||
import bpy
|
import bpy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ..helpers.generate_and_export import generate_and_export
|
from ...core.helpers_collections import (traverse_tree)
|
||||||
from ..helpers.helpers_collections import (traverse_tree)
|
|
||||||
from ..auto_export.export_gltf import (export_gltf, generate_gltf_export_preferences)
|
|
||||||
from ...core.object_makers import make_cube
|
from ...core.object_makers import make_cube
|
||||||
|
from ...materials.materials_helpers import get_all_materials
|
||||||
# get materials per object, and injects the materialInfo component
|
from ..helpers.generate_and_export import generate_and_export
|
||||||
def get_materials(object):
|
from ..auto_export.export_gltf import (generate_gltf_export_preferences)
|
||||||
material_slots = object.material_slots
|
|
||||||
used_materials_names = []
|
|
||||||
#materials_per_object = {}
|
|
||||||
current_project_name = Path(bpy.context.blend_data.filepath).stem
|
|
||||||
|
|
||||||
for m in material_slots:
|
|
||||||
material = m.material
|
|
||||||
# print(" slot", m, "material", material)
|
|
||||||
used_materials_names.append(material.name)
|
|
||||||
# TODO:, also respect slots & export multiple materials if applicable !
|
|
||||||
object['MaterialInfo'] = '(name: "'+material.name+'", source: "'+current_project_name + '")'
|
|
||||||
|
|
||||||
return used_materials_names
|
|
||||||
|
|
||||||
def clear_material_info(collection_names, library_scenes):
|
def clear_material_info(collection_names, library_scenes):
|
||||||
for scene in library_scenes:
|
for scene in library_scenes:
|
||||||
@ -32,21 +17,6 @@ def clear_material_info(collection_names, library_scenes):
|
|||||||
if 'MaterialInfo' in dict(object): # FIXME: hasattr does not work ????
|
if 'MaterialInfo' in dict(object): # FIXME: hasattr does not work ????
|
||||||
del object["MaterialInfo"]
|
del object["MaterialInfo"]
|
||||||
|
|
||||||
|
|
||||||
def get_all_materials(collection_names, library_scenes):
|
|
||||||
#print("collecton", layerColl, "otot", layerColl.all_objects) #all_objects
|
|
||||||
used_material_names = []
|
|
||||||
for scene in library_scenes:
|
|
||||||
root_collection = scene.collection
|
|
||||||
for cur_collection in traverse_tree(root_collection):
|
|
||||||
if cur_collection.name in collection_names:
|
|
||||||
for object in cur_collection.all_objects:
|
|
||||||
used_material_names = used_material_names + get_materials(object)
|
|
||||||
# we only want unique names
|
|
||||||
used_material_names = list(set(used_material_names))
|
|
||||||
return used_material_names
|
|
||||||
|
|
||||||
|
|
||||||
# creates a new object with the applied material, for the material library
|
# creates a new object with the applied material, for the material library
|
||||||
def make_material_object(name, location=[0,0,0], rotation=[0,0,0], scale=[1,1,1], material=None, collection=None):
|
def make_material_object(name, location=[0,0,0], rotation=[0,0,0], scale=[1,1,1], material=None, collection=None):
|
||||||
#original_active_object = bpy.context.active_object
|
#original_active_object = bpy.context.active_object
|
||||||
|
@ -143,92 +143,6 @@ class GLTF_PT_auto_export_change_detection(bpy.types.Panel):
|
|||||||
layout.active = operator.auto_export
|
layout.active = operator.auto_export
|
||||||
layout.prop(operator, "export_change_detection")
|
layout.prop(operator, "export_change_detection")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GLTF_PT_auto_export_scenes(bpy.types.Panel):
|
|
||||||
bl_space_type = 'FILE_BROWSER'
|
|
||||||
bl_region_type = 'TOOL_PROPS'
|
|
||||||
bl_label = "Scenes"
|
|
||||||
bl_parent_id = "GLTF_PT_auto_export_root"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def poll(cls, context):
|
|
||||||
sfile = context.space_data
|
|
||||||
operator = sfile.active_operator
|
|
||||||
|
|
||||||
return operator.bl_idname == "EXPORT_SCENES_OT_auto_gltf" #"EXPORT_SCENE_OT_gltf"
|
|
||||||
|
|
||||||
def draw_header(self, context):
|
|
||||||
layout = self.layout
|
|
||||||
sfile = context.space_data
|
|
||||||
operator = sfile.active_operator
|
|
||||||
#layout.label(text="export scenes")#layout.prop(operator, "export_blueprints", text="")
|
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
layout = self.layout
|
|
||||||
layout.use_property_split = True
|
|
||||||
layout.use_property_decorate = False # No animation.
|
|
||||||
|
|
||||||
sfile = context.space_data
|
|
||||||
operator = sfile.active_operator
|
|
||||||
|
|
||||||
# scene selectors
|
|
||||||
row = layout.row()
|
|
||||||
col = row.column(align=True)
|
|
||||||
col.separator()
|
|
||||||
|
|
||||||
layout.active = operator.auto_export
|
|
||||||
source = operator
|
|
||||||
rows = 2
|
|
||||||
|
|
||||||
# main/level scenes
|
|
||||||
row = layout.row()
|
|
||||||
row.label(text="main scenes")
|
|
||||||
row.prop(context.window_manager, "main_scene", text='')
|
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
row.template_list("SCENE_UL_GLTF_auto_export", "level scenes", source, "main_scenes", source, "main_scenes_index", rows=rows)
|
|
||||||
|
|
||||||
col = row.column(align=True)
|
|
||||||
sub_row = col.row()
|
|
||||||
add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="")
|
|
||||||
add_operator.action = 'ADD'
|
|
||||||
add_operator.scene_type = 'level'
|
|
||||||
#add_operator.source = operator
|
|
||||||
sub_row.enabled = context.window_manager.main_scene is not None
|
|
||||||
|
|
||||||
sub_row = col.row()
|
|
||||||
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="")
|
|
||||||
remove_operator.action = 'REMOVE'
|
|
||||||
remove_operator.scene_type = 'level'
|
|
||||||
col.separator()
|
|
||||||
|
|
||||||
#up_operator = col.operator("scene_list.list_action", icon='TRIA_UP', text="")
|
|
||||||
#up_operator.action = 'UP'
|
|
||||||
#col.operator("scene_list.list_action", icon='TRIA_DOWN', text="").action = 'DOWN'
|
|
||||||
|
|
||||||
# library scenes
|
|
||||||
row = layout.row()
|
|
||||||
row.label(text="library scenes")
|
|
||||||
row.prop(context.window_manager, "library_scene", text='')
|
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
row.template_list("SCENE_UL_GLTF_auto_export", "library scenes", source, "library_scenes", source, "library_scenes_index", rows=rows)
|
|
||||||
|
|
||||||
col = row.column(align=True)
|
|
||||||
sub_row = col.row()
|
|
||||||
add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="")
|
|
||||||
add_operator.action = 'ADD'
|
|
||||||
add_operator.scene_type = 'library'
|
|
||||||
sub_row.enabled = context.window_manager.library_scene is not None
|
|
||||||
|
|
||||||
|
|
||||||
sub_row = col.row()
|
|
||||||
remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="")
|
|
||||||
remove_operator.action = 'REMOVE'
|
|
||||||
remove_operator.scene_type = 'library'
|
|
||||||
col.separator()
|
|
||||||
|
|
||||||
class GLTF_PT_auto_export_blueprints(bpy.types.Panel):
|
class GLTF_PT_auto_export_blueprints(bpy.types.Panel):
|
||||||
bl_space_type = 'FILE_BROWSER'
|
bl_space_type = 'FILE_BROWSER'
|
||||||
bl_region_type = 'TOOL_PROPS'
|
bl_region_type = 'TOOL_PROPS'
|
||||||
@ -268,35 +182,4 @@ class GLTF_PT_auto_export_blueprints(bpy.types.Panel):
|
|||||||
# materials
|
# materials
|
||||||
layout.prop(operator, "export_materials_library")
|
layout.prop(operator, "export_materials_library")
|
||||||
layout.prop(operator, "export_materials_path")
|
layout.prop(operator, "export_materials_path")
|
||||||
|
|
||||||
class SCENE_UL_GLTF_auto_export(bpy.types.UIList):
|
|
||||||
# The draw_item function is called for each item of the collection that is visible in the list.
|
|
||||||
# data is the RNA object containing the collection,
|
|
||||||
# item is the current drawn item of the collection,
|
|
||||||
# icon is the "computed" icon for the item (as an integer, because some objects like materials or textures
|
|
||||||
# have custom icons ID, which are not available as enum items).
|
|
||||||
# active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the
|
|
||||||
# active item of the collection).
|
|
||||||
# active_propname is the name of the active property (use 'getattr(active_data, active_propname)').
|
|
||||||
# index is index of the current item in the collection.
|
|
||||||
# flt_flag is the result of the filtering process for this item.
|
|
||||||
# Note: as index and flt_flag are optional arguments, you do not have to use/declare them here if you don't
|
|
||||||
# need them.
|
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
|
||||||
ob = data
|
|
||||||
# draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code.
|
|
||||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
|
||||||
# You should always start your row layout by a label (icon + text), or a non-embossed text field,
|
|
||||||
# this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
|
|
||||||
# We use icon_value of label, as our given icon is an integer value, not an enum ID.
|
|
||||||
# Note "data" names should never be translated!
|
|
||||||
#if ma:
|
|
||||||
# layout.prop(ma, "name", text="", emboss=False, icon_value=icon)
|
|
||||||
#else:
|
|
||||||
# layout.label(text="", translate=False, icon_value=icon)
|
|
||||||
layout.label(text=item.name, icon_value=icon)
|
|
||||||
#layout.prop(item, "name", text="", emboss=False, icon_value=icon)
|
|
||||||
# 'GRID' layout type should be as compact as possible (typically a single icon!).
|
|
||||||
elif self.layout_type == 'GRID':
|
|
||||||
layout.alignment = 'CENTER'
|
|
||||||
layout.label(text="", icon_value=icon)
|
|
@ -1,181 +0,0 @@
|
|||||||
|
|
||||||
import bpy
|
|
||||||
from bpy.types import Operator
|
|
||||||
|
|
||||||
|
|
||||||
class ASSETS_LIST_OT_actions(Operator):
|
|
||||||
"""Add / remove etc assets"""
|
|
||||||
bl_idname = "asset_list.list_action"
|
|
||||||
bl_label = "Asset Actions"
|
|
||||||
bl_description = "Move items up and down, add and remove"
|
|
||||||
bl_options = {'REGISTER'}
|
|
||||||
|
|
||||||
|
|
||||||
class SCENES_LIST_OT_actions(Operator):
|
|
||||||
"""Move items up and down, add and remove"""
|
|
||||||
bl_idname = "scene_list.list_action"
|
|
||||||
bl_label = "List Actions"
|
|
||||||
bl_description = "Move items up and down, add and remove"
|
|
||||||
bl_options = {'REGISTER'}
|
|
||||||
|
|
||||||
action: bpy.props.EnumProperty(
|
|
||||||
items=(
|
|
||||||
('UP', "Up", ""),
|
|
||||||
('DOWN', "Down", ""),
|
|
||||||
('REMOVE', "Remove", ""),
|
|
||||||
('ADD', "Add", ""))) # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
scene_type: bpy.props.StringProperty()#TODO: replace with enum
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
|
||||||
source = context.active_operator
|
|
||||||
target_name = "library_scenes"
|
|
||||||
target_index = "library_scenes_index"
|
|
||||||
if self.scene_type == "level":
|
|
||||||
target_name = "main_scenes"
|
|
||||||
target_index = "main_scenes_index"
|
|
||||||
|
|
||||||
target = getattr(source, target_name)
|
|
||||||
idx = getattr(source, target_index)
|
|
||||||
current_index = getattr(source, target_index)
|
|
||||||
|
|
||||||
try:
|
|
||||||
item = target[idx]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if self.action == 'DOWN' and idx < len(target) - 1:
|
|
||||||
target.move(idx, idx + 1)
|
|
||||||
setattr(source, target_index, current_index +1 )
|
|
||||||
info = 'Item "%s" moved to position %d' % (item.name, current_index + 1)
|
|
||||||
self.report({'INFO'}, info)
|
|
||||||
|
|
||||||
elif self.action == 'UP' and idx >= 1:
|
|
||||||
target.move(idx, idx - 1)
|
|
||||||
setattr(source, target_index, current_index -1 )
|
|
||||||
info = 'Item "%s" moved to position %d' % (item.name, current_index + 1)
|
|
||||||
self.report({'INFO'}, info)
|
|
||||||
|
|
||||||
elif self.action == 'REMOVE':
|
|
||||||
info = 'Item "%s" removed from list' % (target[idx].name)
|
|
||||||
setattr(source, target_index, current_index -1 )
|
|
||||||
target.remove(idx)
|
|
||||||
self.report({'INFO'}, info)
|
|
||||||
|
|
||||||
if self.action == 'ADD':
|
|
||||||
new_scene_name = None
|
|
||||||
if self.scene_type == "level":
|
|
||||||
if context.window_manager.main_scene:
|
|
||||||
new_scene_name = context.window_manager.main_scene.name
|
|
||||||
else:
|
|
||||||
if context.window_manager.library_scene:
|
|
||||||
new_scene_name = context.window_manager.library_scene.name
|
|
||||||
if new_scene_name:
|
|
||||||
item = target.add()
|
|
||||||
item.name = new_scene_name#f"Rule {idx +1}"
|
|
||||||
|
|
||||||
if self.scene_type == "level":
|
|
||||||
context.window_manager.main_scene = None
|
|
||||||
else:
|
|
||||||
context.window_manager.library_scene = None
|
|
||||||
|
|
||||||
#name = f"Rule {idx +1}"
|
|
||||||
#target.append({"name": name})
|
|
||||||
setattr(source, target_index, len(target) - 1)
|
|
||||||
#source[target_index] = len(target) - 1
|
|
||||||
info = '"%s" added to list' % (item.name)
|
|
||||||
self.report({'INFO'}, info)
|
|
||||||
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
|
||||||
from bpy_extras.io_utils import ImportHelper
|
|
||||||
|
|
||||||
class OT_OpenFolderbrowser(Operator, ImportHelper):
|
|
||||||
"""Browse for registry json file"""
|
|
||||||
bl_idname = "generic.open_folderbrowser"
|
|
||||||
bl_label = "Select folder"
|
|
||||||
|
|
||||||
# Define this to tell 'fileselect_add' that we want a directoy
|
|
||||||
directory: bpy.props.StringProperty(
|
|
||||||
name="Outdir Path",
|
|
||||||
description="selected folder"
|
|
||||||
# subtype='DIR_PATH' is not needed to specify the selection mode.
|
|
||||||
# But this will be anyway a directory path.
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
# Filters folders
|
|
||||||
filter_folder: bpy.props.BoolProperty(
|
|
||||||
default=True,
|
|
||||||
options={"HIDDEN"}
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
target_property: bpy.props.StringProperty(
|
|
||||||
name="target_property",
|
|
||||||
options={'HIDDEN'}
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
"""Do something with the selected file(s)."""
|
|
||||||
operator = context.active_operator
|
|
||||||
new_path = self.directory
|
|
||||||
target_path_name = self.target_property
|
|
||||||
|
|
||||||
# path to the current blend file
|
|
||||||
blend_file_path = bpy.data.filepath
|
|
||||||
# Get the folder
|
|
||||||
blend_file_folder_path = os.path.dirname(blend_file_path)
|
|
||||||
print("blend_file_folder_path", blend_file_folder_path)
|
|
||||||
print("new_path", self.directory, self.target_property, operator)
|
|
||||||
|
|
||||||
asset_path_names = ['export_assets_path', 'export_blueprints_path', 'export_levels_path', 'export_materials_path']
|
|
||||||
export_root_path = operator.export_root_path
|
|
||||||
export_assets_path = operator.export_assets_path
|
|
||||||
#export_root_path_absolute = os.path.join(blend_file_folder_path, export_root_path)
|
|
||||||
export_assets_path_full = os.path.join(blend_file_folder_path, export_root_path, export_assets_path)
|
|
||||||
print("export_assets_path_full", export_assets_path_full)
|
|
||||||
|
|
||||||
#new_root_path = os.path.join(blend_file_folder_path, new_path)
|
|
||||||
if target_path_name == 'export_root_path':
|
|
||||||
new_root_path_relative = os.path.relpath(new_path, blend_file_folder_path)
|
|
||||||
print("changing root new_path to", self.directory, blend_file_folder_path, new_root_path_relative)
|
|
||||||
# we need to change all other relative paths before setting the new absolute path
|
|
||||||
for path_name in asset_path_names:
|
|
||||||
# get current relative path
|
|
||||||
relative_path = getattr(operator, path_name, None)
|
|
||||||
if relative_path is not None:
|
|
||||||
# and now get absolute path of asset_path
|
|
||||||
absolute_path = os.path.join(export_assets_path_full, relative_path)
|
|
||||||
print("absolute path for", path_name, absolute_path)
|
|
||||||
relative_path = os.path.relpath(absolute_path, new_path)
|
|
||||||
setattr(operator, path_name, relative_path)
|
|
||||||
|
|
||||||
# store the root path as relative to the current blend file
|
|
||||||
setattr(operator, target_path_name, new_path)
|
|
||||||
elif target_path_name == 'export_assets_path':
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
relative_path = os.path.relpath(new_path, export_assets_path_full)
|
|
||||||
setattr(operator, target_path_name, relative_path)
|
|
||||||
|
|
||||||
#filename, extension = os.path.splitext(self.filepath)
|
|
||||||
|
|
||||||
|
|
||||||
return {'FINISHED'}
|
|
||||||
|
|
||||||
def draw_folder_browser(layout, label, value, target_property):
|
|
||||||
row = layout.row()
|
|
||||||
row.label(text=label)
|
|
||||||
|
|
||||||
'''box = row.box()
|
|
||||||
box.scale_y = 0.5
|
|
||||||
box.label(text=value)'''
|
|
||||||
|
|
||||||
col = row.column()
|
|
||||||
col.enabled = False
|
|
||||||
col.prop(bpy.context.active_operator, target_property, text="")
|
|
||||||
|
|
||||||
folder_selector = row.operator(OT_OpenFolderbrowser.bl_idname, icon="FILE_FOLDER", text="")
|
|
||||||
folder_selector.target_property = target_property #"export_root_path"
|
|
0
tools/blenvy/materials/__init__.py
Normal file
0
tools/blenvy/materials/__init__.py
Normal file
35
tools/blenvy/materials/materials_helpers.py
Normal file
35
tools/blenvy/materials/materials_helpers.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import os
|
||||||
|
import bpy
|
||||||
|
from pathlib import Path
|
||||||
|
from ..core.helpers_collections import (traverse_tree)
|
||||||
|
|
||||||
|
# get materials per object, and injects the materialInfo component
|
||||||
|
def get_materials(object):
|
||||||
|
material_slots = object.material_slots
|
||||||
|
used_materials_names = []
|
||||||
|
#materials_per_object = {}
|
||||||
|
current_project_name = Path(bpy.context.blend_data.filepath).stem
|
||||||
|
|
||||||
|
for m in material_slots:
|
||||||
|
material = m.material
|
||||||
|
# print(" slot", m, "material", material)
|
||||||
|
used_materials_names.append(material.name)
|
||||||
|
# TODO:, also respect slots & export multiple materials if applicable !
|
||||||
|
# TODO: do NOT modify objects like this !! do it in a different function
|
||||||
|
object['MaterialInfo'] = '(name: "'+material.name+'", source: "'+current_project_name + '")'
|
||||||
|
|
||||||
|
return used_materials_names
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_materials(collection_names, library_scenes):
|
||||||
|
used_material_names = []
|
||||||
|
for scene in library_scenes:
|
||||||
|
root_collection = scene.collection
|
||||||
|
for cur_collection in traverse_tree(root_collection):
|
||||||
|
if cur_collection.name in collection_names:
|
||||||
|
for object in cur_collection.all_objects:
|
||||||
|
used_material_names = used_material_names + get_materials(object)
|
||||||
|
|
||||||
|
# we only want unique names
|
||||||
|
used_material_names = list(set(used_material_names))
|
||||||
|
return used_material_names
|
Loading…
Reference in New Issue
Block a user