diff --git a/README.md b/README.md index 7567c3eaf..65ddb16df 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ [ English / [日本語](#ja_JP) ] -# VRM Add-on for Blender [![CI status](https://github.com/saturday06/VRM-Addon-for-Blender/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/saturday06/VRM-Addon-for-Blender/actions) [![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/saturday06/VRM-Addon-for-Blender?utm_source=badge) +# KHR Character / VRM Add-on for Blender [![CI status](https://github.com/saturday06/VRM-Addon-for-Blender/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/saturday06/VRM-Addon-for-Blender/actions) [![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/saturday06/VRM-Addon-for-Blender?utm_source=badge) -VRM Add-on for Blender is an add-on that adds VRM-related functionality to -Blender. +Import, export, and editing functions for VRM format and experimental KHR +Character format. ## Download @@ -103,9 +103,9 @@ New-Item -ItemType Junction -Path "$Env:APPDATA\Blender Foundation\Blender\$blen [ [English](#en) / 日本語 ] -# VRM Add-on for Blender [![CI status](https://github.com/saturday06/VRM-Addon-for-Blender/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/saturday06/VRM-Addon-for-Blender/actions) [![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/saturday06/VRM-Addon-for-Blender?utm_source=badge) +# KHR Character / VRM Add-on for Blender [![CI status](https://github.com/saturday06/VRM-Addon-for-Blender/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/saturday06/VRM-Addon-for-Blender/actions) [![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/saturday06/VRM-Addon-for-Blender?utm_source=badge) -BlenderにVRM関連機能を追加するアドオンです。 +BlenderにVRM関連機能と実験的なKHR Character関連機能を追加するアドオンです。 ## ダウンロード diff --git a/src/io_scene_vrm/__init__.py b/src/io_scene_vrm/__init__.py index 045e511d8..eeaeab193 100644 --- a/src/io_scene_vrm/__init__.py +++ b/src/io_scene_vrm/__init__.py @@ -6,7 +6,7 @@ from .importer import gltf2_import_user_extension bl_info = { - "name": "VRM format", + "name": "KHR Character / VRM format", "author": "saturday06, iCyP", "version": ( 3, # x-release-please-major @@ -14,7 +14,7 @@ 0, # x-release-please-patch ), "location": "File > Import-Export", - "description": "Import-Edit-Export VRM", + "description": "Import, export, and editing functions for VRM format.", "blender": (2, 93, 0), "warning": "", "support": "COMMUNITY", diff --git a/src/io_scene_vrm/blender_manifest.toml b/src/io_scene_vrm/blender_manifest.toml index 593adbc94..2d44d18b3 100644 --- a/src/io_scene_vrm/blender_manifest.toml +++ b/src/io_scene_vrm/blender_manifest.toml @@ -3,8 +3,8 @@ schema_version = "1.0.0" id = "vrm" version = "3.19.0" -name = "VRM format" -tagline = "VRM import, export and editing capabilities" +name = "KHR Character / VRM format" +tagline = "Import, export, and editing functions for VRM format and experimental KHR Character format." maintainer = "Isamu Mogi " type = "add-on" @@ -23,4 +23,4 @@ copyright = [ ] [permissions] -files = "Import/export VRM from/to disk" +files = "Import/export KHR Character/VRM from/to disk" diff --git a/src/io_scene_vrm/common/ops/vrm.py b/src/io_scene_vrm/common/ops/vrm.py index cd54abb13..3e65b22a6 100644 --- a/src/io_scene_vrm/common/ops/vrm.py +++ b/src/io_scene_vrm/common/ops/vrm.py @@ -7,6 +7,192 @@ import bpy +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def add_khr_xmp_json_ld_packet_dc_creator( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", +) -> set[str]: + return bpy.ops.vrm.add_khr_xmp_json_ld_packet_dc_creator( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def remove_khr_xmp_json_ld_packet_dc_creator( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_creator_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.remove_khr_xmp_json_ld_packet_dc_creator( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_creator_index=dc_creator_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def move_up_khr_xmp_json_ld_packet_dc_creator( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_creator_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.move_up_khr_xmp_json_ld_packet_dc_creator( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_creator_index=dc_creator_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def move_down_khr_xmp_json_ld_packet_dc_creator( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_creator_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.move_down_khr_xmp_json_ld_packet_dc_creator( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_creator_index=dc_creator_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def add_khr_xmp_json_ld_packet_dc_license( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", +) -> set[str]: + return bpy.ops.vrm.add_khr_xmp_json_ld_packet_dc_license( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def remove_khr_xmp_json_ld_packet_dc_license( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_license_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.remove_khr_xmp_json_ld_packet_dc_license( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_license_index=dc_license_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def move_up_khr_xmp_json_ld_packet_dc_license( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_license_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.move_up_khr_xmp_json_ld_packet_dc_license( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_license_index=dc_license_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def move_down_khr_xmp_json_ld_packet_dc_license( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_license_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.move_down_khr_xmp_json_ld_packet_dc_license( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_license_index=dc_license_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def add_khr_xmp_json_ld_packet_dc_subject( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", +) -> set[str]: + return bpy.ops.vrm.add_khr_xmp_json_ld_packet_dc_subject( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def remove_khr_xmp_json_ld_packet_dc_subject( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_subject_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.remove_khr_xmp_json_ld_packet_dc_subject( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_subject_index=dc_subject_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def move_up_khr_xmp_json_ld_packet_dc_subject( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_subject_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.move_up_khr_xmp_json_ld_packet_dc_subject( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_subject_index=dc_subject_index, + ) + + +# This code is auto generated. +# To regenerate, run the `uv run tools/property_typing.py` command. +def move_down_khr_xmp_json_ld_packet_dc_subject( + execution_context: str = "EXEC_DEFAULT", + /, + *, + armature_object_name: str = "", + dc_subject_index: int = 0, +) -> set[str]: + return bpy.ops.vrm.move_down_khr_xmp_json_ld_packet_dc_subject( # type: ignore[attr-defined, no-any-return] + execution_context, + armature_object_name=armature_object_name, + dc_subject_index=dc_subject_index, + ) + + # This code is auto generated. # To regenerate, run the `uv run tools/property_typing.py` command. def add_vrm0_first_person_mesh_annotation( diff --git a/src/io_scene_vrm/editor/extension.py b/src/io_scene_vrm/editor/extension.py index ede4675b4..0ecf048e2 100644 --- a/src/io_scene_vrm/editor/extension.py +++ b/src/io_scene_vrm/editor/extension.py @@ -3,6 +3,7 @@ from collections.abc import Sequence from typing import TYPE_CHECKING, Optional, TypeVar +import bpy from bpy.props import ( CollectionProperty, EnumProperty, @@ -24,6 +25,7 @@ from ..common.logger import get_logger from ..common.preferences import VrmAddonPreferences +from .khr_character.property_group import KhrCharacterPropertyGroup from .mtoon1.property_group import Mtoon1MaterialPropertyGroup from .node_constraint1.property_group import NodeConstraint1NodeConstraintPropertyGroup from .property_group import StringPropertyGroup, property_group_enum @@ -351,11 +353,29 @@ class VrmAddonArmatureExtensionPropertyGroup(PropertyGroup): type=NodeConstraint1NodeConstraintPropertyGroup ) + khr_character: PointerProperty( # type: ignore[valid-type] + type=KhrCharacterPropertyGroup + ) + SPEC_VERSION_VRM0 = "0.0" SPEC_VERSION_VRM1 = "1.0" + SPEC_VERSION_KHR_CHARACTER = "KHR_character" spec_version_items = ( (SPEC_VERSION_VRM0, "VRM 0.0", "", "NONE", 0), (SPEC_VERSION_VRM1, "VRM 1.0", "", "NONE", 1), + *( + [ + ( + SPEC_VERSION_KHR_CHARACTER, + "KHR Character (Experimental)", + "", + "EXPERIMENTAL", + 2, + ) + ] + if bpy.app.version >= (4, 5) + else [] + ), ) def update_spec_version(self, context: Context) -> None: @@ -403,6 +423,9 @@ def is_vrm0(self) -> bool: def is_vrm1(self) -> bool: return str(self.spec_version) == self.SPEC_VERSION_VRM1 + def is_khr_character(self) -> bool: + return str(self.spec_version) == self.SPEC_VERSION_KHR_CHARACTER + @staticmethod def has_vrm_model_metadata(obj: Object) -> bool: if obj.type != "ARMATURE": @@ -434,6 +457,7 @@ def has_vrm_model_metadata(obj: Object) -> bool: node_constraint1: ( # type: ignore[no-redef] NodeConstraint1NodeConstraintPropertyGroup ) + khr_character: KhrCharacterPropertyGroup # type: ignore[no-redef] spec_version: str # type: ignore[no-redef] diff --git a/src/io_scene_vrm/editor/khr_character/__init__.py b/src/io_scene_vrm/editor/khr_character/__init__.py new file mode 100644 index 000000000..3822ea345 --- /dev/null +++ b/src/io_scene_vrm/editor/khr_character/__init__.py @@ -0,0 +1 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later diff --git a/src/io_scene_vrm/editor/khr_character/panel.py b/src/io_scene_vrm/editor/khr_character/panel.py new file mode 100644 index 000000000..fedaecbf8 --- /dev/null +++ b/src/io_scene_vrm/editor/khr_character/panel.py @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later + + +from collections.abc import Set as AbstractSet + +from bpy.types import Armature, Context, Panel + +from ..extension import get_armature_extension +from ..khr_xmp_json_ld.panel import draw_khr_xmp_json_ld_packet_layout +from ..panel import VRM_PT_vrm_armature_object_property +from ..search import active_object_is_armature + + +class VRM_PT_vrm0_humanoid_armature_object_property(Panel): + bl_idname = "VRM_PT_vrm0_humanoid_armature_object_property" + bl_label = "VRM 0.x Humanoid" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} + bl_parent_id = VRM_PT_vrm_armature_object_property.bl_idname + + @classmethod + def poll(cls, context: Context) -> bool: + return active_object_is_armature(context) + + def draw_header(self, _context: Context) -> None: + self.layout.label(icon="ARMATURE_DATA") + + def draw(self, context: Context) -> None: + active_object = context.active_object + if not active_object: + return + armature_data = active_object.data + if not isinstance(armature_data, Armature): + return + draw_khr_xmp_json_ld_packet_layout( + active_object, + context, + self.layout, + get_armature_extension(armature_data).khr_character.khr_xmp_json_ld_packet, + ) diff --git a/src/io_scene_vrm/editor/khr_character/property_group.py b/src/io_scene_vrm/editor/khr_character/property_group.py new file mode 100644 index 000000000..12f34c3ab --- /dev/null +++ b/src/io_scene_vrm/editor/khr_character/property_group.py @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later + +from typing import TYPE_CHECKING + +from bpy.props import ( + PointerProperty, +) +from bpy.types import ( + Armature, + PropertyGroup, +) + +from ...common.logger import get_logger +from ..khr_xmp_json_ld.property_group import KhrXmpJsonLdKhrCharacterPacketPropertyGroup + +logger = get_logger(__name__) + + +# https://github.com/Kjakubzak/glTF/blob/4a1f58a84aa5f9934b749779b89678727d3d2a5c/extensions/2.0/Khronos/KHR_character/README.md +class KhrCharacterPropertyGroup(PropertyGroup): + khr_xmp_json_ld_packet: PointerProperty( # type: ignore[valid-type] + type=KhrXmpJsonLdKhrCharacterPacketPropertyGroup + ) + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + khr_xmp_json_ld_packet: ( # type: ignore[no-redef] + KhrXmpJsonLdKhrCharacterPacketPropertyGroup + ) + + +def get_armature_extension(armature: Armature) -> KhrCharacterPropertyGroup: + from ..extension import get_armature_extension + + khr_character = get_armature_extension(armature).khr_character + return khr_character diff --git a/src/io_scene_vrm/editor/khr_xmp_json_ld/__init__.py b/src/io_scene_vrm/editor/khr_xmp_json_ld/__init__.py new file mode 100644 index 000000000..3822ea345 --- /dev/null +++ b/src/io_scene_vrm/editor/khr_xmp_json_ld/__init__.py @@ -0,0 +1 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later diff --git a/src/io_scene_vrm/editor/khr_xmp_json_ld/ops.py b/src/io_scene_vrm/editor/khr_xmp_json_ld/ops.py new file mode 100644 index 000000000..8cb8987df --- /dev/null +++ b/src/io_scene_vrm/editor/khr_xmp_json_ld/ops.py @@ -0,0 +1,465 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later +from collections.abc import Set as AbstractSet +from typing import TYPE_CHECKING + +from bpy.props import IntProperty, StringProperty +from bpy.types import ( + Armature, + Context, + Operator, +) + +from ...common.logger import get_logger +from ..extension import get_armature_extension + +logger = get_logger(__name__) + + +class VRM_OT_add_khr_xmp_json_ld_packet_dc_creator(Operator): + bl_idname = "vrm.add_khr_xmp_json_ld_packet_dc_creator" + bl_label = "Add Creator" + bl_description = "Add Creator" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + dc_creator = packet.dc_creator.add() + dc_creator.value = "" + packet.active_dc_creator_index = len(packet.dc_creator) - 1 + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + + +class VRM_OT_remove_khr_xmp_json_ld_packet_dc_creator(Operator): + bl_idname = "vrm.remove_khr_xmp_json_ld_packet_dc_creator" + bl_label = "Remove Creator" + bl_description = "Remove Creator" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_creator_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_creator) <= self.dc_creator_index: + return {"CANCELLED"} + packet.dc_creator.remove(self.dc_creator_index) + packet.active_dc_creator_index = min( + packet.active_dc_creator_index, + max(0, len(packet.dc_creator) - 1), + ) + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_creator_index: int # type: ignore[no-redef] + + +class VRM_OT_move_up_khr_xmp_json_ld_packet_dc_creator(Operator): + bl_idname = "vrm.move_up_khr_xmp_json_ld_packet_dc_creator" + bl_label = "Move Up Creator" + bl_description = "Move Up Creator" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_creator_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_creator) <= self.dc_creator_index: + return {"CANCELLED"} + new_index = (self.dc_creator_index - 1) % len(packet.dc_creator) + packet.dc_creator.move(self.dc_creator_index, new_index) + packet.active_dc_creator_index = new_index + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_creator_index: int # type: ignore[no-redef] + + +class VRM_OT_move_down_khr_xmp_json_ld_packet_dc_creator(Operator): + bl_idname = "vrm.move_down_khr_xmp_json_ld_packet_dc_creator" + bl_label = "Move Down Creator" + bl_description = "Move Down Creator" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_creator_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_creator) <= self.dc_creator_index: + return {"CANCELLED"} + new_index = (self.dc_creator_index + 1) % len(packet.dc_creator) + packet.dc_creator.move(self.dc_creator_index, new_index) + packet.active_dc_creator_index = new_index + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_creator_index: int # type: ignore[no-redef] + + +class VRM_OT_add_khr_xmp_json_ld_packet_dc_license(Operator): + bl_idname = "vrm.add_khr_xmp_json_ld_packet_dc_license" + bl_label = "Add License" + bl_description = "Add License" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + dc_license = packet.dc_license.add() + dc_license.value = "" + packet.active_dc_license_index = len(packet.dc_license) - 1 + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + + +class VRM_OT_remove_khr_xmp_json_ld_packet_dc_license(Operator): + bl_idname = "vrm.remove_khr_xmp_json_ld_packet_dc_license" + bl_label = "Remove License" + bl_description = "Remove License" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_license_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_license) <= self.dc_license_index: + return {"CANCELLED"} + packet.dc_license.remove(self.dc_license_index) + packet.active_dc_license_index = min( + packet.active_dc_license_index, + max(0, len(packet.dc_license) - 1), + ) + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_license_index: int # type: ignore[no-redef] + + +class VRM_OT_move_up_khr_xmp_json_ld_packet_dc_license(Operator): + bl_idname = "vrm.move_up_khr_xmp_json_ld_packet_dc_license" + bl_label = "Move Up License" + bl_description = "Move Up License" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_license_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_license) <= self.dc_license_index: + return {"CANCELLED"} + new_index = (self.dc_license_index - 1) % len(packet.dc_license) + packet.dc_license.move(self.dc_license_index, new_index) + packet.active_dc_license_index = new_index + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_license_index: int # type: ignore[no-redef] + + +class VRM_OT_move_down_khr_xmp_json_ld_packet_dc_license(Operator): + bl_idname = "vrm.move_down_khr_xmp_json_ld_packet_dc_license" + bl_label = "Move Down License" + bl_description = "Move Down License" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_license_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_license) <= self.dc_license_index: + return {"CANCELLED"} + new_index = (self.dc_license_index + 1) % len(packet.dc_license) + packet.dc_license.move(self.dc_license_index, new_index) + packet.active_dc_license_index = new_index + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_license_index: int # type: ignore[no-redef] + + +class VRM_OT_add_khr_xmp_json_ld_packet_dc_subject(Operator): + bl_idname = "vrm.add_khr_xmp_json_ld_packet_dc_subject" + bl_label = "Add Subject" + bl_description = "Add Subject" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + dc_subject = packet.dc_subject.add() + dc_subject.value = "" + packet.active_dc_subject_index = len(packet.dc_subject) - 1 + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + + +class VRM_OT_remove_khr_xmp_json_ld_packet_dc_subject(Operator): + bl_idname = "vrm.remove_khr_xmp_json_ld_packet_dc_subject" + bl_label = "Remove Subject" + bl_description = "Remove Subject" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_subject_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_subject) <= self.dc_subject_index: + return {"CANCELLED"} + packet.dc_subject.remove(self.dc_subject_index) + packet.active_dc_subject_index = min( + packet.active_dc_subject_index, + max(0, len(packet.dc_subject) - 1), + ) + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_subject_index: int # type: ignore[no-redef] + + +class VRM_OT_move_up_khr_xmp_json_ld_packet_dc_subject(Operator): + bl_idname = "vrm.move_up_khr_xmp_json_ld_packet_dc_subject" + bl_label = "Move Up Subject" + bl_description = "Move Up Subject" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_subject_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_subject) <= self.dc_subject_index: + return {"CANCELLED"} + new_index = (self.dc_subject_index - 1) % len(packet.dc_subject) + packet.dc_subject.move(self.dc_subject_index, new_index) + packet.active_dc_subject_index = new_index + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_subject_index: int # type: ignore[no-redef] + + +class VRM_OT_move_down_khr_xmp_json_ld_packet_dc_subject(Operator): + bl_idname = "vrm.move_down_khr_xmp_json_ld_packet_dc_subject" + bl_label = "Move Down Subject" + bl_description = "Move Down Subject" + bl_options: AbstractSet[str] = {"REGISTER", "UNDO"} + + armature_object_name: StringProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + ) + + dc_subject_index: IntProperty( # type: ignore[valid-type] + options={"HIDDEN"}, + min=0, + ) + + def execute(self, context: Context) -> set[str]: + armature = context.blend_data.objects.get(self.armature_object_name) + if armature is None or armature.type != "ARMATURE": + return {"CANCELLED"} + armature_data = armature.data + if not isinstance(armature_data, Armature): + return {"CANCELLED"} + packet = get_armature_extension( + armature_data + ).khr_character.khr_xmp_json_ld_packet + if len(packet.dc_subject) <= self.dc_subject_index: + return {"CANCELLED"} + new_index = (self.dc_subject_index + 1) % len(packet.dc_subject) + packet.dc_subject.move(self.dc_subject_index, new_index) + packet.active_dc_subject_index = new_index + return {"FINISHED"} + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + armature_object_name: str # type: ignore[no-redef] + dc_subject_index: int # type: ignore[no-redef] diff --git a/src/io_scene_vrm/editor/khr_xmp_json_ld/panel.py b/src/io_scene_vrm/editor/khr_xmp_json_ld/panel.py new file mode 100644 index 000000000..46b871ff9 --- /dev/null +++ b/src/io_scene_vrm/editor/khr_xmp_json_ld/panel.py @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later + +from bpy.types import Context, Object, UILayout + +from ...common.logger import get_logger +from ..migration import defer_migrate +from ..panel import draw_template_list +from .ops import ( + VRM_OT_add_khr_xmp_json_ld_packet_dc_creator, + VRM_OT_add_khr_xmp_json_ld_packet_dc_license, + VRM_OT_add_khr_xmp_json_ld_packet_dc_subject, + VRM_OT_move_down_khr_xmp_json_ld_packet_dc_creator, + VRM_OT_move_down_khr_xmp_json_ld_packet_dc_license, + VRM_OT_move_down_khr_xmp_json_ld_packet_dc_subject, + VRM_OT_move_up_khr_xmp_json_ld_packet_dc_creator, + VRM_OT_move_up_khr_xmp_json_ld_packet_dc_license, + VRM_OT_move_up_khr_xmp_json_ld_packet_dc_subject, + VRM_OT_remove_khr_xmp_json_ld_packet_dc_creator, + VRM_OT_remove_khr_xmp_json_ld_packet_dc_license, + VRM_OT_remove_khr_xmp_json_ld_packet_dc_subject, +) +from .property_group import ( + KhrXmpJsonLdKhrCharacterPacketPropertyGroup, +) +from .ui_list import ( + VRM_UL_khr_xmp_json_ld_packet_dc_creator, + VRM_UL_khr_xmp_json_ld_packet_dc_license, + VRM_UL_khr_xmp_json_ld_packet_dc_subject, +) + +logger = get_logger(__name__) + + +def draw_khr_xmp_json_ld_packet_layout( + armature: Object, + _context: Context, + layout: UILayout, + packet: KhrXmpJsonLdKhrCharacterPacketPropertyGroup, +) -> None: + defer_migrate(armature.name) + + thumbnail_image_column = layout.column() + thumbnail_image_column.label(text="Thumbnail Image:") + thumbnail_image_column.template_ID_preview(packet, "khr_thumbnail_image") + + layout.prop(packet, "dc_title", icon="FILE_BLEND") + + dc_creator_column = layout.column() + dc_creator_column.label(text="Creator:") + ( + dc_creator_collection_ops, + dc_creator_collection_item_ops, + dc_creator_index, + _, + _, + ) = draw_template_list( + dc_creator_column, + VRM_UL_khr_xmp_json_ld_packet_dc_creator, + packet, + "dc_creator", + "active_dc_creator_index", + VRM_OT_add_khr_xmp_json_ld_packet_dc_creator, + VRM_OT_remove_khr_xmp_json_ld_packet_dc_creator, + VRM_OT_move_up_khr_xmp_json_ld_packet_dc_creator, + VRM_OT_move_down_khr_xmp_json_ld_packet_dc_creator, + can_remove=lambda _: len(packet.dc_creator) >= 2, + compact=True, + ) + for dc_creator_collection_op in dc_creator_collection_ops: + dc_creator_collection_op.armature_object_name = armature.name + + for dc_creator_collection_item_op in dc_creator_collection_item_ops: + dc_creator_collection_item_op.dc_creator_index = dc_creator_index + + dc_license_column = layout.column() + dc_license_column.label(text="License:") + ( + dc_license_collection_ops, + dc_license_collection_item_ops, + dc_license_index, + _, + _, + ) = draw_template_list( + dc_license_column, + VRM_UL_khr_xmp_json_ld_packet_dc_license, + packet, + "dc_license", + "active_dc_license_index", + VRM_OT_add_khr_xmp_json_ld_packet_dc_license, + VRM_OT_remove_khr_xmp_json_ld_packet_dc_license, + VRM_OT_move_up_khr_xmp_json_ld_packet_dc_license, + VRM_OT_move_down_khr_xmp_json_ld_packet_dc_license, + can_remove=lambda _: len(packet.dc_license) >= 2, + compact=True, + ) + for dc_license_collection_op in dc_license_collection_ops: + dc_license_collection_op.armature_object_name = armature.name + + for dc_license_collection_item_op in dc_license_collection_item_ops: + dc_license_collection_item_op.dc_license_index = dc_license_index + + layout.prop(packet, "dc_created", icon="FILE_BLEND") + layout.prop(packet, "dc_rights", icon="FILE_BLEND") + layout.prop(packet, "dc_publisher", icon="FILE_BLEND") + layout.prop(packet, "dc_description", icon="FILE_BLEND") + + dc_subject_column = layout.column() + dc_subject_column.label(text="Subject:") + ( + dc_subject_collection_ops, + dc_subject_collection_item_ops, + dc_subject_index, + _, + _, + ) = draw_template_list( + dc_subject_column, + VRM_UL_khr_xmp_json_ld_packet_dc_subject, + packet, + "dc_subject", + "active_dc_subject_index", + VRM_OT_add_khr_xmp_json_ld_packet_dc_subject, + VRM_OT_remove_khr_xmp_json_ld_packet_dc_subject, + VRM_OT_move_up_khr_xmp_json_ld_packet_dc_subject, + VRM_OT_move_down_khr_xmp_json_ld_packet_dc_subject, + can_remove=lambda _: len(packet.dc_subject) >= 2, + compact=True, + ) + for dc_subject_collection_op in dc_subject_collection_ops: + dc_subject_collection_op.armature_object_name = armature.name + + for dc_subject_collection_item_op in dc_subject_collection_item_ops: + dc_subject_collection_item_op.dc_subject_index = dc_subject_index + + layout.prop(packet, "dc_source", icon="FILE_BLEND") + layout.prop(packet, "khr_version", icon="FILE_BLEND") diff --git a/src/io_scene_vrm/editor/khr_xmp_json_ld/property_group.py b/src/io_scene_vrm/editor/khr_xmp_json_ld/property_group.py new file mode 100644 index 000000000..2bf2d9d33 --- /dev/null +++ b/src/io_scene_vrm/editor/khr_xmp_json_ld/property_group.py @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later +from typing import TYPE_CHECKING, Optional + +from bpy.props import ( + CollectionProperty, + IntProperty, + PointerProperty, + StringProperty, +) +from bpy.types import ( + Image, + PropertyGroup, +) + +from ..property_group import StringPropertyGroup + +if TYPE_CHECKING: + from ..property_group import CollectionPropertyProtocol + + +class KhrXmpJsonLdKhrCharacterPacketPropertyGroup(PropertyGroup): + dc_title: StringProperty( # type: ignore[valid-type] + name="Title" + ) + dc_creator: CollectionProperty( # type: ignore[valid-type] + type=StringPropertyGroup + ) + dc_license: CollectionProperty( # type: ignore[valid-type] + type=StringPropertyGroup + ) + dc_created: StringProperty( # type: ignore[valid-type] + name="Created Date" + ) + dc_rights: StringProperty( # type: ignore[valid-type] + name="Rights" + ) + dc_publisher: StringProperty( # type: ignore[valid-type] + name="Publisher" + ) + dc_description: StringProperty( # type: ignore[valid-type] + name="Description" + ) + dc_subject: CollectionProperty( # type: ignore[valid-type] + type=StringPropertyGroup + ) + dc_source: StringProperty( # type: ignore[valid-type] + name="Source" + ) + khr_version: StringProperty( # type: ignore[valid-type] + name="Version" + ) + khr_thumbnail_image: PointerProperty( # type: ignore[valid-type] + type=Image + ) + + # for UI + active_dc_creator_index: IntProperty(min=0) # type: ignore[valid-type] + active_dc_license_index: IntProperty(min=0) # type: ignore[valid-type] + active_dc_subject_index: IntProperty(min=0) # type: ignore[valid-type] + + if TYPE_CHECKING: + # This code is auto generated. + # To regenerate, run the `uv run tools/property_typing.py` command. + dc_title: str # type: ignore[no-redef] + dc_creator: CollectionPropertyProtocol[ # type: ignore[no-redef] + StringPropertyGroup + ] + dc_license: CollectionPropertyProtocol[ # type: ignore[no-redef] + StringPropertyGroup + ] + dc_created: str # type: ignore[no-redef] + dc_rights: str # type: ignore[no-redef] + dc_publisher: str # type: ignore[no-redef] + dc_description: str # type: ignore[no-redef] + dc_subject: CollectionPropertyProtocol[ # type: ignore[no-redef] + StringPropertyGroup + ] + dc_source: str # type: ignore[no-redef] + khr_version: str # type: ignore[no-redef] + khr_thumbnail_image: Optional[Image] # type: ignore[no-redef] + active_dc_creator_index: int # type: ignore[no-redef] + active_dc_license_index: int # type: ignore[no-redef] + active_dc_subject_index: int # type: ignore[no-redef] diff --git a/src/io_scene_vrm/editor/khr_xmp_json_ld/ui_list.py b/src/io_scene_vrm/editor/khr_xmp_json_ld/ui_list.py new file mode 100644 index 000000000..53d210e16 --- /dev/null +++ b/src/io_scene_vrm/editor/khr_xmp_json_ld/ui_list.py @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: MIT OR GPL-3.0-or-later +from bpy.types import Context, UILayout, UIList + +from ...common.logger import get_logger +from ..property_group import StringPropertyGroup +from .property_group import KhrXmpJsonLdKhrCharacterPacketPropertyGroup + +logger = get_logger(__name__) + + +class VRM_UL_khr_xmp_json_ld_packet_dc_creator(UIList): + bl_idname = "VRM_UL_khr_xmp_json_ld_packet_dc_creator" + + def draw_item( + self, + _context: Context, + layout: UILayout, + packet: object, + dc_creator_item: object, + _icon: int, + _active_data: object, + _active_prop_name: str, + index: int, + _flt_flag: int, + ) -> None: + if not isinstance(packet, KhrXmpJsonLdKhrCharacterPacketPropertyGroup): + return + if not isinstance(dc_creator_item, StringPropertyGroup): + return + + icon = "USER" + + if self.layout_type == "GRID": + layout.alignment = "CENTER" + layout.label(text="", translate=False, icon=icon) + return + + if self.layout_type not in {"DEFAULT", "COMPACT"}: + return + + if index == packet.active_dc_creator_index: + layout.prop(dc_creator_item, "value", icon=icon, text="", translate=False) + else: + layout.label(text=dc_creator_item.value, icon=icon, translate=False) + + +class VRM_UL_khr_xmp_json_ld_packet_dc_license(UIList): + bl_idname = "VRM_UL_khr_xmp_json_ld_packet_dc_license" + + def draw_item( + self, + _context: Context, + layout: UILayout, + packet: object, + dc_license_item: object, + _icon: int, + _active_data: object, + _active_prop_name: str, + index: int, + _flt_flag: int, + ) -> None: + if not isinstance(packet, KhrXmpJsonLdKhrCharacterPacketPropertyGroup): + return + if not isinstance(dc_license_item, StringPropertyGroup): + return + + icon = "USER" + + if self.layout_type == "GRID": + layout.alignment = "CENTER" + layout.label(text="", translate=False, icon=icon) + return + + if self.layout_type not in {"DEFAULT", "COMPACT"}: + return + + if index == packet.active_dc_license_index: + layout.prop(dc_license_item, "value", icon=icon, text="", translate=False) + else: + layout.label(text=dc_license_item.value, icon=icon, translate=False) + + +class VRM_UL_khr_xmp_json_ld_packet_dc_subject(UIList): + bl_idname = "VRM_UL_khr_xmp_json_ld_packet_dc_subject" + + def draw_item( + self, + _context: Context, + layout: UILayout, + packet: object, + dc_subject_item: object, + _icon: int, + _active_data: object, + _active_prop_name: str, + index: int, + _flt_flag: int, + ) -> None: + if not isinstance(packet, KhrXmpJsonLdKhrCharacterPacketPropertyGroup): + return + if not isinstance(dc_subject_item, StringPropertyGroup): + return + + icon = "USER" + + if self.layout_type == "GRID": + layout.alignment = "CENTER" + layout.label(text="", translate=False, icon=icon) + return + + if self.layout_type not in {"DEFAULT", "COMPACT"}: + return + + if index == packet.active_dc_subject_index: + layout.prop(dc_subject_item, "value", icon=icon, text="", translate=False) + else: + layout.label(text=dc_subject_item.value, icon=icon, translate=False) diff --git a/src/io_scene_vrm/editor/node_constraint1/panel.py b/src/io_scene_vrm/editor/node_constraint1/panel.py index 2f1b8d6ff..1e5061c19 100644 --- a/src/io_scene_vrm/editor/node_constraint1/panel.py +++ b/src/io_scene_vrm/editor/node_constraint1/panel.py @@ -291,7 +291,7 @@ class VRM_PT_node_constraint1_ui(Panel): bl_translation_context = "VRM" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod diff --git a/src/io_scene_vrm/editor/panel.py b/src/io_scene_vrm/editor/panel.py index 0aa032602..6f9916ea8 100644 --- a/src/io_scene_vrm/editor/panel.py +++ b/src/io_scene_vrm/editor/panel.py @@ -206,7 +206,7 @@ class VRM_PT_current_selected_armature(Panel): bl_label = "Current selected armature" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"HIDE_HEADER"} @classmethod @@ -226,7 +226,7 @@ class VRM_PT_controller(Panel): bl_label = "Operator" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" def draw_header(self, _context: Context) -> None: self.layout.label(icon="TOOL_SETTINGS") @@ -270,7 +270,7 @@ class VRM_PT_controller_unsupported_blender_version_warning(Panel): bl_label = "Unsupported Blender Version Warning" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"HIDE_HEADER"} @classmethod diff --git a/src/io_scene_vrm/editor/search.py b/src/io_scene_vrm/editor/search.py index 241e51d06..756c57c67 100644 --- a/src/io_scene_vrm/editor/search.py +++ b/src/io_scene_vrm/editor/search.py @@ -719,3 +719,15 @@ def active_object_is_vrm0_armature(context: Context) -> bool: if not isinstance(armature_data, Armature): return False return get_armature_extension(armature_data).is_vrm0() + + +def active_object_is_armature(context: Context) -> bool: + active_object = context.active_object + if not active_object: + return False + if active_object.type != "ARMATURE": + return False + armature_data = active_object.data + if not isinstance(armature_data, Armature): + return False + return get_armature_extension(armature_data).is_khr_character() diff --git a/src/io_scene_vrm/editor/spring_bone1/panel.py b/src/io_scene_vrm/editor/spring_bone1/panel.py index 0b123e9f3..eff8c87a1 100644 --- a/src/io_scene_vrm/editor/spring_bone1/panel.py +++ b/src/io_scene_vrm/editor/spring_bone1/panel.py @@ -486,7 +486,7 @@ class VRM_PT_spring_bone1_ui(Panel): bl_translation_context = "VRM" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod diff --git a/src/io_scene_vrm/editor/vrm0/panel.py b/src/io_scene_vrm/editor/vrm0/panel.py index 64c1bb222..0371e6aaf 100644 --- a/src/io_scene_vrm/editor/vrm0/panel.py +++ b/src/io_scene_vrm/editor/vrm0/panel.py @@ -448,7 +448,7 @@ class VRM_PT_vrm0_humanoid_ui(Panel): bl_label = "VRM 0.x Humanoid" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -572,7 +572,7 @@ class VRM_PT_vrm0_first_person_ui(Panel): bl_label = "VRM 0.x First Person" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -848,7 +848,7 @@ class VRM_PT_vrm0_blend_shape_master_ui(Panel): bl_label = "VRM 0.x Blend Shape Proxy" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -1130,7 +1130,7 @@ class VRM_PT_vrm0_secondary_animation_ui(Panel): bl_label = "VRM 0.x Spring Bone" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -1221,7 +1221,7 @@ class VRM_PT_vrm0_meta_ui(Panel): bl_label = "VRM 0.x Meta" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod diff --git a/src/io_scene_vrm/editor/vrm1/panel.py b/src/io_scene_vrm/editor/vrm1/panel.py index f9c3de9b7..63c59e64f 100644 --- a/src/io_scene_vrm/editor/vrm1/panel.py +++ b/src/io_scene_vrm/editor/vrm1/panel.py @@ -419,7 +419,7 @@ class VRM_PT_vrm1_humanoid_ui(Panel): bl_translation_context = "VRM" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -519,7 +519,7 @@ class VRM_PT_vrm1_first_person_ui(Panel): bl_translation_context = "VRM" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -626,7 +626,7 @@ class VRM_PT_vrm1_look_at_ui(Panel): bl_translation_context = "VRM" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -1012,7 +1012,7 @@ class VRM_PT_vrm1_expressions_ui(Panel): bl_translation_context = "VRM" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod @@ -1162,7 +1162,7 @@ class VRM_PT_vrm1_meta_ui(Panel): bl_translation_context = "VRM" bl_space_type = "VIEW_3D" bl_region_type = "UI" - bl_category = "VRM" + bl_category = "KHR Character / VRM" bl_options: AbstractSet[str] = {"DEFAULT_CLOSED"} @classmethod diff --git a/src/io_scene_vrm/registration.py b/src/io_scene_vrm/registration.py index 6b41fa0e7..882265c32 100644 --- a/src/io_scene_vrm/registration.py +++ b/src/io_scene_vrm/registration.py @@ -52,6 +52,10 @@ subscription, validation, ) +from .editor.khr_character import property_group as khr_character_property_group +from .editor.khr_xmp_json_ld import ops as khr_xmp_json_ld_ops +from .editor.khr_xmp_json_ld import property_group as khr_xmp_json_ld_property_group +from .editor.khr_xmp_json_ld import ui_list as khr_xmp_json_ld_ui_list from .editor.mtoon1 import handler as mtoon1_handler from .editor.mtoon1 import ops as mtoon1_ops from .editor.mtoon1 import panel as mtoon1_panel @@ -214,6 +218,23 @@ mtoon1_property_group.Mtoon0ReceiveShadowTexturePropertyGroup, mtoon1_property_group.Mtoon1MaterialPropertyGroup, mtoon1_property_group.MaterialTraceablePropertyGroup, + khr_xmp_json_ld_ops.VRM_OT_add_khr_xmp_json_ld_packet_dc_creator, + khr_xmp_json_ld_ops.VRM_OT_remove_khr_xmp_json_ld_packet_dc_creator, + khr_xmp_json_ld_ops.VRM_OT_move_up_khr_xmp_json_ld_packet_dc_creator, + khr_xmp_json_ld_ops.VRM_OT_move_down_khr_xmp_json_ld_packet_dc_creator, + khr_xmp_json_ld_ops.VRM_OT_add_khr_xmp_json_ld_packet_dc_license, + khr_xmp_json_ld_ops.VRM_OT_remove_khr_xmp_json_ld_packet_dc_license, + khr_xmp_json_ld_ops.VRM_OT_move_up_khr_xmp_json_ld_packet_dc_license, + khr_xmp_json_ld_ops.VRM_OT_move_down_khr_xmp_json_ld_packet_dc_license, + khr_xmp_json_ld_ops.VRM_OT_add_khr_xmp_json_ld_packet_dc_subject, + khr_xmp_json_ld_ops.VRM_OT_remove_khr_xmp_json_ld_packet_dc_subject, + khr_xmp_json_ld_ops.VRM_OT_move_up_khr_xmp_json_ld_packet_dc_subject, + khr_xmp_json_ld_ops.VRM_OT_move_down_khr_xmp_json_ld_packet_dc_subject, + khr_xmp_json_ld_property_group.KhrXmpJsonLdKhrCharacterPacketPropertyGroup, + khr_xmp_json_ld_ui_list.VRM_UL_khr_xmp_json_ld_packet_dc_creator, + khr_xmp_json_ld_ui_list.VRM_UL_khr_xmp_json_ld_packet_dc_license, + khr_xmp_json_ld_ui_list.VRM_UL_khr_xmp_json_ld_packet_dc_subject, + khr_character_property_group.KhrCharacterPropertyGroup, mtoon1_panel.VRM_PT_vrm_material_property, panel.VRM_PT_current_selected_armature, panel.VRM_PT_controller_unsupported_blender_version_warning,