@volter/blender-engine 0.1.148 → 0.1.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/LICENSE +22 -5
  2. package/README.md +4 -11
  3. package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
  4. package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
  5. package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
  6. package/browser/addons/vrm/README.txt +3 -0
  7. package/browser/addons/vrm/__init__.py +41 -0
  8. package/browser/addons/vrm/blender_manifest.toml +16 -0
  9. package/browser/addons/vrm/common/__init__.py +1 -0
  10. package/browser/addons/vrm/common/animation.py +58 -0
  11. package/browser/addons/vrm/common/blender_manifest.py +82 -0
  12. package/browser/addons/vrm/common/char.py +16 -0
  13. package/browser/addons/vrm/common/convert.py +287 -0
  14. package/browser/addons/vrm/common/convert_any.py +48 -0
  15. package/browser/addons/vrm/common/debug.py +40 -0
  16. package/browser/addons/vrm/common/deep.py +162 -0
  17. package/browser/addons/vrm/common/error_dialog.py +274 -0
  18. package/browser/addons/vrm/common/fs.py +71 -0
  19. package/browser/addons/vrm/common/gl.py +20 -0
  20. package/browser/addons/vrm/common/gltf.py +1149 -0
  21. package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
  22. package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
  23. package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
  24. package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
  25. package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
  26. package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
  27. package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
  28. package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
  29. package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
  30. package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
  31. package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
  32. package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
  33. package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
  34. package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
  35. package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
  36. package/browser/addons/vrm/common/legacy_gltf.py +16 -0
  37. package/browser/addons/vrm/common/logger.py +84 -0
  38. package/browser/addons/vrm/common/mtoon0.blend +0 -0
  39. package/browser/addons/vrm/common/mtoon1.blend +0 -0
  40. package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
  41. package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
  42. package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
  43. package/browser/addons/vrm/common/ops/__init__.py +10 -0
  44. package/browser/addons/vrm/common/ops/export_scene.py +67 -0
  45. package/browser/addons/vrm/common/ops/icyp.py +53 -0
  46. package/browser/addons/vrm/common/ops/import_scene.py +57 -0
  47. package/browser/addons/vrm/common/ops/vrm.py +2380 -0
  48. package/browser/addons/vrm/common/ops/wm.py +167 -0
  49. package/browser/addons/vrm/common/preferences.py +362 -0
  50. package/browser/addons/vrm/common/progress.py +87 -0
  51. package/browser/addons/vrm/common/rotation.py +89 -0
  52. package/browser/addons/vrm/common/safe_removal.py +46 -0
  53. package/browser/addons/vrm/common/scene_watcher.py +230 -0
  54. package/browser/addons/vrm/common/shader.py +2243 -0
  55. package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
  56. package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
  57. package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
  58. package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
  59. package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
  60. package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
  61. package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
  62. package/browser/addons/vrm/common/version.py +161 -0
  63. package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
  64. package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
  65. package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
  66. package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
  67. package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
  68. package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
  69. package/browser/addons/vrm/common/workspace.py +227 -0
  70. package/browser/addons/vrm/common/writable_context.py +77 -0
  71. package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
  72. package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
  73. package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
  74. package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
  75. package/browser/addons/vrm/documentation/en-us/index.md +41 -0
  76. package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
  77. package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
  78. package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
  79. package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
  80. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
  81. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
  82. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
  83. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
  84. package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
  85. package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
  86. package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
  87. package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
  88. package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
  89. package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
  90. package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
  91. package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
  92. package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
  93. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
  94. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
  95. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
  96. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
  97. package/browser/addons/vrm/editor/__init__.py +1 -0
  98. package/browser/addons/vrm/editor/extension.py +425 -0
  99. package/browser/addons/vrm/editor/extension_accessor.py +75 -0
  100. package/browser/addons/vrm/editor/handler.py +84 -0
  101. package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
  102. package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
  103. package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
  104. package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
  105. package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
  106. package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
  107. package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
  108. package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
  109. package/browser/addons/vrm/editor/make_armature.py +709 -0
  110. package/browser/addons/vrm/editor/menu.py +147 -0
  111. package/browser/addons/vrm/editor/migration.py +297 -0
  112. package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
  113. package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
  114. package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
  115. package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
  116. package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
  117. package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
  118. package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
  119. package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
  120. package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
  121. package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
  122. package/browser/addons/vrm/editor/ops.py +471 -0
  123. package/browser/addons/vrm/editor/panel.py +315 -0
  124. package/browser/addons/vrm/editor/property_group.py +888 -0
  125. package/browser/addons/vrm/editor/search.py +682 -0
  126. package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
  127. package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
  128. package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
  129. package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
  130. package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
  131. package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
  132. package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
  133. package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
  134. package/browser/addons/vrm/editor/subscription.py +123 -0
  135. package/browser/addons/vrm/editor/t_pose.py +713 -0
  136. package/browser/addons/vrm/editor/validation.py +1271 -0
  137. package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
  138. package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
  139. package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
  140. package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
  141. package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
  142. package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
  143. package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
  144. package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
  145. package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
  146. package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
  147. package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
  148. package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
  149. package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
  150. package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
  151. package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
  152. package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
  153. package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
  154. package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
  155. package/browser/addons/vrm/exporter/__init__.py +1 -0
  156. package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
  157. package/browser/addons/vrm/exporter/export_scene.py +930 -0
  158. package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
  159. package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
  160. package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
  161. package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
  162. package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
  163. package/browser/addons/vrm/external/__init__.py +1 -0
  164. package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
  165. package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
  166. package/browser/addons/vrm/external/rigify_support.py +1 -0
  167. package/browser/addons/vrm/importer/__init__.py +1 -0
  168. package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
  169. package/browser/addons/vrm/importer/file_handler.py +34 -0
  170. package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
  171. package/browser/addons/vrm/importer/import_scene.py +646 -0
  172. package/browser/addons/vrm/importer/license_validation.py +198 -0
  173. package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
  174. package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
  175. package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
  176. package/browser/addons/vrm/importer/vrm_diff.py +316 -0
  177. package/browser/addons/vrm/locale/__init__.py +1 -0
  178. package/browser/addons/vrm/locale/ja_jp.py +826 -0
  179. package/browser/addons/vrm/locale/ruff.toml +8 -0
  180. package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
  181. package/browser/addons/vrm/locale/zh_hans.py +928 -0
  182. package/browser/addons/vrm/registration.py +670 -0
  183. package/browser/addons/vrm.json +18 -0
  184. package/browser/blender-emscripten-engine.mts +66 -129
  185. package/browser/blender-engine.mts +20 -186
  186. package/browser/blender-wali-engine.mts +37 -81
  187. package/browser/describe-thrown.mts +3 -6
  188. package/browser/document-chunks.mts +4 -16
  189. package/browser/gltf_export.py +3161 -0
  190. package/browser/heap-growth.mts +23 -0
  191. package/browser/index.ts +3 -0
  192. package/browser/protocol.ts +130 -43
  193. package/browser/pull-job.mts +2 -10
  194. package/browser/rna.ts +190 -73
  195. package/browser/runtime.ts +271 -106
  196. package/browser/session-addons.mts +33 -0
  197. package/browser/session-frame.mts +5 -24
  198. package/browser/session.py +1389 -1446
  199. package/browser/three/attach-presenter.ts +11 -39
  200. package/browser/three/blender-base64.ts +1 -36
  201. package/browser/three/blender-corner-normals.ts +1 -23
  202. package/browser/three/blender-display-shaders.json +1 -1
  203. package/browser/three/blender-display-shaders.lut +0 -0
  204. package/browser/three/blender-display-transform.ts +2 -1
  205. package/browser/three/blender-frame-columns.ts +5 -13
  206. package/browser/three/blender-graph-material.ts +18 -3
  207. package/browser/three/blender-node-graph.ts +10 -34
  208. package/browser/three/blender-physical-material.ts +2 -31
  209. package/browser/three/blender-runtime-armature.ts +7 -60
  210. package/browser/three/blender-runtime-frame.ts +9 -23
  211. package/browser/three/blender-runtime-geometry.ts +22 -26
  212. package/browser/three/blender-runtime-lighting.ts +48 -178
  213. package/browser/three/blender-runtime-shadows.ts +187 -1
  214. package/browser/three/blender-runtime-skeleton.ts +53 -1
  215. package/browser/three/blender-runtime-view.ts +492 -306
  216. package/browser/three/blender-runtime-weights.ts +9 -72
  217. package/browser/three/blender-sky.ts +13 -33
  218. package/browser/three/blender-triangulate.ts +7 -35
  219. package/browser/three/blender-viewport-sampling.ts +235 -0
  220. package/browser/three/blender-workbench-material.ts +25 -29
  221. package/browser/three/blender-workbench-outline.ts +199 -0
  222. package/browser/three/blender-world-volume.ts +62 -10
  223. package/browser/three/presenter.ts +10 -26
  224. package/browser/three/release.ts +5 -21
  225. package/browser/three/sky-precompute-worker.ts +1 -18
  226. package/browser/three/sky-worker.ts +5 -23
  227. package/browser/three/world-field-sampler.ts +12 -26
  228. package/browser/volter_three.py +9 -105
  229. package/browser/worker.ts +195 -180
  230. package/package.json +5 -2
  231. package/wasm/BUNDLE.json +17 -17
  232. package/wasm/DEPENDENCY-LICENSES.txt +14 -0
  233. package/wasm/blender_browser.data.br +0 -0
  234. package/wasm/blender_browser.js +1 -1
  235. package/wasm/blender_browser.wasm.br +0 -0
  236. package/browser/frame-transfer.mts +0 -19
  237. package/browser/three/agx-base-srgb.lut +0 -0
  238. package/browser/three/agx-look-medium-high-contrast.lut +0 -0
  239. package/browser/three/agx-look-punchy.lut +0 -0
  240. package/browser/three/blender-agx.ts +0 -235
  241. package/browser/three/blender-display-lut.ts +0 -145
  242. package/browser/three/blender-filmic.ts +0 -49
  243. package/browser/three/blender-standard.ts +0 -68
  244. package/browser/three/blender-world-visibility.ts +0 -278
  245. package/browser/three/filmic-srgb.lut +0 -0
@@ -0,0 +1,147 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import math
3
+ from typing import Final, Optional
4
+
5
+ from bpy.app.translations import pgettext
6
+ from bpy.types import Context, Menu, PointerProperty, PropertyGroup, UILayout
7
+
8
+ from ..common.logger import get_logger
9
+ from .ops import (
10
+ VRM_OT_assign_bone_to_bone_property_group,
11
+ VRM_OT_unassign_bone_to_bone_property_group,
12
+ layout_operator,
13
+ )
14
+ from .property_group import BonePropertyGroup
15
+
16
+ _logger = get_logger(__name__)
17
+
18
+
19
+ class VRM_MT_bone_assignment(Menu):
20
+ bl_label = "Bone Assignment Menu"
21
+ bl_idname = "VRM_MT_bone_assignment"
22
+
23
+ CONTEXT_POINTER_BONE_PROPERTY_GROUP: Final = bl_idname + "_bone_property_group"
24
+
25
+ @classmethod
26
+ def draw_input_layout(
27
+ cls,
28
+ layout: UILayout,
29
+ bone_property_group: BonePropertyGroup,
30
+ *,
31
+ text: Optional[str] = None,
32
+ icon: str = "BONE_DATA",
33
+ simple: bool = False,
34
+ ) -> UILayout:
35
+ bone_name = bone_property_group.bone_name
36
+ if (
37
+ text is None
38
+ and (path_components := bone_property_group.path_from_id().split("."))
39
+ and (parent_path_components := path_components[:-1])
40
+ and (property_name := path_components[-1])
41
+ and (id_data := bone_property_group.id_data)
42
+ and (parent_path := ".".join(parent_path_components))
43
+ and (parent := id_data.path_resolve(parent_path, False))
44
+ and isinstance(parent, PropertyGroup)
45
+ and (pointer_property := parent.bl_rna.properties.get(property_name))
46
+ and isinstance(pointer_property, PointerProperty)
47
+ ):
48
+ text = pointer_property.name
49
+
50
+ if simple:
51
+ label = pgettext(text) if text is not None else ""
52
+ row = layout.row(align=True)
53
+ row.prop_search(
54
+ bone_property_group,
55
+ "bone_name",
56
+ bone_property_group.find_armature(),
57
+ "bones",
58
+ text=label,
59
+ icon=icon,
60
+ translate=False,
61
+ )
62
+ return row
63
+
64
+ row = layout.row(align=True)
65
+ if text:
66
+ row = row.split(factor=0.24, align=True)
67
+ row.label(text=pgettext(text) + ":", translate=False)
68
+ row.context_pointer_set(
69
+ cls.CONTEXT_POINTER_BONE_PROPERTY_GROUP, bone_property_group
70
+ )
71
+ row.menu(
72
+ VRM_MT_bone_assignment.bl_idname,
73
+ text=bone_name or " ",
74
+ icon=icon,
75
+ translate=False,
76
+ )
77
+ return row
78
+
79
+ def draw(self, context: Context) -> None:
80
+ layout = self.layout
81
+
82
+ bone_property_group = getattr(
83
+ context, self.CONTEXT_POINTER_BONE_PROPERTY_GROUP, None
84
+ )
85
+ if not isinstance(bone_property_group, BonePropertyGroup):
86
+ return
87
+ armature_data = bone_property_group.find_armature()
88
+ bone_property_group_path = bone_property_group.path_from_id()
89
+
90
+ bone_names = [
91
+ bone_name
92
+ for bone_name in bone_property_group.filter_bone_names(
93
+ armature_data.bones.keys()
94
+ )
95
+ if bone_name != bone_property_group.bone_name
96
+ ]
97
+ # Include the search row in the total item count for column calculation
98
+ all_items_count = len(bone_names) + 1
99
+
100
+ row = layout.row()
101
+ column = row.column()
102
+ column.prop_search(
103
+ bone_property_group,
104
+ "bone_name",
105
+ armature_data,
106
+ "bones",
107
+ text="",
108
+ translate=False,
109
+ icon="VIEWZOOM",
110
+ )
111
+ base_item_index = 1
112
+ if bone_property_group.bone_name:
113
+ unassign_op = layout_operator(
114
+ column,
115
+ VRM_OT_unassign_bone_to_bone_property_group,
116
+ text="<Unassign>",
117
+ translate=True,
118
+ icon="REMOVE",
119
+ )
120
+ unassign_op.armature_data_name = armature_data.name
121
+ unassign_op.bone_property_group_path = bone_property_group_path
122
+ all_items_count += 1
123
+ base_item_index = 2
124
+
125
+ column_count_limit = 7
126
+ column_items_count_soft_limit = 15
127
+ column_count = min(
128
+ math.ceil(all_items_count / column_items_count_soft_limit),
129
+ column_count_limit,
130
+ )
131
+ column_items_count = math.ceil(all_items_count / column_count)
132
+
133
+ for bone_index, bone_name in enumerate(bone_names):
134
+ item_index = base_item_index + bone_index
135
+ if item_index != 0 and item_index % column_items_count == 0:
136
+ column = row.column()
137
+
138
+ op = layout_operator(
139
+ column,
140
+ VRM_OT_assign_bone_to_bone_property_group,
141
+ text=bone_name,
142
+ translate=False,
143
+ icon="BONE_DATA",
144
+ )
145
+ op.armature_data_name = armature_data.name
146
+ op.bone_property_group_path = bone_property_group_path
147
+ op.bone_name = bone_name
@@ -0,0 +1,297 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import functools
3
+ from dataclasses import dataclass, field
4
+ from typing import Final, Optional
5
+
6
+ import bpy
7
+ from bpy.types import Armature, Context
8
+
9
+ from ..common import ops
10
+ from ..common.logger import get_logger
11
+ from ..common.preferences import get_preferences
12
+ from ..common.version import get_addon_version
13
+ from .extension import (
14
+ VrmAddonArmatureExtensionPropertyGroup,
15
+ VrmAddonSceneExtensionPropertyGroup,
16
+ )
17
+ from .extension_accessor import get_armature_extension
18
+ from .mtoon1 import migration as mtoon1_migration
19
+ from .spring_bone1 import migration as spring_bone1_migration
20
+ from .vrm0 import migration as vrm0_migration
21
+ from .vrm1 import migration as vrm1_migration
22
+
23
+ _logger = get_logger(__name__)
24
+
25
+
26
+ @dataclass
27
+ class State:
28
+ blend_file_compatibility_warning_shown: bool = False
29
+ blend_file_addon_compatibility_warning_shown: bool = False
30
+ deferred_migration_parameters: Final[set[tuple[str, bool]]] = field(
31
+ default_factory=set[tuple[str, bool]]
32
+ )
33
+
34
+ def clear(self) -> None:
35
+ self.blend_file_compatibility_warning_shown = False
36
+ self.blend_file_addon_compatibility_warning_shown = False
37
+ self.deferred_migration_parameters.clear()
38
+
39
+
40
+ _state: Final = State()
41
+
42
+
43
+ def is_unnecessary(armature_data: Armature, *, heavy_migration: bool) -> bool:
44
+ ext = get_armature_extension(armature_data)
45
+ return (
46
+ tuple(ext.addon_version) >= get_addon_version()
47
+ and vrm0_migration.is_unnecessary(ext.vrm0, heavy_migration=heavy_migration)
48
+ and vrm1_migration.is_unnecessary(ext.vrm1, heavy_migration=heavy_migration)
49
+ and spring_bone1_migration.is_unnecessary(
50
+ ext.spring_bone1, heavy_migration=heavy_migration
51
+ )
52
+ )
53
+
54
+
55
+ def defer_migrate(armature_object_name: str, *, heavy_migration: bool) -> bool:
56
+ context = bpy.context
57
+
58
+ armature = context.blend_data.objects.get(armature_object_name)
59
+ if not armature:
60
+ return False
61
+ armature_data = armature.data
62
+ if not isinstance(armature_data, Armature):
63
+ return False
64
+ if is_unnecessary(armature_data, heavy_migration=heavy_migration):
65
+ return True
66
+
67
+ parameter = (armature_object_name, heavy_migration)
68
+ light_parameter = (armature_object_name, False)
69
+ heavy_parameter = (armature_object_name, True)
70
+
71
+ if parameter in _state.deferred_migration_parameters:
72
+ return False
73
+
74
+ if heavy_migration:
75
+ _state.deferred_migration_parameters.add(parameter)
76
+ _state.deferred_migration_parameters.discard(light_parameter)
77
+ elif heavy_parameter not in _state.deferred_migration_parameters:
78
+ _state.deferred_migration_parameters.add(parameter)
79
+ else:
80
+ return False
81
+
82
+ if not bpy.app.timers.is_registered(_migrate_timer_callback):
83
+ bpy.app.timers.register(_migrate_timer_callback)
84
+ return False
85
+
86
+
87
+ def _migrate_timer_callback() -> None:
88
+ """Match the type of migrate() to bpy.app.timers.register."""
89
+ context = bpy.context # Context cannot span frames, so get it anew
90
+
91
+ sorted_deferred_migration_parameters = sorted(_state.deferred_migration_parameters)
92
+ _state.deferred_migration_parameters.clear()
93
+ for armature_object_name, heavy_migration in sorted_deferred_migration_parameters:
94
+ migrate(context, armature_object_name, heavy_migration=heavy_migration)
95
+
96
+
97
+ def migrate(
98
+ context: Optional[Context],
99
+ armature_object_name: str,
100
+ *,
101
+ heavy_migration: bool,
102
+ ) -> bool:
103
+ if context is None:
104
+ context = bpy.context
105
+
106
+ armature = context.blend_data.objects.get(armature_object_name)
107
+ if not armature:
108
+ return False
109
+ armature_data = armature.data
110
+ if not isinstance(armature_data, Armature):
111
+ return False
112
+
113
+ if is_unnecessary(armature_data, heavy_migration=heavy_migration):
114
+ return True
115
+
116
+ ext = get_armature_extension(armature_data)
117
+ if (
118
+ ext.has_vrm_model_metadata(armature)
119
+ and tuple(ext.addon_version) == ext.UNMANAGED_ADDON_VERSION
120
+ ):
121
+ # If old metadata exists from before ext.addon_version existed,
122
+ # set addon_version to 0.0.100 and properly upgrade it within migrate().
123
+ ext.addon_version = (0, 0, 100)
124
+
125
+ vrm0_migration.migrate(context, ext.vrm0, armature, heavy_migration=heavy_migration)
126
+ vrm1_migration.migrate(context, ext.vrm1, armature, heavy_migration=heavy_migration)
127
+ spring_bone1_migration.migrate(context, armature, heavy_migration=heavy_migration)
128
+
129
+ if (
130
+ tuple(ext.addon_version) < (3, 14, 0)
131
+ and tuple(ext.addon_version) != ext.UNMANAGED_ADDON_VERSION
132
+ and not ext.get("spec_version")
133
+ ):
134
+ ext.spec_version = ext.SPEC_VERSION_VRM0
135
+
136
+ updated_addon_version = get_addon_version()
137
+ _logger.info(
138
+ "Upgrade armature %s %s to %s",
139
+ armature_object_name,
140
+ tuple(ext.addon_version),
141
+ updated_addon_version,
142
+ )
143
+ ext.addon_version = updated_addon_version
144
+ return True
145
+
146
+
147
+ def migrate_all_objects(
148
+ context: Context,
149
+ *,
150
+ heavy_migration: bool,
151
+ show_progress: bool = False,
152
+ ) -> None:
153
+ for obj in context.blend_data.objects:
154
+ if obj.type == "ARMATURE":
155
+ migrate(context, obj.name, heavy_migration=heavy_migration)
156
+
157
+ VrmAddonSceneExtensionPropertyGroup.update_vrm0_material_property_names(context)
158
+ mtoon1_migration.migrate(context, show_progress=show_progress)
159
+ _validate_blend_file_compatibility(context)
160
+ _validate_blend_file_addon_compatibility(context)
161
+
162
+ preferences = get_preferences(context)
163
+
164
+ updated_addon_version = get_addon_version()
165
+ if tuple(preferences.addon_version) != updated_addon_version:
166
+ _logger.debug(
167
+ "Upgrade preferences %s to %s",
168
+ tuple(preferences.addon_version),
169
+ updated_addon_version,
170
+ )
171
+
172
+ if (
173
+ tuple(preferences.addon_version) < (2, 34, 0)
174
+ and tuple(preferences.addon_version) != preferences.UNMANAGED_ADDON_VERSION
175
+ ):
176
+ preferences.enable_advanced_preferences = True
177
+ preferences.export_gltf_animations = True
178
+
179
+ preferences.addon_version = updated_addon_version
180
+
181
+
182
+ def _validate_blend_file_compatibility(context: Context) -> None:
183
+ """Warn when attempting to edit a file created in newer Blender with older Blender.
184
+
185
+ Due to add-on version support issues, there are often reports of users trying to
186
+ edit files created in newer Blender with older Blender, which can cause shape keys
187
+ to break. This warning alerts users to be careful.
188
+ """
189
+ if not context.blend_data.filepath:
190
+ return
191
+ if not _have_vrm_model(context):
192
+ return
193
+
194
+ blend_file_major_minor_version = (
195
+ context.blend_data.version[0],
196
+ context.blend_data.version[1],
197
+ )
198
+ current_major_minor_version = (bpy.app.version[0], bpy.app.version[1])
199
+ if blend_file_major_minor_version <= current_major_minor_version:
200
+ return
201
+
202
+ file_version_str = ".".join(map(str, blend_file_major_minor_version))
203
+ app_version_str = ".".join(map(str, current_major_minor_version))
204
+
205
+ _logger.error(
206
+ "Opening incompatible file: file_blender_version=%s running_blender_version=%s",
207
+ file_version_str,
208
+ app_version_str,
209
+ )
210
+
211
+ if not _state.blend_file_compatibility_warning_shown:
212
+ _state.blend_file_compatibility_warning_shown = True
213
+ # Use timer because dialog disappears automatically if not executed with
214
+ # timer in Blender 4.2.0
215
+ bpy.app.timers.register(
216
+ functools.partial(
217
+ _show_blend_file_compatibility_warning,
218
+ file_version_str,
219
+ app_version_str,
220
+ ),
221
+ first_interval=0.1,
222
+ )
223
+
224
+
225
+ def _show_blend_file_compatibility_warning(file_version: str, app_version: str) -> None:
226
+ ops.vrm.show_blend_file_compatibility_warning(
227
+ "INVOKE_DEFAULT",
228
+ file_version=file_version,
229
+ app_version=app_version,
230
+ )
231
+
232
+
233
+ def _validate_blend_file_addon_compatibility(context: Context) -> None:
234
+ """Warn when attempting to edit a file created with a newer VRM add-on.
235
+
236
+ This warning is for files using an older VRM add-on.
237
+ """
238
+ if not context.blend_data.filepath:
239
+ return
240
+ installed_addon_version = get_addon_version()
241
+
242
+ # TODO: It might be better to store the version in Scene or similar
243
+ file_addon_version: tuple[int, ...] = (0, 0, 0)
244
+ for armature in context.blend_data.armatures:
245
+ file_addon_version = tuple(get_armature_extension(armature).addon_version)
246
+ if file_addon_version > installed_addon_version:
247
+ break
248
+ else:
249
+ return
250
+
251
+ file_addon_version_str = ".".join(map(str, file_addon_version))
252
+ installed_addon_version_str = ".".join(map(str, installed_addon_version))
253
+
254
+ _logger.error(
255
+ "Opening incompatible VRM add-on version: file=%s installed=%s",
256
+ file_addon_version_str,
257
+ installed_addon_version_str,
258
+ )
259
+
260
+ if not _state.blend_file_addon_compatibility_warning_shown:
261
+ _state.blend_file_addon_compatibility_warning_shown = True
262
+ # Use timer because dialog disappears automatically if not executed with
263
+ # timer in Blender 4.2.0
264
+ bpy.app.timers.register(
265
+ functools.partial(
266
+ _show_blend_file_addon_compatibility_warning,
267
+ file_addon_version_str,
268
+ installed_addon_version_str,
269
+ ),
270
+ first_interval=0.1,
271
+ )
272
+
273
+
274
+ def _show_blend_file_addon_compatibility_warning(
275
+ file_addon_version: str, installed_addon_version: str
276
+ ) -> None:
277
+ ops.vrm.show_blend_file_addon_compatibility_warning(
278
+ "INVOKE_DEFAULT",
279
+ file_addon_version=file_addon_version,
280
+ installed_addon_version=installed_addon_version,
281
+ )
282
+
283
+
284
+ def _have_vrm_model(context: Context) -> bool:
285
+ return any(
286
+ map(
287
+ VrmAddonArmatureExtensionPropertyGroup.has_vrm_model_metadata,
288
+ context.blend_data.objects,
289
+ )
290
+ )
291
+
292
+
293
+ def clear_global_variables() -> None:
294
+ _state.clear()
295
+
296
+ if bpy.app.timers.is_registered(_migrate_timer_callback):
297
+ bpy.app.timers.unregister(_migrate_timer_callback)
@@ -0,0 +1 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
@@ -0,0 +1,20 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+
3
+ import bpy
4
+ from bpy.app.handlers import persistent
5
+ from bpy.types import Depsgraph, Scene
6
+
7
+ from ...common.logger import get_logger
8
+ from ...common.scene_watcher import trigger_scene_watcher
9
+ from .scene_watcher import MToon1AutoSetup, OutlineUpdater
10
+
11
+ _logger = get_logger(__name__)
12
+
13
+
14
+ @persistent
15
+ def depsgraph_update_post(_scene: Scene, depsgraph: Depsgraph) -> None:
16
+ if depsgraph.id_type_updated("MATERIAL"):
17
+ trigger_scene_watcher(MToon1AutoSetup)
18
+
19
+ if bpy.app.version >= (3, 3):
20
+ trigger_scene_watcher(OutlineUpdater)