kitou commited on
Commit
4d3af08
1 Parent(s): c391c6c

Upload 646 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +27 -0
  2. vae/com3d/2018-04-18_225822/crash.dmp +0 -0
  3. vae/com3d/2018-04-18_225822/error.log +25 -0
  4. vae/com3d/2018-04-18_225822/output_log.txt +0 -0
  5. vae/com3d/2018-04-18_225822/report.ini +0 -0
  6. vae/com3d/[CM3D2]English Mod Tools Pack/All Purpose arc Editor (Sybaris Arc Edtor(English))/Readme.txt +17 -0
  7. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/__init__.py +310 -0
  8. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/anm_export.py +334 -0
  9. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/anm_import.py +213 -0
  10. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/append_data.blend +3 -0
  11. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/common.py +635 -0
  12. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/console_toggle.py +3 -0
  13. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/fileutil.py +83 -0
  14. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/kiss.png +0 -0
  15. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/mate_export.py +257 -0
  16. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/mate_import.py +224 -0
  17. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_DATA_PT_context_arm.py +300 -0
  18. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_DATA_PT_modifiers.py +217 -0
  19. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_DATA_PT_vertex_groups.py +127 -0
  20. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_IMAGE_HT_header.py +14 -0
  21. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_IMAGE_PT_image_properties.py +12 -0
  22. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_HT_header.py +48 -0
  23. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_MT_add.py +56 -0
  24. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_MT_curve_add.py +186 -0
  25. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_MT_help.py +154 -0
  26. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_MATERIAL_PT_context_material.py +822 -0
  27. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_MESH_MT_shape_key_specials.py +575 -0
  28. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_MESH_MT_vertex_group_specials.py +672 -0
  29. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_OBJECT_PT_context_object.py +184 -0
  30. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_OBJECT_PT_transform.py +42 -0
  31. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_RENDER_PT_bake.py +1680 -0
  32. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_RENDER_PT_render.py +306 -0
  33. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_TEXTURE_PT_context_texture.py +568 -0
  34. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_TEXT_HT_header.py +174 -0
  35. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_MT_edit_mesh_specials.py +56 -0
  36. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_MT_pose_apply.py +113 -0
  37. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_PT_tools_mesh_shapekey.py +16 -0
  38. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_PT_tools_weightpaint.py +394 -0
  39. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/model_export.py +849 -0
  40. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/model_import.py +671 -0
  41. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/tex_export.py +115 -0
  42. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/tex_import.py +71 -0
  43. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/CM3D2 Mod Search.exe +0 -0
  44. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/CM3D2 Mod Search.html +22 -0
  45. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/CM3D2 Mod Search.ini +9 -0
  46. vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/Readme & Modder List.txt +213 -0
  47. vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/Dictionary and How to.txt +102 -0
  48. vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/[CM3D2]menuEdit.exe +0 -0
  49. vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/readme.txt +4 -0
  50. vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/src/[CM3D2]menuEdit.ahk +274 -0
.gitattributes CHANGED
@@ -80,3 +80,30 @@ vae/com3d/COM3D2x64_Data/resources.assets filter=lfs diff=lfs merge=lfs -text
80
  vae/com3d/COM3D2x64_Data/resources.assets.resS filter=lfs diff=lfs merge=lfs -text
81
  vae/com3d/COM3D2x64_Data/sharedassets0.assets filter=lfs diff=lfs merge=lfs -text
82
  vae/com3d/COM3D2x64_Data/sharedassets0.assets.resS filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  vae/com3d/COM3D2x64_Data/resources.assets.resS filter=lfs diff=lfs merge=lfs -text
81
  vae/com3d/COM3D2x64_Data/sharedassets0.assets filter=lfs diff=lfs merge=lfs -text
82
  vae/com3d/COM3D2x64_Data/sharedassets0.assets.resS filter=lfs diff=lfs merge=lfs -text
83
+ vae/com3d/_AssetsBundleExtractor_2.1c/32bit/fmod.dll filter=lfs diff=lfs merge=lfs -text
84
+ vae/com3d/_AssetsBundleExtractor_2.1c/32bit/PVRTexLib.dll filter=lfs diff=lfs merge=lfs -text
85
+ vae/com3d/_AssetsBundleExtractor_2.1c/64bit/fmod64.dll filter=lfs diff=lfs merge=lfs -text
86
+ vae/com3d/_AssetsBundleExtractor_2.1c/64bit/PVRTexLib.dll filter=lfs diff=lfs merge=lfs -text
87
+ vae/com3d/_CM3D2_Toolkit_PR2/Tスタンス素体.blend filter=lfs diff=lfs merge=lfs -text
88
+ vae/com3d/_setup/CM3D2_ED_x64.exe filter=lfs diff=lfs merge=lfs -text
89
+ vae/com3d/_setup/CM3D2_EF.exe filter=lfs diff=lfs merge=lfs -text
90
+ vae/com3d/_setup/CM3D2.exe filter=lfs diff=lfs merge=lfs -text
91
+ vae/com3d/_setup/CM3D2x64.exe filter=lfs diff=lfs merge=lfs -text
92
+ vae/com3d/_setup/Sybaris/Plugins/UnityInjector/Config/EditMenuUtility.xml filter=lfs diff=lfs merge=lfs -text
93
+ vae/com3d/_setup/Sybaris/Plugins/UnityInjector/Config/PropMyItem.xml filter=lfs diff=lfs merge=lfs -text
94
+ vae/com3d/_setup/SybarisArcEditor.exe filter=lfs diff=lfs merge=lfs -text
95
+ vae/com3d/_Translation/Assets/_kor/sharedassets0/1367BD762E26A742.png filter=lfs diff=lfs merge=lfs -text
96
+ vae/com3d/_Translation/Assets/_kor/sharedassets0/[email protected] filter=lfs diff=lfs merge=lfs -text
97
+ vae/com3d/_Translation/Assets/_kor/sharedassets0/4209AC888C3D23D8.png filter=lfs diff=lfs merge=lfs -text
98
+ vae/com3d/_Translation/Textures/_ENG/Tutorial/cm3d2_tutorial_deskcustom.tex filter=lfs diff=lfs merge=lfs -text
99
+ vae/com3d/_Translation/Textures/_ENG/Tutorial/cm3d2_tutorial_skillselect00.tex filter=lfs diff=lfs merge=lfs -text
100
+ vae/com3d/_Translation/Textures/_kor/UI_Tutorial/cm3d2_tutorial_deskcustom.png filter=lfs diff=lfs merge=lfs -text
101
+ vae/com3d/_Translation/Textures/_kor/UI_Tutorial/cm3d2_tutorial_skillselect00.png filter=lfs diff=lfs merge=lfs -text
102
+ vae/com3d/_vmd/magnet/magミク修正版3.vmd filter=lfs diff=lfs merge=lfs -text
103
+ vae/com3d/_vmd/magnet/magミク別バージョン.vmd filter=lfs diff=lfs merge=lfs -text
104
+ vae/com3d/_vmd/magnet/magルカ修正版3.vmd filter=lfs diff=lfs merge=lfs -text
105
+ vae/com3d/_vmd/magnet/magルカ別バージョン.vmd filter=lfs diff=lfs merge=lfs -text
106
+ vae/com3d/_vmd/いーあるモーションせっと/いーあるぐみさん.vmd filter=lfs diff=lfs merge=lfs -text
107
+ vae/com3d/_vmd/いーあるモーションせっと/いーあるりんちゃんさん.vmd filter=lfs diff=lfs merge=lfs -text
108
+ vae/com3d/\[CM3D2\]English[[:space:]]Mod[[:space:]]Tools[[:space:]]Pack/\[CM3D2\]Various[[:space:]]Modding[[:space:]]Tools[[:space:]]151220[[:space:]](English)/T[[:space:]]Pose[[:space:]]body.blend filter=lfs diff=lfs merge=lfs -text
109
+ vae/com3d/\[CM3D2\]English[[:space:]]Mod[[:space:]]Tools[[:space:]]Pack/CM3D2[[:space:]]Converter[[:space:]](English)/append_data.blend filter=lfs diff=lfs merge=lfs -text
vae/com3d/2018-04-18_225822/crash.dmp ADDED
Binary file (146 kB). View file
 
vae/com3d/2018-04-18_225822/error.log ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Unity Player [version: Unity 4.7.1f1_68064779abd0]
2
+
3
+ CM3D2x64.exe caused an Access Violation (0xc0000005)
4
+ in module CM3D2x64.exe at 0033:d76fa030.
5
+
6
+ Error occurred at 2018-04-18_225830.
7
+ D:\CM3D2\CM3D2x64.exe, run by TOMOKI.
8
+ 24% memory in use.
9
+ 32716 MB physical memory [24700 MB free].
10
+ 37580 MB paging file [28009 MB free].
11
+ 134217728 MB user address space [134216871 MB free].
12
+ Write to location d76fa030 caused an access violation.
13
+
14
+ Context:
15
+ RDI: 0x0670e530 RSI: 0x152a4e30 RAX: 0xd76fa030
16
+ RBX: 0x152a4e10 RCX: 0x152a4e30 RDX: 0x152a4e30
17
+ RIP: 0xd76fa030 RBP: 0x068ef530 SegCs: 0x00000033
18
+ EFlags: 0x00010206 RSP: 0x068ef498 SegSs: 0x0000002b
19
+ R8: 0x068ef6c0 R9: 0x00000000 R10: 0x00000000
20
+ R11: 0x068ef4c8 R12: 0x06064d48 R13: 0x152a4e10
21
+ R14: 0x06064d48 R15: 0x00000000
22
+
23
+ Bytes at CS:EIP:
24
+ ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??
25
+ == [end of error.log] ==
vae/com3d/2018-04-18_225822/output_log.txt ADDED
The diff for this file is too large to render. See raw diff
 
vae/com3d/2018-04-18_225822/report.ini ADDED
Binary file (630 Bytes). View file
 
vae/com3d/[CM3D2]English Mod Tools Pack/All Purpose arc Editor (Sybaris Arc Edtor(English))/Readme.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This is the best application for anything having to do with arc files by far.
2
+ A very simple and handy graphical interface makes locating the files you want to extract/replace etc very easy and now this app is 99% in english.
3
+
4
+ ***To make use of it simply drop it in your install directory (your CM3D2 folder) or wherever your main CM3D2 application is located. Then just run it and you are good to go.
5
+ Sybaris Arc editor is completely stand alone and does not need sybaris to work and can work with reipatcher.
6
+
7
+ This app will open every arc file it can find in one window so you can easily use the search function to search through every arc instantly.
8
+ It can even let you find specific mods as it allows you to view loaded mods too by menu icon and category all in the menu tab. and it has many more features and tools.
9
+
10
+ NOTE: The app can take some time to show on screen after it has been opened because opening every single arc in the game isn't exactly easy.
11
+ But the wait is minimal and worth it compared to the benefits.
12
+
13
+ NOTE 2: With this newer version of SAE the load times are cut down by a lot and at most you will have a short wait time while switching tabs.
14
+
15
+ I take no credit for creating this application. I only take credit for translating and extend credit to Exkirion on hongfire for also translating.
16
+
17
+ Don't abuse your miedos!
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/__init__.py ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # アドオンを読み込む時に最初にこのファイルが読み込まれます
2
+
3
+ # アドオン情報
4
+ bl_info = {
5
+ "name" : "CM3D2 Converter",
6
+ "author" : "@saidenka_cm3d2",
7
+ "version" : (2017, 5, 16, 21, 39, 32),
8
+ "blender" : (2, 78, 0),
9
+ "location" : "File > Import/Export > CM3D2 Model (.model)",
10
+ "description" : "A plugin dedicated to the editing, importing, and exporting of CM3D2 .Model Files.",
11
+ "warning" : "",
12
+ "wiki_url" : "https://github.com/CM3Duser/Blender-CM3D2-Converter",
13
+ "tracker_url" : "https://twitter.com/saidenka_cm3d2",
14
+ "category" : "Import-Export"
15
+ }
16
+
17
+ # サブスクリプト群をインポート
18
+ if "bpy" in locals():
19
+ import imp
20
+
21
+ imp.reload(common)
22
+
23
+ imp.reload(model_import)
24
+ imp.reload(model_export)
25
+
26
+ imp.reload(anm_import)
27
+ imp.reload(anm_export)
28
+
29
+ imp.reload(tex_import)
30
+ imp.reload(tex_export)
31
+
32
+ imp.reload(mate_import)
33
+ imp.reload(mate_export)
34
+
35
+ imp.reload(misc_DATA_PT_context_arm)
36
+ imp.reload(misc_DATA_PT_modifiers)
37
+ imp.reload(misc_DATA_PT_vertex_groups)
38
+ imp.reload(misc_IMAGE_HT_header)
39
+ imp.reload(misc_IMAGE_PT_image_properties)
40
+ imp.reload(misc_INFO_HT_header)
41
+ imp.reload(misc_INFO_MT_add)
42
+ imp.reload(misc_INFO_MT_curve_add)
43
+ imp.reload(misc_INFO_MT_help)
44
+ imp.reload(misc_MATERIAL_PT_context_material)
45
+ imp.reload(misc_MESH_MT_shape_key_specials)
46
+ imp.reload(misc_MESH_MT_vertex_group_specials)
47
+ imp.reload(misc_OBJECT_PT_context_object)
48
+ imp.reload(misc_OBJECT_PT_transform)
49
+ imp.reload(misc_RENDER_PT_bake)
50
+ imp.reload(misc_RENDER_PT_render)
51
+ imp.reload(misc_TEXTURE_PT_context_texture)
52
+ imp.reload(misc_TEXT_HT_header)
53
+ imp.reload(misc_VIEW3D_MT_edit_mesh_specials)
54
+ imp.reload(misc_VIEW3D_MT_pose_apply)
55
+ imp.reload(misc_VIEW3D_PT_tools_weightpaint)
56
+ imp.reload(misc_VIEW3D_PT_tools_mesh_shapekey)
57
+
58
+ else:
59
+ from . import common
60
+
61
+ from . import model_import
62
+ from . import model_export
63
+
64
+ from . import anm_import
65
+ from . import anm_export
66
+
67
+ from . import tex_import
68
+ from . import tex_export
69
+
70
+ from . import mate_import
71
+ from . import mate_export
72
+
73
+ from . import misc_DATA_PT_context_arm
74
+ from . import misc_DATA_PT_modifiers
75
+ from . import misc_DATA_PT_vertex_groups
76
+ from . import misc_IMAGE_HT_header
77
+ from . import misc_IMAGE_PT_image_properties
78
+ from . import misc_INFO_HT_header
79
+ from . import misc_INFO_MT_add
80
+ from . import misc_INFO_MT_curve_add
81
+ from . import misc_INFO_MT_help
82
+ from . import misc_MATERIAL_PT_context_material
83
+ from . import misc_MESH_MT_shape_key_specials
84
+ from . import misc_MESH_MT_vertex_group_specials
85
+ from . import misc_OBJECT_PT_context_object
86
+ from . import misc_OBJECT_PT_transform
87
+ from . import misc_RENDER_PT_bake
88
+ from . import misc_RENDER_PT_render
89
+ from . import misc_TEXTURE_PT_context_texture
90
+ from . import misc_TEXT_HT_header
91
+ from . import misc_VIEW3D_MT_edit_mesh_specials
92
+ from . import misc_VIEW3D_MT_pose_apply
93
+ from . import misc_VIEW3D_PT_tools_weightpaint
94
+ from . import misc_VIEW3D_PT_tools_mesh_shapekey
95
+
96
+ import bpy, os.path, bpy.utils.previews
97
+
98
+ # アドオン設定
99
+ class AddonPreferences(bpy.types.AddonPreferences):
100
+ bl_idname = __name__
101
+
102
+ cm3d2_path = bpy.props.StringProperty(name="CM3D2 Location", subtype='DIR_PATH', description="You should set the correct directory if you used a different one.")
103
+ backup_ext = bpy.props.StringProperty(name="Backup Extension (Must not be left blank)", description="The previous Model file with the same name will be given an extension.", default='bak')
104
+
105
+ scale = bpy.props.FloatProperty(name="Scale", description="The scale at which the models are imported and exported", default=5, min=0.01, max=100, soft_min=0.01, soft_max=100, step=10, precision=2)
106
+ is_convert_bone_weight_names = bpy.props.BoolProperty(name="Convert weight names for Blender", default=False, description="Will change the options default when importing or exporting.")
107
+ model_default_path = bpy.props.StringProperty(name="Model Default Path", subtype='DIR_PATH', description="If set. The file selection will open here.")
108
+ model_import_path = bpy.props.StringProperty(name="Model Default Import Path", subtype='FILE_PATH', description="When importing a .model file. The file selection prompt will begin here.")
109
+ model_export_path = bpy.props.StringProperty(name="Model Default Export Path", subtype='FILE_PATH', description="When exporting a .model file. The file selection prompt will begin here.")
110
+
111
+ anm_default_path = bpy.props.StringProperty(name=".anm Default Path", subtype='DIR_PATH', description="If set. The file selection will open here.")
112
+ anm_import_path = bpy.props.StringProperty(name=".anm Default Import Path", subtype='FILE_PATH', description="When importing a .anm file. The file selection prompt will begin here.")
113
+ anm_export_path = bpy.props.StringProperty(name=".anm Default Export Path", subtype='FILE_PATH', description="When exporting a .anm file. The file selection prompt will begin here.")
114
+
115
+ tex_default_path = bpy.props.StringProperty(name=".tex Default Path", subtype='DIR_PATH', description="If set. The file selection will open here.")
116
+ tex_import_path = bpy.props.StringProperty(name=".tex Default Import Path", subtype='FILE_PATH', description="When importing a .tex file. The file selection prompt will begin here.")
117
+ tex_export_path = bpy.props.StringProperty(name=".tex Default Export Path", subtype='FILE_PATH', description="When exporting a .tex file. The file selection prompt will begin here.")
118
+
119
+ mate_default_path = bpy.props.StringProperty(name=".mate Default Path", subtype='DIR_PATH', description="If set. The file selection will open here.")
120
+ mate_unread_same_value = bpy.props.BoolProperty(name="Delete if there are two or more same values", default=True, description="_ShadowColor")
121
+ mate_import_path = bpy.props.StringProperty(name=".mate Default Import Path", subtype='FILE_PATH', description="When importing a .mate file. The file selection prompt will begin here.")
122
+ mate_export_path = bpy.props.StringProperty(name=".mate Default Export Path", subtype='FILE_PATH', description="When exporting a .mate file. The file selection prompt will begin here.")
123
+
124
+ is_replace_cm3d2_tex = bpy.props.BoolProperty(name="Search for Tex File", default=True, description="Sets the default of the option to search for tex files")
125
+ default_tex_path0 = bpy.props.StringProperty(name="Tex file search area", subtype='DIR_PATH', description="Search here for tex files")
126
+ default_tex_path1 = bpy.props.StringProperty(name="Tex file search area", subtype='DIR_PATH', description="Search here for tex files")
127
+ default_tex_path2 = bpy.props.StringProperty(name="Tex file search area", subtype='DIR_PATH', description="Search here for tex files")
128
+ default_tex_path3 = bpy.props.StringProperty(name="Tex file search area", subtype='DIR_PATH', description="Search here for tex files")
129
+
130
+
131
+ new_mate_tex_color = bpy.props.FloatVectorProperty(name="Material Color", default=(0, 0, 1, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=4)
132
+
133
+ new_mate_toonramp_name = bpy.props.StringProperty(name="_ToonRamp Name", default="toonGrayA1")
134
+ new_mate_toonramp_path = bpy.props.StringProperty(name="_ToonRamp Path", default=r"Assets\texture\texture\toon\toonGrayA1.png")
135
+
136
+ new_mate_shadowratetoon_name = bpy.props.StringProperty(name="_ShadowRateToon Name", default="toonDress_shadow")
137
+ new_mate_shadowratetoon_path = bpy.props.StringProperty(name="_ShadowRateToon Path", default=r"Assets\texture\texture\toon\toonDress_shadow.png")
138
+
139
+ new_mate_color = bpy.props.FloatVectorProperty(name="_Color", default=(1, 1, 1, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=4)
140
+ new_mate_shadowcolor = bpy.props.FloatVectorProperty(name="_ShadowColor", default=(0, 0, 0, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=4)
141
+ new_mate_rimcolor = bpy.props.FloatVectorProperty(name="_RimColor", default=(0.5, 0.5, 0.5, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=4)
142
+ new_mate_outlinecolor = bpy.props.FloatVectorProperty(name="_OutlineColor", default=(0, 0, 0, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=4)
143
+
144
+ new_mate_shininess = bpy.props.FloatProperty(name="_Shininess", default=0, min=-100, max=100, soft_min=-100, soft_max=100, step=1, precision=2)
145
+ new_mate_outlinewidth = bpy.props.FloatProperty(name="_OutlineWidth", default=0.0015, min=-100, max=100, soft_min=-100, soft_max=100, step=1, precision=2)
146
+ new_mate_rimpower = bpy.props.FloatProperty(name="_RimPower", default=25, min=-100, max=100, soft_min=-100, soft_max=100, step=1, precision=2)
147
+ new_mate_rimshift = bpy.props.FloatProperty(name="_RimShift", default=0, min=-100, max=100, soft_min=-100, soft_max=100, step=1, precision=2)
148
+ new_mate_hirate = bpy.props.FloatProperty(name="_HiRate", default=0.5, min=-100, max=100, soft_min=-100, soft_max=100, step=1, precision=2)
149
+ new_mate_hipow = bpy.props.FloatProperty(name="_HiPow", default=0.001, min=-100, max=100, soft_min=-100, soft_max=100, step=1, precision=2)
150
+
151
+ def draw(self, context):
152
+ self.layout.label(text="These settings are not saved until you press the (Save User Settings) button", icon='QUESTION')
153
+ self.layout.prop(self, 'cm3d2_path', icon_value=common.preview_collections['main']['KISS'].icon_id)
154
+ self.layout.prop(self, 'backup_ext', icon='FILE_BACKUP')
155
+
156
+ box = self.layout.box()
157
+ box.label(text=".Model File", icon='MESH_ICOSPHERE')
158
+ row = box.row()
159
+ row.prop(self, 'scale', icon='MAN_SCALE')
160
+ row.prop(self, 'is_convert_bone_weight_names', icon='BLENDER')
161
+ box.prop(self, 'model_default_path', icon='FILESEL', text="Initial folder when selecting files")
162
+
163
+ box = self.layout.box()
164
+ box.label(text=".anm File", icon='POSE_HLT')
165
+ box.prop(self, 'anm_default_path', icon='FILESEL', text="Initial folder when selecting files")
166
+
167
+ box = self.layout.box()
168
+ box.label(text=".tex File", icon='FILE_IMAGE')
169
+ box.prop(self, 'tex_default_path', icon='FILESEL', text="Initial folder when selecting files")
170
+
171
+ box = self.layout.box()
172
+ box.label(text=".mate File", icon='MATERIAL')
173
+ box.prop(self, 'mate_unread_same_value', icon='DISCLOSURE_TRI_DOWN')
174
+ box.prop(self, 'mate_default_path', icon='FILESEL', text="Initial folder when selecting files")
175
+
176
+ box = self.layout.box()
177
+ box.label(text="Search for Tex File", icon='BORDERMOVE')
178
+ box.prop(self, 'is_replace_cm3d2_tex', icon='VIEWZOOM')
179
+ box.prop(self, 'default_tex_path0', icon='LAYER_ACTIVE', text="Part 1")
180
+ box.prop(self, 'default_tex_path1', icon='LAYER_ACTIVE', text="Part 2")
181
+ box.prop(self, 'default_tex_path2', icon='LAYER_ACTIVE', text="Part 3")
182
+ box.prop(self, 'default_tex_path3', icon='LAYER_ACTIVE', text="Part 4")
183
+
184
+ box = self.layout.box()
185
+ box.label(text="Defaults for when a new CM3d2 Material is Created.", icon='MATERIAL')
186
+ box.prop(self, 'new_mate_tex_color', icon='COLOR')
187
+ row = box.row()
188
+ row.prop(self, 'new_mate_toonramp_name', icon='BRUSH_TEXFILL')
189
+ row.prop(self, 'new_mate_toonramp_path', icon='ANIM')
190
+ row = box.row()
191
+ row.prop(self, 'new_mate_shadowratetoon_name', icon='BRUSH_TEXMASK')
192
+ row.prop(self, 'new_mate_shadowratetoon_path', icon='ANIM')
193
+ row = box.row()
194
+ row.prop(self, 'new_mate_color', icon='COLOR')
195
+ row.prop(self, 'new_mate_shadowcolor', icon='IMAGE_ALPHA')
196
+ row.prop(self, 'new_mate_rimcolor', icon='MATCAP_07')
197
+ row.prop(self, 'new_mate_outlinecolor', icon='SOLID')
198
+ row = box.row()
199
+ row.prop(self, 'new_mate_shininess', icon='MATCAP_05')
200
+ row.prop(self, 'new_mate_outlinewidth', icon='SOLID')
201
+ row.prop(self, 'new_mate_rimpower', icon='MATCAP_14')
202
+ row.prop(self, 'new_mate_rimshift', icon='ARROW_LEFTRIGHT')
203
+ row.prop(self, 'new_mate_hirate')
204
+ row.prop(self, 'new_mate_hipow')
205
+
206
+ row = self.layout.row()
207
+ row.operator('script.update_cm3d2_converter', icon='FILE_REFRESH')
208
+ row.menu('INFO_MT_help_CM3D2_Converter_RSS', icon='INFO')
209
+
210
+ # プラグインをインストールしたときの処理
211
+ def register():
212
+ bpy.utils.register_module(__name__)
213
+
214
+ bpy.types.INFO_MT_file_import.append(model_import.menu_func)
215
+ bpy.types.INFO_MT_file_export.append(model_export.menu_func)
216
+
217
+ bpy.types.INFO_MT_file_import.append(anm_import.menu_func)
218
+ bpy.types.INFO_MT_file_export.append(anm_export.menu_func)
219
+
220
+ bpy.types.IMAGE_MT_image.append(tex_import.menu_func)
221
+ bpy.types.IMAGE_MT_image.append(tex_export.menu_func)
222
+
223
+ bpy.types.TEXT_MT_text.append(mate_import.TEXT_MT_text)
224
+ bpy.types.TEXT_MT_text.append(mate_export.TEXT_MT_text)
225
+
226
+ bpy.types.DATA_PT_context_arm.append(misc_DATA_PT_context_arm.menu_func)
227
+ bpy.types.DATA_PT_modifiers.append(misc_DATA_PT_modifiers.menu_func)
228
+ bpy.types.DATA_PT_vertex_groups.append(misc_DATA_PT_vertex_groups.menu_func)
229
+ bpy.types.IMAGE_HT_header.append(misc_IMAGE_HT_header.menu_func)
230
+ bpy.types.IMAGE_PT_image_properties.append(misc_IMAGE_PT_image_properties.menu_func)
231
+ bpy.types.INFO_HT_header.append(misc_INFO_HT_header.menu_func)
232
+ bpy.types.INFO_MT_add.append(misc_INFO_MT_add.menu_func)
233
+ bpy.types.INFO_MT_curve_add.append(misc_INFO_MT_curve_add.menu_func)
234
+ bpy.types.INFO_MT_help.append(misc_INFO_MT_help.menu_func)
235
+ bpy.types.MATERIAL_PT_context_material.append(misc_MATERIAL_PT_context_material.menu_func)
236
+ bpy.types.MESH_MT_shape_key_specials.append(misc_MESH_MT_shape_key_specials.menu_func)
237
+ bpy.types.MESH_MT_vertex_group_specials.append(misc_MESH_MT_vertex_group_specials.menu_func)
238
+ bpy.types.OBJECT_PT_context_object.append(misc_OBJECT_PT_context_object.menu_func)
239
+ bpy.types.OBJECT_PT_transform.append(misc_OBJECT_PT_transform.menu_func)
240
+ bpy.types.RENDER_PT_bake.append(misc_RENDER_PT_bake.menu_func)
241
+ bpy.types.RENDER_PT_render.append(misc_RENDER_PT_render.menu_func)
242
+ bpy.types.TEXTURE_PT_context_texture.append(misc_TEXTURE_PT_context_texture.menu_func)
243
+ bpy.types.TEXT_HT_header.append(misc_TEXT_HT_header.menu_func)
244
+ bpy.types.VIEW3D_MT_edit_mesh_specials.append(misc_VIEW3D_MT_edit_mesh_specials.menu_func)
245
+ bpy.types.VIEW3D_MT_pose_apply.append(misc_VIEW3D_MT_pose_apply.menu_func)
246
+ bpy.types.VIEW3D_PT_tools_weightpaint.append(misc_VIEW3D_PT_tools_weightpaint.menu_func)
247
+
248
+ pcoll = bpy.utils.previews.new()
249
+ dir = os.path.dirname(__file__)
250
+ pcoll.load('KISS', os.path.join(dir, "kiss.png"), 'IMAGE')
251
+ common.preview_collections['main'] = pcoll
252
+
253
+ system = bpy.context.user_preferences.system
254
+ if not system.use_international_fonts:
255
+ system.use_international_fonts = True
256
+ if not system.use_translate_interface:
257
+ system.use_translate_interface = True
258
+ try:
259
+ import locale
260
+ if system.language == 'DEFAULT' and locale.getdefaultlocale()[0] != 'ja_JP':
261
+ system.language = 'en_US'
262
+ except: pass
263
+
264
+ # プラグインをアンインストールしたときの処理
265
+ def unregister():
266
+ bpy.utils.unregister_module(__name__)
267
+
268
+ bpy.types.INFO_MT_file_import.remove(model_import.menu_func)
269
+ bpy.types.INFO_MT_file_export.remove(model_export.menu_func)
270
+
271
+ bpy.types.INFO_MT_file_import.remove(anm_import.menu_func)
272
+ bpy.types.INFO_MT_file_export.remove(anm_export.menu_func)
273
+
274
+ bpy.types.IMAGE_MT_image.remove(tex_import.menu_func)
275
+ bpy.types.IMAGE_MT_image.remove(tex_export.menu_func)
276
+
277
+ bpy.types.TEXT_MT_text.remove(mate_import.TEXT_MT_text)
278
+ bpy.types.TEXT_MT_text.remove(mate_export.TEXT_MT_text)
279
+
280
+ bpy.types.DATA_PT_context_arm.remove(misc_DATA_PT_context_arm.menu_func)
281
+ bpy.types.DATA_PT_modifiers.remove(misc_DATA_PT_modifiers.menu_func)
282
+ bpy.types.DATA_PT_vertex_groups.remove(misc_DATA_PT_vertex_groups.menu_func)
283
+ bpy.types.IMAGE_HT_header.remove(misc_IMAGE_HT_header.menu_func)
284
+ bpy.types.IMAGE_PT_image_properties.remove(misc_IMAGE_PT_image_properties.menu_func)
285
+ bpy.types.INFO_HT_header.remove(misc_INFO_HT_header.menu_func)
286
+ bpy.types.INFO_MT_add.remove(misc_INFO_MT_add.menu_func)
287
+ bpy.types.INFO_MT_curve_add.remove(misc_INFO_MT_curve_add.menu_func)
288
+ bpy.types.INFO_MT_help.remove(misc_INFO_MT_help.menu_func)
289
+ bpy.types.MATERIAL_PT_context_material.remove(misc_MATERIAL_PT_context_material.menu_func)
290
+ bpy.types.MESH_MT_shape_key_specials.remove(misc_MESH_MT_shape_key_specials.menu_func)
291
+ bpy.types.MESH_MT_vertex_group_specials.remove(misc_MESH_MT_vertex_group_specials.menu_func)
292
+ bpy.types.OBJECT_PT_context_object.remove(misc_OBJECT_PT_context_object.menu_func)
293
+ bpy.types.OBJECT_PT_transform.remove(misc_OBJECT_PT_transform.menu_func)
294
+ bpy.types.RENDER_PT_bake.remove(misc_RENDER_PT_bake.menu_func)
295
+ bpy.types.RENDER_PT_render.remove(misc_RENDER_PT_render.menu_func)
296
+ bpy.types.TEXTURE_PT_context_texture.remove(misc_TEXTURE_PT_context_texture.menu_func)
297
+ bpy.types.TEXT_HT_header.remove(misc_TEXT_HT_header.menu_func)
298
+ bpy.types.VIEW3D_MT_edit_mesh_specials.remove(misc_VIEW3D_MT_edit_mesh_specials.menu_func)
299
+ bpy.types.VIEW3D_MT_pose_apply.remove(misc_VIEW3D_MT_pose_apply.menu_func)
300
+ bpy.types.VIEW3D_PT_tools_weightpaint.remove(misc_VIEW3D_PT_tools_weightpaint.menu_func)
301
+
302
+ for pcoll in common.preview_collections.values():
303
+ bpy.utils.previews.remove(pcoll)
304
+ common.preview_collections.clear()
305
+
306
+ bpy.app.translations.unregister(__name__)
307
+
308
+ # メイン関数
309
+ if __name__ == "__main__":
310
+ register()
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/anm_export.py ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bpy, mathutils
2
+ import struct, re, math, unicodedata
3
+ from . import common
4
+
5
+ # メインオペレーター
6
+ class export_cm3d2_anm(bpy.types.Operator):
7
+ bl_idname = 'export_anim.export_cm3d2_anm'
8
+ bl_label = "CM3D2 Motion (.anm) (Work In Progress)"
9
+ bl_description = "Allows you to export a pose to a .anm file."
10
+ bl_options = {'REGISTER'}
11
+
12
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
13
+ filename_ext = ".anm"
14
+ filter_glob = bpy.props.StringProperty(default="*.anm", options={'HIDDEN'})
15
+
16
+ scale = bpy.props.FloatProperty(name="Scale", default=0.2, min=0.1, max=100, soft_min=0.1, soft_max=100, step=100, precision=1, description="Scale of the .anm at the time of export")
17
+ is_backup = bpy.props.BoolProperty(name="Backup", default=True, description="Will backup overwritten files.")
18
+ version = bpy.props.IntProperty(name="Version", default=1000, min=1000, max=1111, soft_min=1000, soft_max=1111, step=1)
19
+
20
+ frame_start = bpy.props.IntProperty(name="Starting Frame", default=0, min=0, max=99999, soft_min=0, soft_max=99999, step=1)
21
+ frame_end = bpy.props.IntProperty(name="Last Frame", default=0, min=0, max=99999, soft_min=0, soft_max=99999, step=1)
22
+ key_frame_count = bpy.props.IntProperty(name="Number of key frames", default=1, min=1, max=99999, soft_min=1, soft_max=99999, step=1)
23
+ time_scale = bpy.props.FloatProperty(name="Playback Speed", default=1.0, min=0.1, max=10.0, soft_min=0.1, soft_max=10.0, step=10, precision=1)
24
+ is_keyframe_clean = bpy.props.BoolProperty(name="Clean Keyframes", default=True)
25
+ is_smooth_handle = bpy.props.BoolProperty(name="Smooth Transitions", default=True)
26
+
27
+ items = [
28
+ ('ARMATURE', "Armature", "", 'OUTLINER_OB_ARMATURE', 1),
29
+ ('ARMATURE_PROPERTY', "Armature Data", "", 'ARMATURE_DATA', 2),
30
+ ]
31
+ bone_parent_from = bpy.props.EnumProperty(items=items, name="Bone Parent From", default='ARMATURE_PROPERTY')
32
+
33
+ is_remove_alone_bone = bpy.props.BoolProperty(name="Remove Loose Bones", default=True)
34
+ is_remove_ik_bone = bpy.props.BoolProperty(name="Remove IK Bones", default=True)
35
+ is_remove_serial_number_bone = bpy.props.BoolProperty(name="Remove Duplicate Numbers", default=True)
36
+ is_remove_japanese_bone = bpy.props.BoolProperty(name="Remove Japanese Characters from Bones", default=True)
37
+
38
+ @classmethod
39
+ def poll(cls, context):
40
+ ob = context.active_object
41
+ if ob:
42
+ if ob.type == 'ARMATURE':
43
+ return True
44
+ return False
45
+
46
+ def invoke(self, context, event):
47
+ if common.preferences().anm_default_path:
48
+ self.filepath = common.default_cm3d2_dir(common.preferences().anm_default_path, "", "anm")
49
+ else:
50
+ self.filepath = common.default_cm3d2_dir(common.preferences().anm_export_path, "", "anm")
51
+ self.frame_start = context.scene.frame_start
52
+ self.frame_end = context.scene.frame_end
53
+ self.scale = 1.0 / common.preferences().scale
54
+ self.is_backup = bool(common.preferences().backup_ext)
55
+ self.key_frame_count = (context.scene.frame_end - context.scene.frame_start) + 1
56
+
57
+ ob = context.active_object
58
+ arm = ob.data
59
+ if "BoneData:0" in arm:
60
+ self.bone_parent_from = 'ARMATURE_PROPERTY'
61
+ else:
62
+ self.bone_parent_from = 'ARMATURE'
63
+
64
+ context.window_manager.fileselect_add(self)
65
+ return {'RUNNING_MODAL'}
66
+
67
+ def draw(self, context):
68
+ self.layout.prop(self, 'scale')
69
+
70
+ box = self.layout.box()
71
+ box.prop(self, 'is_backup', icon='FILE_BACKUP')
72
+ box.prop(self, 'version')
73
+
74
+ box = self.layout.box()
75
+ sub_box = box.box()
76
+ row = sub_box.row()
77
+ row.prop(self, 'frame_start')
78
+ row.prop(self, 'frame_end')
79
+ sub_box.prop(self, 'key_frame_count')
80
+ sub_box.prop(self, 'time_scale')
81
+ sub_box.prop(self, 'is_keyframe_clean', icon='DISCLOSURE_TRI_DOWN')
82
+ sub_box.prop(self, 'is_smooth_handle', icon='SMOOTHCURVE')
83
+
84
+ sub_box = box.box()
85
+ sub_box.label("Destination of bone parent information", icon='FILE_PARENT')
86
+ sub_box.prop(self, 'bone_parent_from', icon='FILE_PARENT', expand=True)
87
+
88
+ sub_box = box.box()
89
+ sub_box.label("Bones to Exclude", icon='X')
90
+ column = sub_box.column(align=True)
91
+ column.prop(self, 'is_remove_alone_bone', icon='UNLINKED')
92
+ column.prop(self, 'is_remove_ik_bone', icon='CONSTRAINT_BONE')
93
+ column.prop(self, 'is_remove_serial_number_bone', icon='DOTSDOWN')
94
+ column.prop(self, 'is_remove_japanese_bone', icon='MATCAP_13')
95
+
96
+ def execute(self, context):
97
+ common.preferences().anm_export_path = self.filepath
98
+
99
+ try:
100
+ file = common.open_temporary(self.filepath, 'wb', is_backup=self.is_backup)
101
+ except:
102
+ self.report(type={'ERROR'}, message="Failed to open this file, possibily inaccessible.")
103
+ return {'CANCELLED'}
104
+
105
+ try:
106
+ with file:
107
+ self.write_animation(context, file)
108
+ except common.CM3D2ExportException as e:
109
+ self.report(type={'ERROR'}, message=str(e))
110
+ return {'CANCELLED'}
111
+
112
+ return {'FINISHED'}
113
+
114
+ def write_animation(self, context, file):
115
+ ob = context.active_object
116
+ arm = ob.data
117
+ pose = ob.pose
118
+ fps = context.scene.render.fps
119
+
120
+ common.write_str(file, 'CM3D2_ANIM')
121
+ file.write(struct.pack('<i', self.version))
122
+
123
+ bone_parents = {}
124
+ if self.bone_parent_from == 'ARMATURE_PROPERTY':
125
+ for i in range(9999):
126
+ name = "BoneData:" + str(i)
127
+ if name not in arm: continue
128
+ elems = arm[name].split(",")
129
+ if len(elems) != 5: continue
130
+ if elems[0] in arm.bones:
131
+ if elems[2] in arm.bones:
132
+ bone_parents[elems[0]] = arm.bones[elems[2]]
133
+ else:
134
+ bone_parents[elems[0]] = None
135
+ for bone in arm.bones:
136
+ if bone.name in bone_parents: continue
137
+ bone_parents[bone.name] = bone.parent
138
+ else:
139
+ for bone in arm.bones:
140
+ bone_parents[bone.name] = bone.parent
141
+
142
+ def is_japanese(string):
143
+ for ch in string:
144
+ name = unicodedata.name(ch)
145
+ if "CJK UNIFIED" in name \
146
+ or "HIRAGANA" in name \
147
+ or "KATAKANA" in name:
148
+ return True
149
+ return False
150
+ bones = []
151
+ already_bone_names = []
152
+ bones_queue = arm.bones[:]
153
+ while len(bones_queue):
154
+ bone = bones_queue.pop(0)
155
+
156
+ if not bone_parents[bone.name]:
157
+ already_bone_names.append(bone.name)
158
+ if self.is_remove_serial_number_bone:
159
+ if re.search(r"\.\d{3,}$", bone.name): continue
160
+ if self.is_remove_japanese_bone:
161
+ if is_japanese(bone.name): continue
162
+ if self.is_remove_alone_bone and len(bone.children) == 0:
163
+ continue
164
+ bones.append(bone)
165
+ continue
166
+ elif bone_parents[bone.name].name in already_bone_names:
167
+ already_bone_names.append(bone.name)
168
+ if self.is_remove_serial_number_bone:
169
+ if re.search(r"\.\d{3,}$", bone.name): continue
170
+ if self.is_remove_japanese_bone:
171
+ if is_japanese(bone.name): continue
172
+ if self.is_remove_ik_bone:
173
+ if "_ik_" in bone.name.lower(): continue
174
+ if re.search(r"_nub$", bone.name.lower()): continue
175
+ if re.search(r"Nub$", bone.name): continue
176
+ bones.append(bone)
177
+ continue
178
+
179
+ bones_queue.append(bone)
180
+
181
+ anm_data_raw = {}
182
+ class KeyFrame:
183
+ def __init__(self, time, value):
184
+ self.time = time
185
+ self.value = value
186
+ same_locs = {}
187
+ same_rots = {}
188
+ pre_rots = {}
189
+ for key_frame_index in range(self.key_frame_count):
190
+ if self.key_frame_count == 1:
191
+ frame = 0.0
192
+ else:
193
+ frame = (self.frame_end - self.frame_start) / (self.key_frame_count - 1) * key_frame_index + self.frame_start
194
+ context.scene.frame_set(int(frame), frame - int(frame))
195
+ context.scene.update()
196
+
197
+ time = frame / fps * (1.0 / self.time_scale)
198
+
199
+ for bone in bones:
200
+ if bone.name not in anm_data_raw:
201
+ anm_data_raw[bone.name] = {"LOC":{}, "ROT":{}}
202
+ same_locs[bone.name] = []
203
+ same_rots[bone.name] = []
204
+
205
+ pose_bone = pose.bones[bone.name]
206
+
207
+ pose_mat = ob.convert_space(pose_bone, pose_bone.matrix, 'POSE', 'WORLD')
208
+ if bone_parents[bone.name]:
209
+ parent_mat = ob.convert_space(pose.bones[bone_parents[bone.name].name], pose.bones[bone_parents[bone.name].name].matrix, 'POSE', 'WORLD')
210
+ pose_mat = parent_mat.inverted() * pose_mat
211
+
212
+ loc = pose_mat.to_translation() * self.scale
213
+ rot = pose_mat.to_quaternion()
214
+
215
+ if bone.name in pre_rots:
216
+ if 5.0 < pre_rots[bone.name].rotation_difference(rot).angle:
217
+ rot.w, rot.x, rot.y, rot.z = -rot.w, -rot.x, -rot.y, -rot.z
218
+ pre_rots[bone.name] = rot.copy()
219
+
220
+ if bone_parents[bone.name]:
221
+ loc.x, loc.y, loc.z = -loc.y, -loc.x, loc.z
222
+ rot.w, rot.x, rot.y, rot.z = rot.w, rot.y, rot.x, -rot.z
223
+ else:
224
+ loc.x, loc.y, loc.z = -loc.x, loc.z, -loc.y
225
+
226
+ fix_quat = mathutils.Euler((0, 0, math.radians(-90)), 'XYZ').to_quaternion()
227
+ fix_quat2 = mathutils.Euler((math.radians(-90), 0, 0), 'XYZ').to_quaternion()
228
+ rot = rot * fix_quat * fix_quat2
229
+
230
+ rot.w, rot.x, rot.y, rot.z = -rot.y, -rot.z, -rot.x, rot.w
231
+
232
+ if not self.is_keyframe_clean or key_frame_index == 0 or key_frame_index == self.key_frame_count - 1:
233
+ anm_data_raw[bone.name]["LOC"][time] = loc.copy()
234
+ anm_data_raw[bone.name]["ROT"][time] = rot.copy()
235
+
236
+ if self.is_keyframe_clean:
237
+ same_locs[bone.name].append(KeyFrame(time, loc.copy()))
238
+ same_rots[bone.name].append(KeyFrame(time, rot.copy()))
239
+ else:
240
+ def is_mismatch(a, b):
241
+ return 0.000001 < abs(a - b)
242
+
243
+ a, b = loc, same_locs[bone.name][-1].value
244
+ if is_mismatch(a.x, b.x) or is_mismatch(a.y, b.y) or is_mismatch(a.z, b.z):
245
+ if 2 <= len(same_locs[bone.name]):
246
+ anm_data_raw[bone.name]["LOC"][same_locs[bone.name][-1].time] = same_locs[bone.name][-1].value.copy()
247
+ anm_data_raw[bone.name]["LOC"][time] = loc.copy()
248
+ same_locs[bone.name] = [KeyFrame(time, loc.copy())]
249
+ else:
250
+ same_locs[bone.name].append(KeyFrame(time, loc.copy()))
251
+
252
+ a, b = rot, same_rots[bone.name][-1].value
253
+ if is_mismatch(a.w, b.w) or is_mismatch(a.x, b.x) or is_mismatch(a.y, b.y) or is_mismatch(a.z, b.z):
254
+ if 2 <= len(same_rots[bone.name]):
255
+ anm_data_raw[bone.name]["ROT"][same_rots[bone.name][-1].time] = same_rots[bone.name][-1].value.copy()
256
+ anm_data_raw[bone.name]["ROT"][time] = rot.copy()
257
+ same_rots[bone.name] = [KeyFrame(time, rot.copy())]
258
+ else:
259
+ same_rots[bone.name].append(KeyFrame(time, rot.copy()))
260
+
261
+ anm_data = {}
262
+ for bone_name, channels in anm_data_raw.items():
263
+ anm_data[bone_name] = {100:{}, 101:{}, 102:{}, 103:{}, 104:{}, 105:{}, 106:{}}
264
+ for time, loc in channels["LOC"].items():
265
+ anm_data[bone_name][104][time] = loc.x
266
+ anm_data[bone_name][105][time] = loc.y
267
+ anm_data[bone_name][106][time] = loc.z
268
+ for time, rot in channels["ROT"].items():
269
+ anm_data[bone_name][100][time] = rot.x
270
+ anm_data[bone_name][101][time] = rot.y
271
+ anm_data[bone_name][102][time] = rot.z
272
+ anm_data[bone_name][103][time] = rot.w
273
+
274
+ for bone in bones:
275
+ file.write(struct.pack('<?', True))
276
+
277
+ bone_names = [bone.name]
278
+ current_bone = bone
279
+ while bone_parents[current_bone.name]:
280
+ bone_names.append(bone_parents[current_bone.name].name)
281
+ current_bone = bone_parents[current_bone.name]
282
+
283
+ bone_names.reverse()
284
+ common.write_str(file, "/".join(bone_names))
285
+
286
+ for channel_id, keyframes in sorted(anm_data[bone.name].items(), key=lambda x: x[0]):
287
+ file.write(struct.pack('<B', channel_id))
288
+ file.write(struct.pack('<i', len(keyframes)))
289
+
290
+ keyframes_list = sorted(keyframes.items(), key=lambda x: x[0])
291
+ for i in range(len(keyframes_list)):
292
+ x = keyframes_list[i][0]
293
+ y = keyframes_list[i][1]
294
+
295
+ if len(keyframes_list) <= 1:
296
+ file.write(struct.pack('<f', x))
297
+ file.write(struct.pack('<f', y))
298
+ file.write(struct.pack('<2f', 0.0, 0.0))
299
+ continue
300
+
301
+ if i == 0:
302
+ prev_x = x - (keyframes_list[i+1][0] - x)
303
+ prev_y = y - (keyframes_list[i+1][1] - y)
304
+ next_x = keyframes_list[i+1][0]
305
+ next_y = keyframes_list[i+1][1]
306
+ elif i == len(keyframes_list) - 1:
307
+ prev_x = keyframes_list[i-1][0]
308
+ prev_y = keyframes_list[i-1][1]
309
+ next_x = x + (x - keyframes_list[i-1][0])
310
+ next_y = y + (y - keyframes_list[i-1][1])
311
+ else:
312
+ prev_x = keyframes_list[i-1][0]
313
+ prev_y = keyframes_list[i-1][1]
314
+ next_x = keyframes_list[i+1][0]
315
+ next_y = keyframes_list[i+1][1]
316
+
317
+ prev_rad = (prev_y - y) / (prev_x - x)
318
+ next_rad = (next_y - y) / (next_x - x)
319
+ join_rad = (prev_rad + next_rad) / 2
320
+
321
+ file.write(struct.pack('<f', x))
322
+ file.write(struct.pack('<f', y))
323
+
324
+ if self.is_smooth_handle:
325
+ file.write(struct.pack('<2f', join_rad, join_rad))
326
+ #file.write(struct.pack('<2f', prev_rad, next_rad))
327
+ else:
328
+ file.write(struct.pack('<2f', 0.0, 0.0))
329
+
330
+ file.write(struct.pack('<?', False))
331
+
332
+ # メニューに登録する関数
333
+ def menu_func(self, context):
334
+ self.layout.operator(export_cm3d2_anm.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/anm_import.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, re, bpy, math, struct, os.path, mathutils
2
+ from . import common
3
+
4
+ # メインオペレーター
5
+ class import_cm3d2_anm(bpy.types.Operator):
6
+ bl_idname = 'import_anim.import_cm3d2_anm'
7
+ bl_label = "CM3D2 Animation (.anm)"
8
+ bl_description = "Loads a CM3D2 .anm file."
9
+ bl_options = {'REGISTER'}
10
+
11
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
12
+ filename_ext = ".anm"
13
+ filter_glob = bpy.props.StringProperty(default="*.anm", options={'HIDDEN'})
14
+
15
+ scale = bpy.props.FloatProperty(name="Scale", default=5, min=0.1, max=100, soft_min=0.1, soft_max=100, step=100, precision=1, description="The scale at the time of import.")
16
+
17
+ remove_pre_animation = bpy.props.BoolProperty(name="Remove previous Animation", default=True)
18
+ set_frame = bpy.props.BoolProperty(name="Set Frame", default=True)
19
+ ignore_automatic_bone = bpy.props.BoolProperty(name="Exclude Twister Bones", default=True)
20
+
21
+ is_location = bpy.props.BoolProperty(name="Position", default=True)
22
+ is_rotation = bpy.props.BoolProperty(name="Rotation", default=True)
23
+ is_scale = bpy.props.BoolProperty(name="Bigger/Smaller", default=False)
24
+
25
+
26
+ @classmethod
27
+ def poll(cls, context):
28
+ ob = context.active_object
29
+ if ob:
30
+ if ob.type == 'ARMATURE':
31
+ return True
32
+ return False
33
+
34
+ def invoke(self, context, event):
35
+ if common.preferences().anm_default_path:
36
+ self.filepath = common.default_cm3d2_dir(common.preferences().anm_default_path, "", "anm")
37
+ else:
38
+ self.filepath = common.default_cm3d2_dir(common.preferences().anm_import_path, "", "anm")
39
+ self.scale = common.preferences().scale
40
+ context.window_manager.fileselect_add(self)
41
+ return {'RUNNING_MODAL'}
42
+
43
+ def draw(self, context):
44
+ self.layout.prop(self, 'scale')
45
+ box = self.layout.box()
46
+ box.prop(self, 'remove_pre_animation', icon='DISCLOSURE_TRI_DOWN')
47
+ box.prop(self, 'set_frame', icon='NEXT_KEYFRAME')
48
+ box.prop(self, 'ignore_automatic_bone', icon='X')
49
+ box = self.layout.box()
50
+ box.label("Animation Information")
51
+ column = box.column(align=True)
52
+ column.prop(self, 'is_location', icon='MAN_TRANS')
53
+ column.prop(self, 'is_rotation', icon='MAN_ROT')
54
+ row = column.row()
55
+ row.prop(self, 'is_scale', icon='MAN_SCALE')
56
+ row.enabled = False
57
+
58
+ def execute(self, context):
59
+ common.preferences().anm_import_path = self.filepath
60
+
61
+ try:
62
+ file = open(self.filepath, 'rb')
63
+ except:
64
+ self.report(type={'ERROR'}, message="Failed to open the file. It's either inaccessible or the file does not exist")
65
+ return {'CANCELLED'}
66
+
67
+ # ヘッダー
68
+ ext = common.read_str(file)
69
+ if ext != 'CM3D2_ANIM':
70
+ self.report(type={'ERROR'}, message="This is not a CM3D2 animation file.")
71
+ return {'CANCELLED'}
72
+ struct.unpack('<i', file.read(4))[0]
73
+
74
+ global_flag = struct.unpack('<?', file.read(1))[0]
75
+
76
+ anm_data = {}
77
+
78
+ for anm_data_index in range(9**9):
79
+ path = common.read_str(file)
80
+
81
+ base_bone_name = path.split('/')[-1]
82
+ if base_bone_name not in anm_data:
83
+ anm_data[base_bone_name] = {'path':path}
84
+ anm_data[base_bone_name]['channels'] = {}
85
+
86
+ for channel_index in range(9**9):
87
+ channel_id = struct.unpack('<B', file.read(1))[0]
88
+ channel_id_str = channel_id
89
+ if channel_id <= 1:
90
+ break
91
+ anm_data[base_bone_name]['channels'][channel_id_str] = []
92
+ channel_data_count = struct.unpack('<i', file.read(4))[0]
93
+ for channel_data_index in range(channel_data_count):
94
+ frame = struct.unpack('<f', file.read(4))[0]
95
+ data = struct.unpack('<3f', file.read(4*3))
96
+
97
+ anm_data[base_bone_name]['channels'][channel_id_str].append({'frame':frame, 'f0':data[0], 'f1':data[1], 'f2':data[2]})
98
+
99
+ if channel_id == 0:
100
+ break
101
+
102
+ fps = context.scene.render.fps
103
+
104
+ ob = context.active_object
105
+ arm = ob.data
106
+ pose = ob.pose
107
+
108
+ if self.remove_pre_animation:
109
+ anim = ob.animation_data
110
+ if anim:
111
+ if anim.action:
112
+ for fcurve in anim.action.fcurves:
113
+ anim.action.fcurves.remove(fcurve)
114
+
115
+ max_frame = 0
116
+ bpy.ops.object.mode_set(mode='OBJECT')
117
+ for bone_name, bone_data in anm_data.items():
118
+
119
+ if self.ignore_automatic_bone:
120
+ if re.match(r"Kata_[RL]", bone_name): continue
121
+ if re.match(r"Uppertwist1_[RL]", bone_name): continue
122
+ if re.match(r"momoniku_[RL]", bone_name): continue
123
+
124
+ if bone_name not in pose.bones:
125
+ bone_name = common.decode_bone_name(bone_name)
126
+ if bone_name not in pose.bones:
127
+ continue
128
+ bone = arm.bones[bone_name]
129
+ pose_bone = pose.bones[bone_name]
130
+
131
+ locs = {}
132
+ quats = {}
133
+ for channel_id, channel_data in bone_data['channels'].items():
134
+
135
+ if channel_id in [100, 101, 102, 103]:
136
+ for data in channel_data:
137
+ frame = data['frame']
138
+ if frame not in quats:
139
+ quats[frame] = [None, None, None, None]
140
+
141
+ if channel_id == 103:
142
+ quats[frame][0] = data['f0']
143
+ elif channel_id == 100:
144
+ quats[frame][1] = data['f0']
145
+ elif channel_id == 101:
146
+ quats[frame][2] = data['f0']
147
+ elif channel_id == 102:
148
+ quats[frame][3] = data['f0']
149
+
150
+ elif channel_id in [104, 105, 106]:
151
+ for data in channel_data:
152
+ frame = data['frame']
153
+ if frame not in locs:
154
+ locs[frame] = [None, None, None]
155
+
156
+ if channel_id == 104:
157
+ locs[frame][0] = data['f0']
158
+ elif channel_id == 105:
159
+ locs[frame][1] = data['f0']
160
+ elif channel_id == 106:
161
+ locs[frame][2] = data['f0']
162
+
163
+ if self.is_location:
164
+ for frame, loc in locs.items():
165
+ loc = mathutils.Vector(loc) * self.scale
166
+ bone_loc = bone.head_local.copy()
167
+
168
+ if bone.parent:
169
+ loc.x, loc.y, loc.z = -loc.y, -loc.x, loc.z
170
+
171
+ bone_loc = bone_loc - bone.parent.head_local
172
+ bone_loc.rotate(bone.parent.matrix_local.to_quaternion().inverted())
173
+ else:
174
+ loc.x, loc.y, loc.z = loc.x, loc.z, loc.y
175
+
176
+ result_loc = loc - bone_loc
177
+ pose_bone.location = result_loc.copy()
178
+
179
+ pose_bone.keyframe_insert('location', frame=frame * fps)
180
+ if max_frame < frame * fps:
181
+ max_frame = frame * fps
182
+
183
+ if self.is_rotation:
184
+ for frame, quat in quats.items():
185
+ quat = mathutils.Quaternion(quat)
186
+ bone_quat = bone.matrix.to_quaternion()
187
+
188
+ if bone.parent:
189
+ quat.w, quat.x, quat.y, quat.z = quat.w, quat.y, quat.x, -quat.z
190
+ else:
191
+ quat.w, quat.x, quat.y, quat.z = quat.w, quat.y, quat.x, -quat.z
192
+
193
+ fix_quat = mathutils.Euler((math.radians(90), math.radians(90), 0.0), 'XYZ').to_quaternion()
194
+ fix_quat2 = mathutils.Euler((0.0, math.radians(-90), 0.0), 'XYZ').to_quaternion()
195
+ quat = fix_quat * quat
196
+
197
+ result_quat = bone_quat.inverted() * quat
198
+ pose_bone.rotation_quaternion = result_quat.copy()
199
+
200
+ pose_bone.keyframe_insert('rotation_quaternion', frame=frame * fps)
201
+ if max_frame < frame * fps:
202
+ max_frame = frame * fps
203
+
204
+ if self.set_frame:
205
+ context.scene.frame_start = 0
206
+ context.scene.frame_end = max_frame
207
+ context.scene.frame_set(0)
208
+
209
+ return {'FINISHED'}
210
+
211
+ # メニューに登録する関数
212
+ def menu_func(self, context):
213
+ self.layout.operator(import_cm3d2_anm.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/append_data.blend ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:beea77137dea25c59f59e6865dda2f37d3f5810630e76cf28cefbf510bca20e7
3
+ size 26923656
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/common.py ADDED
@@ -0,0 +1,635 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bpy, os, re, math, bmesh, struct, shutil, mathutils
2
+ from . import fileutil
3
+
4
+ # アドオン情報
5
+ bl_info = {
6
+ "name" : "CM3D2 Converter",
7
+ "author" : "@saidenka_cm3d2",
8
+ "version" : (2017, 5, 16, 21, 39, 32),
9
+ "blender" : (2, 78, 0),
10
+ "location" : "File> Import / Export > CM3D2 Model (.model)",
11
+ "description" : "Import/Export .Model files for CM3D2",
12
+ "warning" : "",
13
+ "wiki_url" : "https://github.com/CM3Duser/Blender-CM3D2-Converter",
14
+ "tracker_url" : "https://twitter.com/saidenka_cm3d2",
15
+ "category" : "Import-Export"
16
+ }
17
+
18
+ addon_name = "CM3D2 Converter"
19
+ preview_collections = {}
20
+
21
+ # このアドオンの設定値群を呼び出す
22
+ def preferences():
23
+ return bpy.context.user_preferences.addons[__name__.split('.')[0]].preferences
24
+
25
+ # データ名末尾の「.001」などを削除
26
+ def remove_serial_number(name, enable=True):
27
+ return re.sub(r'\.\d{3,}$', "", name) if enable else name
28
+
29
+ # 文字列の左右端から空白を削除
30
+ def line_trim(line, enable=True):
31
+ return line.strip('  \t\r\n') if enable else line
32
+
33
+ # CM3D2専用ファイル用の文字列書き込み
34
+ def write_str(file, raw_str):
35
+ b_str = format(len(raw_str.encode('utf-8')), 'b')
36
+ for i in range(9):
37
+ if 7 < len(b_str):
38
+ file.write( struct.pack('<B', int("1"+b_str[-7:], 2)) )
39
+ b_str = b_str[:-7]
40
+ else:
41
+ file.write( struct.pack('<B', int(b_str, 2)) )
42
+ break
43
+ file.write(raw_str.encode('utf-8'))
44
+
45
+ # CM3D2専用ファイル用の文字列読み込み
46
+ def read_str(file, total_b = ""):
47
+ for i in range(9):
48
+ b_str = format(struct.unpack('<B', file.read(1))[0], '08b')
49
+ total_b = b_str[1:] + total_b
50
+ if b_str[0] == '0': break
51
+ return file.read(int(total_b, 2)).decode('utf-8')
52
+
53
+ # ボーン/ウェイト名を Blender → CM3D2
54
+ def encode_bone_name(name, enable=True):
55
+ return re.sub(r'([_ ])\*([_ ].*)\.([rRlL])$', r'\1\3\2', name) if name.count('*') == 1 and enable else name
56
+
57
+ # ボーン/ウェイト名を CM3D2 → Blender
58
+ def decode_bone_name(name, enable=True):
59
+ return re.sub(r'([_ ])([rRlL])([_ ].*)$', r'\1*\3.\2', name) if enable else name
60
+
61
+ # CM3D2用マテリアルを設定に合わせて装飾
62
+ def decorate_material(mate, enable=True, me=None, mate_index=-1):
63
+ if not enable: return
64
+ if 'shader1' not in mate: return
65
+
66
+ shader = mate['shader1']
67
+ if 'CM3D2/Man' == shader:
68
+ mate.use_shadeless = True
69
+ mate.diffuse_color = (0, 1, 1)
70
+ elif 'CM3D2/Mosaic' == shader:
71
+ mate.use_transparency = True
72
+ mate.transparency_method = 'RAYTRACE'
73
+ mate.alpha = 0.25
74
+ mate.raytrace_transparency.ior = 2
75
+ elif 'CM3D2_Debug/Debug_CM3D2_Normal2Color' == shader:
76
+ mate.use_tangent_shading = True
77
+ mate.diffuse_color = (0.5, 0.5, 1)
78
+
79
+ else:
80
+ if '/Toony_' in shader:
81
+ mate.diffuse_shader = 'TOON'
82
+ mate.diffuse_toon_smooth = 0.01
83
+ mate.diffuse_toon_size = 1.2
84
+ if 'Trans' in shader:
85
+ mate.use_transparency = True
86
+ mate.alpha = 0.0
87
+ mate.texture_slots[0].use_map_alpha = True
88
+ if 'Unlit/' in shader:
89
+ mate.emit = 0.5
90
+ if '_NoZ' in shader:
91
+ mate.offset_z = 9999
92
+
93
+ is_colored = False
94
+ is_textured = [False, False, False, False]
95
+ rimcolor, rimpower, rimshift = mathutils.Color((1, 1, 1)), 0.0, 0.0
96
+ for slot in mate.texture_slots:
97
+ if not slot: continue
98
+ if not slot.texture: continue
99
+
100
+ tex = slot.texture
101
+ tex_name = remove_serial_number(tex.name)
102
+ slot.use_map_color_diffuse = False
103
+
104
+ if tex_name == '_MainTex':
105
+ slot.use_map_color_diffuse = True
106
+ if 'image' in dir(tex):
107
+ img = tex.image
108
+ if len(img.pixels):
109
+ if me:
110
+ color = mathutils.Color(get_image_average_color_uv(img, me, mate_index)[:3])
111
+ else:
112
+ color = mathutils.Color(get_image_average_color(img)[:3])
113
+ mate.diffuse_color = color
114
+ is_colored = True
115
+
116
+ elif tex_name == '_RimColor':
117
+ rimcolor = slot.color[:]
118
+ if not is_colored:
119
+ mate.diffuse_color = slot.color[:]
120
+ mate.diffuse_color.v += 0.5
121
+
122
+ elif tex_name == '_Shininess':
123
+ mate.specular_intensity = slot.diffuse_color_factor
124
+
125
+ elif tex_name == '_RimPower':
126
+ rimpower = slot.diffuse_color_factor
127
+
128
+ elif tex_name == '_RimShift':
129
+ rimshift = slot.diffuse_color_factor
130
+
131
+ for index, name in enumerate(['_MainTex', '_ToonRamp', '_ShadowTex', '_ShadowRateToon']):
132
+ if tex_name == name:
133
+ if 'image' in dir(tex):
134
+ if tex.image:
135
+ if len(tex.image.pixels):
136
+ is_textured[index] = tex
137
+
138
+ set_texture_color(slot)
139
+
140
+ # よりオリジナルに近く描画するノード作成
141
+ if all(is_textured):
142
+ mate.use_nodes = True
143
+ mate.use_shadeless = True
144
+
145
+ node_tree = mate.node_tree
146
+ for node in node_tree.nodes[:]:
147
+ node_tree.nodes.remove(node)
148
+
149
+ mate_node = node_tree.nodes.new('ShaderNodeExtendedMaterial')
150
+ mate_node.location = (0, 0)
151
+ mate_node.material = mate
152
+
153
+ if "CM3D2 Shade" in bpy.context.blend_data.materials:
154
+ shade_mate = bpy.context.blend_data.materials["CM3D2 Shade"]
155
+ else:
156
+ shade_mate = bpy.context.blend_data.materials.new("CM3D2 Shade")
157
+ shade_mate.diffuse_color = (1, 1, 1)
158
+ shade_mate.diffuse_intensity = 1
159
+ shade_mate.specular_intensity = 1
160
+ shade_mate_node = node_tree.nodes.new('ShaderNodeExtendedMaterial')
161
+ shade_mate_node.location = (234.7785, -131.8243)
162
+ shade_mate_node.material = shade_mate
163
+
164
+ toon_node = node_tree.nodes.new('ShaderNodeValToRGB')
165
+ toon_node.location = (571.3662, -381.0965)
166
+ toon_img = is_textured[1].image
167
+ toon_w, toon_h = toon_img.size[0], toon_img.size[1]
168
+ for i in range(32 - 2):
169
+ toon_node.color_ramp.elements.new(0.0)
170
+ for i in range(32):
171
+ pos = i / (32 - 1)
172
+ toon_node.color_ramp.elements[i].position = pos
173
+ x = int( (toon_w / (32 - 1)) * i )
174
+ pixel_index = x * toon_img.channels
175
+ toon_node.color_ramp.elements[i].color = toon_img.pixels[pixel_index:pixel_index+4]
176
+ toon_node.color_ramp.interpolation = 'EASE'
177
+
178
+ shadow_rate_node = node_tree.nodes.new('ShaderNodeValToRGB')
179
+ shadow_rate_node.location = (488.2785, 7.8446)
180
+ shadow_rate_img = is_textured[3].image
181
+ shadow_rate_w, shadow_rate_h = shadow_rate_img.size[0], shadow_rate_img.size[1]
182
+ for i in range(32 - 2):
183
+ shadow_rate_node.color_ramp.elements.new(0.0)
184
+ for i in range(32):
185
+ pos = i / (32 - 1)
186
+ shadow_rate_node.color_ramp.elements[i].position = pos
187
+ x = int( (shadow_rate_w / (32)) * i )
188
+ pixel_index = x * shadow_rate_img.channels
189
+ shadow_rate_node.color_ramp.elements[i].color = shadow_rate_img.pixels[pixel_index:pixel_index+4]
190
+ shadow_rate_node.color_ramp.interpolation = 'EASE'
191
+
192
+ geometry_node = node_tree.nodes.new('ShaderNodeGeometry')
193
+ geometry_node.location = (323.4597, -810.8045)
194
+
195
+ shadow_texture_node = node_tree.nodes.new('ShaderNodeTexture')
196
+ shadow_texture_node.location = (626.0117, -666.0227)
197
+ shadow_texture_node.texture = is_textured[2]
198
+
199
+ invert_node = node_tree.nodes.new('ShaderNodeInvert')
200
+ invert_node.location = (805.6814, -132.9144)
201
+
202
+ shadow_mix_node = node_tree.nodes.new('ShaderNodeMixRGB')
203
+ shadow_mix_node.location = (1031.2714, -201.5598)
204
+
205
+ toon_mix_node = node_tree.nodes.new('ShaderNodeMixRGB')
206
+ toon_mix_node.location = (1257.5538, -308.8037)
207
+ toon_mix_node.blend_type = 'MULTIPLY'
208
+ toon_mix_node.inputs[0].default_value = 1.0
209
+
210
+ specular_mix_node = node_tree.nodes.new('ShaderNodeMixRGB')
211
+ specular_mix_node.location = (1473.2079, -382.7421)
212
+ specular_mix_node.blend_type = 'SCREEN'
213
+ specular_mix_node.inputs[0].default_value = mate.specular_intensity
214
+
215
+ normal_node = node_tree.nodes.new('ShaderNodeNormal')
216
+ normal_node.location = (912.1372, -590.8748)
217
+
218
+ rim_ramp_node = node_tree.nodes.new('ShaderNodeValToRGB')
219
+ rim_ramp_node.location = (1119.0664, -570.0284)
220
+ rim_ramp_node.color_ramp.elements[0].color = list(rimcolor[:]) + [1.0]
221
+ rim_ramp_node.color_ramp.elements[0].position = rimshift
222
+ rim_ramp_node.color_ramp.elements[1].color = (0, 0, 0, 1)
223
+ rim_ramp_node.color_ramp.elements[1].position = (rimshift) + ((1.0 - (rimpower * 0.03333)) * 0.5)
224
+
225
+ rim_power_node = node_tree.nodes.new('ShaderNodeHueSaturation')
226
+ rim_power_node.location = (1426.6332, -575.6142)
227
+ #rim_power_node.inputs[2].default_value = rimpower * 0.1
228
+
229
+ rim_mix_node = node_tree.nodes.new('ShaderNodeMixRGB')
230
+ rim_mix_node.location = (1724.7024, -451.9624)
231
+ rim_mix_node.blend_type = 'ADD'
232
+
233
+ out_node = node_tree.nodes.new('ShaderNodeOutput')
234
+ out_node.location = (1957.4023, -480.5365)
235
+
236
+ node_tree.links.new(shadow_mix_node.inputs[1], mate_node.outputs[0])
237
+ node_tree.links.new(shadow_rate_node.inputs[0], shade_mate_node.outputs[3])
238
+ node_tree.links.new(invert_node.inputs[1], shadow_rate_node.outputs[0])
239
+ node_tree.links.new(shadow_mix_node.inputs[0], invert_node.outputs[0])
240
+ node_tree.links.new(toon_node.inputs[0], shade_mate_node.outputs[3])
241
+ node_tree.links.new(shadow_texture_node.inputs[0], geometry_node.outputs[4])
242
+ node_tree.links.new(shadow_mix_node.inputs[2], shadow_texture_node.outputs[1])
243
+ node_tree.links.new(toon_node.inputs[0], shade_mate_node.outputs[3])
244
+ node_tree.links.new(toon_mix_node.inputs[1], shadow_mix_node.outputs[0])
245
+ node_tree.links.new(toon_mix_node.inputs[2], toon_node.outputs[0])
246
+ node_tree.links.new(specular_mix_node.inputs[1], toon_mix_node.outputs[0])
247
+ node_tree.links.new(specular_mix_node.inputs[2], shade_mate_node.outputs[4])
248
+ node_tree.links.new(normal_node.inputs[0], mate_node.outputs[2])
249
+ node_tree.links.new(rim_ramp_node.inputs[0], normal_node.outputs[1])
250
+ node_tree.links.new(rim_power_node.inputs[4], rim_ramp_node.outputs[0])
251
+ node_tree.links.new(rim_mix_node.inputs[2], rim_power_node.outputs[0])
252
+ node_tree.links.new(rim_mix_node.inputs[0], shadow_rate_node.outputs[0])
253
+ node_tree.links.new(rim_mix_node.inputs[1], specular_mix_node.outputs[0])
254
+ node_tree.links.new(out_node.inputs[0], rim_mix_node.outputs[0])
255
+ node_tree.links.new(out_node.inputs[1], mate_node.outputs[1])
256
+
257
+ for node in node_tree.nodes[:]:
258
+ node.select = False
259
+ node_tree.nodes.active = mate_node
260
+ node_tree.nodes.active.select = True
261
+
262
+ else:
263
+ mate.use_nodes = False
264
+ mate.use_shadeless = False
265
+
266
+ # 画像のおおよその平均色を取得
267
+ def get_image_average_color(img, sample_count=10):
268
+ if not len(img.pixels): return mathutils.Color([0, 0, 0])
269
+
270
+ pixel_count = img.size[0] * img.size[1]
271
+ channels = img.channels
272
+
273
+ max_s = 0.0
274
+ max_s_color, average_color = mathutils.Color([0, 0, 0]), mathutils.Color([0, 0, 0])
275
+ seek_interval = pixel_count / sample_count
276
+ for sample_index in range(sample_count):
277
+
278
+ index = int(seek_interval * sample_index) * channels
279
+ color = mathutils.Color(img.pixels[index:index+3])
280
+ average_color += color
281
+ if max_s < color.s:
282
+ max_s_color, max_s = color, color.s
283
+
284
+ average_color /= sample_count
285
+ output_color = (average_color + max_s_color) / 2
286
+ output_color.s *= 1.5
287
+ return max_s_color
288
+
289
+ # 画像のおおよその平均色を取得 (UV版)
290
+ def get_image_average_color_uv(img, me=None, mate_index=-1, sample_count=10):
291
+ if not len(img.pixels): return mathutils.Color([0, 0, 0])
292
+
293
+ img_width, img_height, img_channel = img.size[0], img.size[1], img.channels
294
+
295
+ bm = bmesh.new()
296
+ bm.from_mesh(me)
297
+ uv_lay = bm.loops.layers.uv.active
298
+ uvs = [l[uv_lay].uv[:] for f in bm.faces if f.material_index == mate_index for l in f.loops]
299
+ bm.free()
300
+
301
+ if len(uvs) <= sample_count:
302
+ return get_image_average_color(img)
303
+
304
+ average_color = mathutils.Color([0, 0, 0])
305
+ max_s = 0.0
306
+ max_s_color = mathutils.Color([0, 0, 0])
307
+ seek_interval = len(uvs) / sample_count
308
+ for sample_index in range(sample_count):
309
+
310
+ uv_index = int(seek_interval * sample_index)
311
+ x, y = uvs[uv_index]
312
+
313
+ x = math.modf(x)[0]
314
+ if x < 0.0: x += 1.0
315
+ y = math.modf(y)[0]
316
+ if y < 0.0: y += 1.0
317
+
318
+ x, y = int(x * img_width), int(y * img_height)
319
+
320
+ pixel_index = ((y * img_width) + x) * img_channel
321
+ color = mathutils.Color(img.pixels[pixel_index:pixel_index+3])
322
+
323
+ average_color += color
324
+ if max_s < color.s:
325
+ max_s_color, max_s = color, color.s
326
+
327
+ average_color /= sample_count
328
+ output_color = (average_color + max_s_color) / 2
329
+ output_color.s *= 1.5
330
+ return output_color
331
+
332
+ # CM3D2のインストールフォルダを取得+α
333
+ def default_cm3d2_dir(base_dir, file_name, new_ext):
334
+ if not base_dir:
335
+ if preferences().cm3d2_path:
336
+ base_dir = os.path.join(preferences().cm3d2_path, "GameData", "*." + new_ext)
337
+ else:
338
+ try:
339
+ import winreg
340
+ with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\KISS\カスタムメイド3D2') as key:
341
+ base_dir = winreg.QueryValueEx(key, 'InstallPath')[0]
342
+ preferences().cm3d2_path = base_dir
343
+ base_dir = os.path.join(base_dir, "GameData", "*." + new_ext)
344
+ except: pass
345
+ if file_name:
346
+ base_dir = os.path.join(os.path.split(base_dir)[0], file_name)
347
+ base_dir = os.path.splitext(base_dir)[0] + "." + new_ext
348
+ return base_dir
349
+
350
+ # 一時ファイル書き込みと自動バックアップを行うファイルオブジェクトを返す
351
+ def open_temporary(filepath, mode, is_backup=False):
352
+ backup_ext = preferences().backup_ext
353
+ if is_backup and backup_ext:
354
+ backup_filepath = filepath + '.' + backup_ext
355
+ else:
356
+ backup_filepath = None
357
+ return fileutil.TemporaryFileWriter(filepath, mode, backup_filepath=backup_filepath)
358
+
359
+ # ファイルを上書きするならバックアップ処理
360
+ def file_backup(filepath, enable=True):
361
+ backup_ext = preferences().backup_ext
362
+ if enable and backup_ext and os.path.exists(filepath):
363
+ shutil.copyfile(filepath, filepath+"."+backup_ext)
364
+
365
+ # サブフォルダを再帰的に検索してリスト化
366
+ def fild_tex_all_files(dir):
367
+ for root, dirs, files in os.walk(dir):
368
+ yield root
369
+ for file in files:
370
+ if os.path.splitext(file)[1].lower() == ".tex":
371
+ yield os.path.join(root, file)
372
+ elif os.path.splitext(file)[1].lower() == ".png":
373
+ yield os.path.join(root, file)
374
+
375
+ # テクスチャ置き場のパスのリストを返す
376
+ def get_default_tex_paths():
377
+ default_paths = [preferences().default_tex_path0, preferences().default_tex_path1, preferences().default_tex_path2, preferences().default_tex_path3]
378
+ if not any(default_paths):
379
+
380
+ cm3d2_dir = preferences().cm3d2_path
381
+ if not cm3d2_dir:
382
+ try:
383
+ import winreg
384
+ with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\KISS\カスタムメイド3D2') as key:
385
+ cm3d2_dir = winreg.QueryValueEx(key, 'InstallPath')[0]
386
+ except: return []
387
+
388
+ target_dir = [os.path.join(cm3d2_dir, "GameData", "texture")]
389
+ target_dir.append(os.path.join(cm3d2_dir, "GameData", "texture2"))
390
+ target_dir.append(os.path.join(cm3d2_dir, "Sybaris", "GameData"))
391
+ target_dir.append(os.path.join(cm3d2_dir, "Mod"))
392
+
393
+ tex_dirs = [path for path in target_dir if os.path.isdir(path)]
394
+
395
+ for index, path in enumerate(tex_dirs):
396
+ preferences().__setattr__('default_tex_path' + str(index), path)
397
+ else:
398
+ tex_dirs = [preferences().__getattribute__('default_tex_path' + str(i)) for i in range(4) if preferences().__getattribute__('default_tex_path' + str(i))]
399
+ return tex_dirs
400
+
401
+ # テクスチャ置き場の全ファイルを返す
402
+ def get_tex_storage_files():
403
+ files = []
404
+ tex_dirs = get_default_tex_paths()
405
+ for tex_dir in tex_dirs:
406
+ tex_dir = bpy.path.abspath(tex_dir)
407
+ files.extend(fild_tex_all_files(tex_dir))
408
+ return files
409
+
410
+ # テクスチャを検索して空の画像へ置換
411
+ def replace_cm3d2_tex(img, pre_files=[]):
412
+ source_png_name = remove_serial_number(img.name).lower() + ".png"
413
+ source_tex_name = remove_serial_number(img.name).lower() + ".tex"
414
+
415
+ tex_dirs = get_default_tex_paths()
416
+
417
+ for tex_dir in tex_dirs:
418
+
419
+ if len(pre_files):
420
+ files = pre_files
421
+ else:
422
+ files = fild_tex_all_files(tex_dir)
423
+
424
+ for path in files:
425
+ path = bpy.path.abspath(path)
426
+ file_name = os.path.basename(path).lower()
427
+
428
+ if file_name == source_png_name:
429
+ img.filepath = path
430
+ img.reload()
431
+ return True
432
+
433
+ elif file_name == source_tex_name:
434
+ try:
435
+ file = open(path, 'rb')
436
+ except: return False
437
+
438
+ header_ext = read_str(file)
439
+ if header_ext == 'CM3D2_TEX':
440
+ file.seek(4, 1)
441
+ read_str(file)
442
+ png_size = struct.unpack('<i', file.read(4))[0]
443
+ png_path = os.path.splitext(path)[0] + ".png"
444
+ try:
445
+ png_file = open(png_path, 'wb')
446
+ except: return False
447
+ png_file.write(file.read(png_size))
448
+ png_file.close() ; file.close()
449
+ img.filepath = png_path
450
+ img.reload()
451
+ return True
452
+ else:
453
+ file.close()
454
+ return False
455
+
456
+ if len(pre_files):
457
+ return False
458
+ return False
459
+
460
+ # col f タイプの設定値を値に合わせて着色
461
+ def set_texture_color(slot):
462
+ if not slot or not slot.texture or slot.use: return
463
+
464
+ type = 'col' if slot.use_rgb_to_intensity else 'f'
465
+ tex = slot.texture
466
+ base_name = remove_serial_number(tex.name)
467
+ tex.type = 'BLEND'
468
+ if 'progression' in dir(tex):
469
+ tex.progression = 'DIAGONAL'
470
+ tex.use_color_ramp = True
471
+ tex.use_preview_alpha = True
472
+ elements = tex.color_ramp.elements
473
+
474
+ element_count = 4
475
+ if element_count < len(elements):
476
+ for i in range(len(elements) - element_count):
477
+ elements.remove(elements[-1])
478
+ elif len(elements) < element_count:
479
+ for i in range(element_count - len(elements)):
480
+ elements.new(1.0)
481
+
482
+ elements[0].position, elements[1].position, elements[2].position, elements[3].position = 0.2, 0.21, 0.25, 0.26
483
+
484
+ if type == 'col':
485
+ elements[0].color = [0.2, 1, 0.2, 1]
486
+ elements[-1].color = slot.color[:] + (slot.diffuse_color_factor, )
487
+ if 0.3 < mathutils.Color(slot.color[:3]).v:
488
+ elements[1].color, elements[2].color = [0, 0, 0, 1], [0, 0, 0, 1]
489
+ else:
490
+ elements[1].color, elements[2].color = [1, 1, 1, 1], [1, 1, 1, 1]
491
+
492
+ elif type == 'f':
493
+ elements[0].color = [0.2, 0.2, 1, 1]
494
+ multi = 1.0
495
+ if base_name == '_OutlineWidth':
496
+ multi = 200
497
+ elif base_name == '_RimPower':
498
+ multi = 1.0 / 30.0
499
+ value = slot.diffuse_color_factor * multi
500
+ elements[-1].color = [value, value, value, 1]
501
+ if 0.3 < value:
502
+ elements[1].color, elements[2].color = [0, 0, 0, 1], [0, 0, 0, 1]
503
+ else:
504
+ elements[1].color, elements[2].color = [1, 1, 1, 1], [1, 1, 1, 1]
505
+
506
+ # 必要なエリアタイプを設定を変更してでも取得
507
+ def get_request_area(context, request_type, except_types=['VIEW_3D', 'PROPERTIES', 'INFO', 'USER_PREFERENCES']):
508
+ request_areas = [(a, a.width * a.height) for a in context.screen.areas if a.type == request_type]
509
+ candidate_areas = [(a, a.width * a.height) for a in context.screen.areas if a.type not in except_types]
510
+
511
+ return_areas = request_areas[:] if len(request_areas) else candidate_areas
512
+ if not len(return_areas): return None
513
+
514
+ return_areas.sort(key=lambda i: i[1])
515
+ return_area = return_areas[-1][0]
516
+ return_area.type = request_type
517
+ return return_area
518
+
519
+ # 複数のデータを完全に削除
520
+ def remove_data(target_data):
521
+ try: target_data = target_data[:]
522
+ except: target_data = [target_data]
523
+
524
+ for data in target_data:
525
+ if data.__class__.__name__ == 'Object':
526
+ if data.name in bpy.context.scene.objects:
527
+ bpy.context.scene.objects.unlink(data)
528
+
529
+ for data in target_data:
530
+ if 'users' in dir(data) and 'user_clear' in dir(data):
531
+ if data.users: data.user_clear()
532
+
533
+ for data in target_data:
534
+ for data_str in dir(bpy.data):
535
+ if data_str[-1] != "s": continue
536
+ try:
537
+ if data.__class__.__name__ == eval('bpy.data.%s[0].__class__.__name__' % data_str):
538
+ exec('bpy.data.%s.remove(data, do_unlink=True)' % data_str)
539
+ break
540
+ except: pass
541
+
542
+ # オブジェクトのマテリアルを削除/復元するクラス
543
+ class material_restore:
544
+ def __init__(self, ob):
545
+ override = bpy.context.copy()
546
+ override['object'] = ob
547
+ self.object = ob
548
+
549
+ self.slots = []
550
+ for slot in ob.material_slots:
551
+ if slot: self.slots.append(slot.material)
552
+ else: self.slots.append(None)
553
+
554
+ self.mesh_data = []
555
+ for index, slot in enumerate(ob.material_slots):
556
+ self.mesh_data.append([])
557
+ for face in ob.data.polygons:
558
+ if face.material_index == index:
559
+ self.mesh_data[-1].append(face.index)
560
+
561
+ for slot in ob.material_slots[:]:
562
+ bpy.ops.object.material_slot_remove(override)
563
+
564
+ def restore(self):
565
+ override = bpy.context.copy()
566
+ override['object'] = self.object
567
+
568
+ for slot in self.object.material_slots[:]:
569
+ bpy.ops.object.material_slot_remove(override)
570
+
571
+ for index, mate in enumerate(self.slots):
572
+ bpy.ops.object.material_slot_add(override)
573
+ slot = self.object.material_slots[index]
574
+ if slot:
575
+ slot.material = mate
576
+ for face_index in self.mesh_data[index]:
577
+ self.object.data.polygons[face_index].material_index = index
578
+
579
+ # 現在のレイヤー内のオブジェクトをレンダリングしなくする/戻す
580
+ class hide_render_restore:
581
+ def __init__(self, render_objects=[]):
582
+ try: render_objects = render_objects[:]
583
+ except: render_objects = [render_objects]
584
+
585
+ if not len(render_objects):
586
+ render_objects = bpy.context.selected_objects[:]
587
+
588
+ self.render_objects = render_objects[:]
589
+ self.render_object_names = [ob.name for ob in render_objects]
590
+
591
+ self.rendered_objects = []
592
+ for ob in render_objects:
593
+ if ob.hide_render:
594
+ self.rendered_objects.append(ob)
595
+ ob.hide_render = False
596
+
597
+ self.hide_rendered_objects = []
598
+ for ob in bpy.data.objects:
599
+ for layer_index, is_used in enumerate(bpy.context.scene.layers):
600
+ if not is_used: continue
601
+ if ob.layers[layer_index] and is_used and ob.name not in self.render_object_names and not ob.hide_render:
602
+ self.hide_rendered_objects.append(ob)
603
+ ob.hide_render = True
604
+ break
605
+
606
+ def restore(self):
607
+ for ob in self.rendered_objects:
608
+ ob.hide_render = True
609
+ for ob in self.hide_rendered_objects:
610
+ ob.hide_render = False
611
+
612
+ # 指定エリアに変数をセット
613
+ def set_area_space_attr(area, attr_name, value):
614
+ if not area: return
615
+ for space in area.spaces:
616
+ if space.type == area.type:
617
+ space.__setattr__(attr_name, value)
618
+ break
619
+
620
+ # スムーズなグラフを返す1
621
+ def in_out_quad_blend(f):
622
+ if f <= 0.5:
623
+ return 2.0 * math.sqrt(f)
624
+ f -= 0.5
625
+ return 2.0 * f * (1.0 - f) + 0.5
626
+ # スムーズなグラフを返す2
627
+ def bezier_blend(f):
628
+ return math.sqrt(f) * (3.0 - 2.0 * f)
629
+ # 三角関数でスムーズなグラフを返す
630
+ def trigonometric_smooth(x):
631
+ return math.sin((x-0.5)*math.pi)*0.5+0.5
632
+
633
+ # エクスポート例外クラス
634
+ class CM3D2ExportException(Exception):
635
+ pass
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/console_toggle.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ import os, bpy
2
+ if os.name == 'nt':
3
+ bpy.ops.wm.console_toggle()
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/fileutil.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import os
3
+ import shutil
4
+ import tempfile
5
+
6
+
7
+
8
+ class TemporaryFileWriter(io.BufferedWriter):
9
+ """ファイルをアトミックに更新します。"""
10
+
11
+ backup_filepath = None
12
+ __filepath = None
13
+ __temppath = None
14
+
15
+
16
+ @property
17
+ def filepath(self):
18
+ """ファイルパスを取得します。"""
19
+ return self.__filepath
20
+
21
+
22
+ @property
23
+ def temppath(self):
24
+ """一時ファイルパスを取得します。"""
25
+ return self.__temppath
26
+
27
+
28
+ def __init__(self, filepath, mode='wb', buffer_size=io.DEFAULT_BUFFER_SIZE, backup_filepath=None):
29
+ """ファイルパスを指定して初期化します。
30
+ backup_filepath に None 以外が指定された場合、書き込み完了時に
31
+ バックアップファイルが作成されます。
32
+ """
33
+ dirpath, filename = os.path.split(filepath)
34
+ fd, temppath = tempfile.mkstemp(prefix=filename + '.', dir=dirpath)
35
+ try:
36
+ fh = os.fdopen(fd, mode)
37
+ super(TemporaryFileWriter, self).__init__(fh, buffer_size)
38
+ except:
39
+ if fh:
40
+ fh.close()
41
+ os.remove(temppath)
42
+ raise
43
+ self.__filepath = filepath
44
+ self.__temppath = temppath
45
+ self.backup_filepath = backup_filepath
46
+
47
+
48
+ def __enter__(self):
49
+ return self
50
+
51
+
52
+ def __exit__(self, exc_type, exc_value, traceback):
53
+ if exc_type is None and exc_value is None and traceback is None:
54
+ self.close()
55
+ else:
56
+ self.abort()
57
+
58
+
59
+ def close(self):
60
+ """一時ファイルを閉じてリネームします。"""
61
+ if self.closed:
62
+ return
63
+ super(io.BufferedWriter, self).close()
64
+ self.raw.close()
65
+ try:
66
+ if os.path.exists(self.filepath):
67
+ if self.backup_filepath is not None:
68
+ shutil.move(self.filepath, self.backup_filepath)
69
+ else:
70
+ os.remove(self.filepath)
71
+ shutil.move(self.temppath, self.filepath)
72
+ except:
73
+ os.remove(self.temppath)
74
+ raise
75
+
76
+
77
+ def abort(self):
78
+ """一時ファイルを閉じて削除します。"""
79
+ if self.closed:
80
+ return
81
+ super(io.BufferedWriter, self).close()
82
+ self.raw.close()
83
+ os.remove(self.temppath)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/kiss.png ADDED
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/mate_export.py ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bpy
2
+ import os
3
+ import re
4
+ import struct
5
+ from . import common
6
+
7
+ class export_cm3d2_mate(bpy.types.Operator):
8
+ bl_idname = 'material.export_cm3d2_mate'
9
+ bl_label = "Save As Mate"
10
+ bl_description = "Allows you to save blender CM3d2 materials as seperate .mate files."
11
+ bl_options = {'REGISTER', 'UNDO'}
12
+
13
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
14
+ filename_ext = ".mate"
15
+ filter_glob = bpy.props.StringProperty(default="*.mate", options={'HIDDEN'})
16
+
17
+ is_backup = bpy.props.BoolProperty(name="Backup", default=True, description="Will backup an overwritten file.")
18
+
19
+ version = bpy.props.IntProperty(name="Version", default=1000, min=1000, max=1111, soft_min=1000, soft_max=1111, step=1)
20
+ name1 = bpy.props.StringProperty(name="Name 1")
21
+ name2 = bpy.props.StringProperty(name="Name 2")
22
+
23
+ @classmethod
24
+ def poll(cls, context):
25
+ if 'material' in dir(context):
26
+ mate = context.material
27
+ if mate:
28
+ if 'shader1' in mate and 'shader2' in mate:
29
+ return True
30
+ return False
31
+
32
+ def invoke(self, context, event):
33
+ mate = context.material
34
+ if common.preferences().mate_default_path:
35
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_default_path, mate.name.lower(), "mate")
36
+ else:
37
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_export_path, mate.name.lower(), "mate")
38
+ self.is_backup = bool(common.preferences().backup_ext)
39
+ self.name1 = common.remove_serial_number(mate.name.lower())
40
+ self.name2 = common.remove_serial_number(mate.name)
41
+ context.window_manager.fileselect_add(self)
42
+ return {'RUNNING_MODAL'}
43
+
44
+ def draw(self, context):
45
+ row = self.layout.row()
46
+ row.prop(self, 'is_backup', icon='FILE_BACKUP')
47
+ if not common.preferences().backup_ext:
48
+ row.enabled = False
49
+ self.layout.prop(self, 'version', icon='LINENUMBERS_ON')
50
+ self.layout.prop(self, 'name1', icon='SORTALPHA')
51
+ self.layout.prop(self, 'name2', icon='SORTALPHA')
52
+
53
+ def execute(self, context):
54
+ common.preferences().mate_export_path = self.filepath
55
+
56
+ try:
57
+ file = common.open_temporary(self.filepath, 'wb', is_backup=self.is_backup)
58
+ except:
59
+ self.report(type={'ERROR'}, message="Failed to backup file, possibly inaccessible.")
60
+ return {'CANCELLED'}
61
+
62
+ try:
63
+ with file:
64
+ self.write_material(context, file)
65
+ except common.CM3D2ExportException as e:
66
+ self.report(type={'ERROR'}, message=str(e))
67
+ return {'CANCELLED'}
68
+
69
+ return {'FINISHED'}
70
+
71
+ def write_material(self, context, file):
72
+ mate = context.material
73
+
74
+ common.write_str(file, 'CM3D2_MATERIAL')
75
+ file.write(struct.pack('<i', self.version))
76
+
77
+ common.write_str(file, self.name1)
78
+ common.write_str(file, self.name2)
79
+ common.write_str(file, mate['shader1'])
80
+ common.write_str(file, mate['shader2'])
81
+
82
+ for tex_slot in mate.texture_slots:
83
+ if not tex_slot:
84
+ continue
85
+ tex = tex_slot.texture
86
+ if tex_slot.use:
87
+ type = 'tex'
88
+ else:
89
+ if tex_slot.use_rgb_to_intensity:
90
+ type = 'col'
91
+ else:
92
+ type = 'f'
93
+ common.write_str(file, type)
94
+ common.write_str(file, common.remove_serial_number(tex.name))
95
+ if type == 'tex':
96
+ try:
97
+ img = tex.image
98
+ except:
99
+ raise common.CM3D2ExportException("Couldn't acquire tex type, mission abort.")
100
+ if img:
101
+ common.write_str(file, 'tex2d')
102
+ common.write_str(file, common.remove_serial_number(img.name))
103
+ if 'cm3d2_path' in img:
104
+ path = img['cm3d2_path']
105
+ else:
106
+ path = bpy.path.abspath(img.filepath)
107
+ path = path.replace('\\', '/')
108
+ path = re.sub(r'^[\/\.]*', "", path)
109
+ if not re.search(r'^assets/texture/', path, re.I):
110
+ path = "Assets/texture/texture/" + os.path.basename(path)
111
+ common.write_str(file, path)
112
+ col = tex_slot.color
113
+ file.write(struct.pack('<3f', col[0], col[1], col[2]))
114
+ file.write(struct.pack('<f', tex_slot.diffuse_color_factor))
115
+ else:
116
+ common.write_str(file, 'null')
117
+ elif type == 'col':
118
+ col = tex_slot.color
119
+ file.write(struct.pack('<3f', col[0], col[1], col[2]))
120
+ file.write(struct.pack('<f', tex_slot.diffuse_color_factor))
121
+ elif type == 'f':
122
+ file.write(struct.pack('<f', tex_slot.diffuse_color_factor))
123
+
124
+ common.write_str(file, 'end')
125
+
126
+ class export_cm3d2_mate_text(bpy.types.Operator):
127
+ bl_idname = 'text.export_cm3d2_mate_text'
128
+ bl_label = "Save Text as Mate"
129
+ bl_description = "This will allow you to save any text in the text editor as a .mate file"
130
+ bl_options = {'REGISTER', 'UNDO'}
131
+
132
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
133
+ filename_ext = ".mate"
134
+ filter_glob = bpy.props.StringProperty(default="*.mate", options={'HIDDEN'})
135
+
136
+ is_backup = bpy.props.BoolProperty(name="Backup", default=True, description="Will backup any overwritten files.")
137
+
138
+ version = bpy.props.IntProperty(name="Version", default=1000, min=1000, max=1111, soft_min=1000, soft_max=1111, step=1)
139
+ name1 = bpy.props.StringProperty(name="Name1")
140
+ name2 = bpy.props.StringProperty(name="Name2")
141
+
142
+ @classmethod
143
+ def poll(cls, context):
144
+ if 'edit_text' in dir(context):
145
+ txt = context.edit_text
146
+ if txt:
147
+ data = txt.as_string()
148
+ lines = txt.as_string().split('\n')
149
+ if len(lines) < 10:
150
+ return False
151
+ match_strs = ['\ntex\n', '\ncol\n', '\nf\n', '\n\t_MainTex\n', '\n\t_Color\n', '\n\t_Shininess\n']
152
+ for s in match_strs:
153
+ if s in data:
154
+ return True
155
+ return False
156
+
157
+ def invoke(self, context, event):
158
+ txt = context.edit_text
159
+ lines = txt.as_string().split('\n')
160
+ mate_name = lines[1]
161
+ if common.preferences().mate_default_path:
162
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_default_path, mate_name.lower(), "mate")
163
+ else:
164
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_export_path, mate_name.lower(), "mate")
165
+ try:
166
+ self.version = int(lines[0])
167
+ except:
168
+ self.version = 1000
169
+ if lines[1] != '***':
170
+ self.name1 = lines[1]
171
+ else:
172
+ self.name1 = lines[2]
173
+ self.name2 = lines[2]
174
+ context.window_manager.fileselect_add(self)
175
+ return {'RUNNING_MODAL'}
176
+
177
+ def draw(self, context):
178
+ row = self.layout.row()
179
+ row.prop(self, 'is_backup', icon='FILE_BACKUP')
180
+ if not common.preferences().backup_ext:
181
+ row.enabled = False
182
+ self.layout.prop(self, 'version', icon='LINENUMBERS_ON')
183
+ self.layout.prop(self, 'name1', icon='SORTALPHA')
184
+ self.layout.prop(self, 'name2', icon='SORTALPHA')
185
+
186
+ def execute(self, context):
187
+ common.preferences().mate_export_path = self.filepath
188
+
189
+ try:
190
+ file = common.open_temporary(self.filepath, 'wb', is_backup=self.is_backup)
191
+ except:
192
+ self.report(type={'ERROR'}, message="Failed to backup file, possibly inaccessible.")
193
+ return {'CANCELLED'}
194
+
195
+ try:
196
+ with file:
197
+ self.write_material(context, file)
198
+ except common.CM3D2ExportException as e:
199
+ self.report(type={'ERROR'}, message=str(e))
200
+ return {'CANCELLED'}
201
+
202
+ return {'FINISHED'}
203
+
204
+ def write_material(self, context, file):
205
+ txt = context.edit_text
206
+ lines = txt.as_string().split('\n')
207
+
208
+ common.write_str(file, 'CM3D2_MATERIAL')
209
+ file.write(struct.pack('<i', self.version))
210
+
211
+ common.write_str(file, self.name1)
212
+ common.write_str(file, self.name2)
213
+ common.write_str(file, lines[3])
214
+ common.write_str(file, lines[4])
215
+
216
+ line_seek = 5
217
+ try:
218
+ for i in range(99999):
219
+ if len(lines) <= line_seek:
220
+ break
221
+ if not lines[line_seek]:
222
+ line_seek += 1
223
+ continue
224
+ if lines[line_seek] == 'tex':
225
+ common.write_str(file, common.line_trim(lines[line_seek]))
226
+ common.write_str(file, common.line_trim(lines[line_seek + 1]))
227
+ common.write_str(file, common.line_trim(lines[line_seek + 2]))
228
+ line_seek += 3
229
+ if common.line_trim(lines[line_seek - 1]) == 'tex2d':
230
+ common.write_str(file, common.line_trim(lines[line_seek]))
231
+ common.write_str(file, common.line_trim(lines[line_seek + 1]))
232
+ floats = common.line_trim(lines[line_seek + 2]).split(' ')
233
+ for f in floats:
234
+ file.write(struct.pack('<f', float(f)))
235
+ line_seek += 3
236
+ elif lines[line_seek] == 'col':
237
+ common.write_str(file, common.line_trim(lines[line_seek]))
238
+ common.write_str(file, common.line_trim(lines[line_seek + 1]))
239
+ floats = common.line_trim(lines[line_seek + 2]).split(' ')
240
+ for f in floats:
241
+ file.write(struct.pack('<f', float(f)))
242
+ line_seek += 3
243
+ elif lines[line_seek] == 'f':
244
+ common.write_str(file, common.line_trim(lines[line_seek]))
245
+ common.write_str(file, common.line_trim(lines[line_seek + 1]))
246
+ f = float(common.line_trim(lines[line_seek + 2]))
247
+ file.write(struct.pack('<f', f))
248
+ line_seek += 3
249
+ else:
250
+ raise common.CM3D2ExportException("Setting value other than [tex, col, or f] was found. Mission abort")
251
+ except:
252
+ raise common.CM3D2ExportException("Failed to save .mate, review data.")
253
+ common.write_str(file, 'end')
254
+
255
+ # テキストメニューに項目を登録
256
+ def TEXT_MT_text(self, context):
257
+ self.layout.operator(export_cm3d2_mate_text.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/mate_import.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, re, bpy, struct, os.path, shutil
2
+ from . import common
3
+
4
+ class import_cm3d2_mate(bpy.types.Operator):
5
+ bl_idname = 'material.import_cm3d2_mate'
6
+ bl_label = "Import Mate"
7
+ bl_description = "Open a .mate file as a material."
8
+ bl_options = {'REGISTER', 'UNDO'}
9
+
10
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
11
+ filename_ext = ".mate"
12
+ filter_glob = bpy.props.StringProperty(default="*.mate", options={'HIDDEN'})
13
+
14
+ is_decorate = bpy.props.BoolProperty(name="Decorate the material according to its type", default=True)
15
+ is_replace_cm3d2_tex = bpy.props.BoolProperty(name="Find textures", default=True, description="Will search for the textures.")
16
+
17
+ @classmethod
18
+ def poll(cls, context):
19
+ if 'material_slot' in dir(context):
20
+ if 'material' in dir(context):
21
+ return True
22
+ return False
23
+
24
+ def invoke(self, context, event):
25
+ if common.preferences().mate_default_path:
26
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_default_path, "", "mate")
27
+ else:
28
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_import_path, "", "mate")
29
+ self.is_replace_cm3d2_tex = common.preferences().is_replace_cm3d2_tex
30
+ context.window_manager.fileselect_add(self)
31
+ return {'RUNNING_MODAL'}
32
+
33
+ def draw(self, context):
34
+ self.layout.prop(self, 'is_decorate', icon='TEXTURE_SHADED')
35
+ self.layout.prop(self, 'is_replace_cm3d2_tex', icon='BORDERMOVE')
36
+
37
+ def execute(self, context):
38
+ common.preferences().mate_import_path = self.filepath
39
+
40
+ ob = context.active_object
41
+ me = ob.data
42
+
43
+ try:
44
+ file = open(self.filepath, 'rb')
45
+ except:
46
+ self.report(type={'ERROR'}, message="Failed to import file, File is possibly inaccessible or non-existent.")
47
+ return {'CANCELLED'}
48
+ if common.read_str(file) != 'CM3D2_MATERIAL':
49
+ self.report(type={'ERROR'}, message="This is not a .mate file for CM3D2")
50
+ return {'CANCELLED'}
51
+ struct.unpack('<i', file.read(4))[0]
52
+ common.read_str(file)
53
+ mate_name = common.read_str(file)
54
+
55
+ if not context.material_slot:
56
+ bpy.ops.object.material_slot_add()
57
+ root, ext = os.path.splitext(os.path.basename(self.filepath))
58
+ mate = context.blend_data.materials.new(mate_name)
59
+ context.material_slot.material = mate
60
+
61
+ mate['shader1'] = common.read_str(file)
62
+ mate['shader2'] = common.read_str(file)
63
+
64
+ slot_index = 0
65
+ already_texs = []
66
+ for i in range(99999):
67
+ type = common.read_str(file)
68
+ if type == 'tex':
69
+ slot = mate.texture_slots.create(slot_index)
70
+ tex_name = common.read_str(file)
71
+ tex = context.blend_data.textures.new(tex_name, 'IMAGE')
72
+ slot.texture = tex
73
+ sub_type = common.read_str(file)
74
+ if sub_type == 'tex2d':
75
+ img = context.blend_data.images.new(common.read_str(file), 128, 128)
76
+ img['cm3d2_path'] = common.read_str(file)
77
+ img.filepath = img['cm3d2_path']
78
+ img.source = 'FILE'
79
+ tex.image = img
80
+ slot.color = struct.unpack('<3f', file.read(4*3))
81
+ slot.diffuse_color_factor = struct.unpack('<f', file.read(4))[0]
82
+
83
+ # tex探し
84
+ if self.is_replace_cm3d2_tex:
85
+ if common.replace_cm3d2_tex(img) and tex_name=='_MainTex':
86
+ for face in me.polygons:
87
+ if face.material_index == ob.active_material_index:
88
+ me.uv_textures.active.data[face.index].image = img
89
+
90
+ elif type == 'col':
91
+ slot = mate.texture_slots.create(slot_index)
92
+ tex_name = common.read_str(file)
93
+ tex = context.blend_data.textures.new(tex_name, 'BLEND')
94
+ mate.use_textures[slot_index] = False
95
+ slot.use_rgb_to_intensity = True
96
+ slot.color = struct.unpack('<3f', file.read(4*3))
97
+ slot.diffuse_color_factor = struct.unpack('<f', file.read(4))[0]
98
+ slot.texture = tex
99
+
100
+ elif type == 'f':
101
+ slot = mate.texture_slots.create(slot_index)
102
+ tex_name = common.read_str(file)
103
+ tex = context.blend_data.textures.new(tex_name, 'BLEND')
104
+ mate.use_textures[slot_index] = False
105
+ slot.diffuse_color_factor = struct.unpack('<f', file.read(4))[0]
106
+ slot.texture = tex
107
+
108
+ elif type == 'end':
109
+ break
110
+ else:
111
+ self.report(type={'ERROR'}, message="Unknown value was found, mission failed")
112
+ return {'CANCELLED'}
113
+
114
+ if common.preferences().mate_unread_same_value:
115
+ if tex_name in already_texs:
116
+ mate.texture_slots.clear(slot_index)
117
+ slot_index -= 1
118
+ already_texs.append(tex_name)
119
+
120
+ slot_index += 1
121
+
122
+ file.close()
123
+ common.decorate_material(mate, self.is_decorate, me, ob.active_material_index)
124
+ return {'FINISHED'}
125
+
126
+ class import_cm3d2_mate_text(bpy.types.Operator):
127
+ bl_idname = 'text.import_cm3d2_mate_text'
128
+ bl_label = "Import a mate"
129
+ bl_description = "Open a mate file in the text editor as text"
130
+ bl_options = {'REGISTER', 'UNDO'}
131
+
132
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
133
+ filename_ext = ".mate"
134
+ filter_glob = bpy.props.StringProperty(default="*.mate", options={'HIDDEN'})
135
+
136
+ is_overwrite = bpy.props.BoolProperty(name="Overwrites current text in the text editor.", default=False)
137
+
138
+ @classmethod
139
+ def poll(cls, context):
140
+ return True
141
+
142
+ def invoke(self, context, event):
143
+ if common.preferences().mate_default_path:
144
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_default_path, "", "mate")
145
+ else:
146
+ self.filepath = common.default_cm3d2_dir(common.preferences().mate_import_path, "", "mate")
147
+ context.window_manager.fileselect_add(self)
148
+ return {'RUNNING_MODAL'}
149
+
150
+ def draw(self, context):
151
+ self.layout.prop(self, 'is_overwrite', icon='SAVE_COPY')
152
+
153
+ def execute(self, context):
154
+ common.preferences().mate_import_path = self.filepath
155
+
156
+ txt = None
157
+ if self.is_overwrite:
158
+ if 'edit_text' not in dir(context):
159
+ self.report(type={'ERROR'}, message="Text data could not be overwritten")
160
+ return {'CANCELLED'}
161
+ if not context.edit_text:
162
+ self.report(type={'ERROR'}, message="Text data could not be overwritten")
163
+ return {'CANCELLED'}
164
+ txt = context.edit_text
165
+ txt.clear()
166
+
167
+ try:
168
+ file = open(self.filepath, 'rb')
169
+ except:
170
+ self.report(type={'ERROR'}, message="Failed to open the file, File does not exist or is not accessible")
171
+ return {'CANCELLED'}
172
+ if common.read_str(file) != 'CM3D2_MATERIAL':
173
+ self.report(type={'ERROR'}, message="This is not a CM3D2 Mate file")
174
+ return {'CANCELLED'}
175
+
176
+ version = str(struct.unpack('<i', file.read(4))[0])
177
+ name1 = common.read_str(file)
178
+ name2 = common.read_str(file)
179
+ if not txt:
180
+ txt = context.blend_data.texts.new(os.path.basename(name2))
181
+ context.area.type = 'TEXT_EDITOR'
182
+ context.space_data.text = txt
183
+ txt.write( version + "\n" )
184
+ txt.write( name1 + "\n" )
185
+ txt.write( name2 + "\n" )
186
+ txt.write( common.read_str(file) + "\n" )
187
+ txt.write( common.read_str(file) + "\n" )
188
+ txt.write("\n")
189
+
190
+ for i in range(99999):
191
+ type = common.read_str(file)
192
+ if type == 'tex':
193
+ txt.write( type + "\n" )
194
+ txt.write( "\t" + common.read_str(file) + "\n" )
195
+ tex_type = common.read_str(file)
196
+ txt.write( "\t" + tex_type + "\n" )
197
+ if tex_type == 'tex2d':
198
+ txt.write( "\t" + common.read_str(file) + "\n" )
199
+ txt.write( "\t" + common.read_str(file) + "\n" )
200
+ fs = struct.unpack('<4f', file.read(4*4))
201
+ txt.write( "\t" + " ".join([str(fs[0]), str(fs[1]), str(fs[2]), str(fs[3])]) + "\n" )
202
+ elif type == 'col':
203
+ txt.write( type + "\n" )
204
+ txt.write( "\t" + common.read_str(file) + "\n" )
205
+ fs = struct.unpack('<4f', file.read(4*4))
206
+ txt.write( "\t" + " ".join([str(fs[0]), str(fs[1]), str(fs[2]), str(fs[3])]) + "\n" )
207
+ elif type == 'f':
208
+ txt.write( type + "\n" )
209
+ txt.write( "\t" + common.read_str(file) + "\n" )
210
+ txt.write( "\t" + str(struct.unpack('<f', file.read(4))[0]) + "\n" )
211
+ elif type == 'end':
212
+ break
213
+ else:
214
+ self.report(type={'ERROR'}, message="Unknown value was found, mission failed.")
215
+ return {'CANCELLED'}
216
+
217
+ file.close()
218
+ txt.current_line_index = 0
219
+ return {'FINISHED'}
220
+
221
+ # テキストメニューに項目を登録
222
+ def TEXT_MT_text(self, context):
223
+ self.layout.separator()
224
+ self.layout.operator(import_cm3d2_mate_text.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_DATA_PT_context_arm.py ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「アーマチュアデータ」タブ
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ import re
8
+ ob = context.active_object
9
+ if not ob: return
10
+ if ob.type != 'ARMATURE': return
11
+
12
+ arm = ob.data
13
+ is_boxed = False
14
+
15
+ bone_data_count = 0
16
+ if 'BoneData:0' in arm and 'LocalBoneData:0' in arm:
17
+ for key in arm.keys():
18
+ if re.search(r'^(Local)?BoneData:\d+$', key):
19
+ bone_data_count += 1
20
+ enabled_clipboard = False
21
+ clipboard = context.window_manager.clipboard
22
+ if 'BoneData:' in clipboard and 'LocalBoneData:' in clipboard:
23
+ enabled_clipboard = True
24
+ if bone_data_count or enabled_clipboard:
25
+ if not is_boxed:
26
+ box = self.layout.box()
27
+ box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
28
+ is_boxed = True
29
+
30
+ col = box.column(align=True)
31
+ row = col.row(align=True)
32
+ row.label(text="Bone Data", icon='CONSTRAINT_BONE')
33
+ sub_row = row.row()
34
+ sub_row.alignment = 'RIGHT'
35
+ if bone_data_count:
36
+ sub_row.label(text=str(bone_data_count), icon='CHECKBOX_HLT')
37
+ else:
38
+ sub_row.label(text="0", icon='CHECKBOX_DEHLT')
39
+ row = col.row(align=True)
40
+ row.operator('object.copy_armature_bone_data_property', icon='COPYDOWN', text="Copy")
41
+ row.operator('object.paste_armature_bone_data_property', icon='PASTEDOWN', text="Paste")
42
+ row.operator('object.remove_armature_bone_data_property', icon='X', text="")
43
+
44
+ flag = False
45
+ for bone in arm.bones:
46
+ if not flag and re.search(r'[_ ]([rRlL])[_ ]', bone.name):
47
+ flag = True
48
+ if not flag and bone.name.count('*') == 1:
49
+ if re.search(r'\.([rRlL])$', bone.name):
50
+ flag = True
51
+ if flag:
52
+ if not is_boxed:
53
+ box = self.layout.box()
54
+ box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
55
+ is_boxed = True
56
+
57
+ col = box.column(align=True)
58
+ col.label(text="Convert Bone Names", icon='SORTALPHA')
59
+ row = col.row(align=True)
60
+ row.operator('armature.decode_cm3d2_bone_names', text="CM3D2 → Blender", icon='BLENDER')
61
+ row.operator('armature.encode_cm3d2_bone_names', text="Blender → CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
62
+ break
63
+
64
+ if 'is T Stance' in arm:
65
+ if not is_boxed:
66
+ box = self.layout.box()
67
+ box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
68
+ is_boxed = True
69
+
70
+ col = box.column(align=True)
71
+ col.label(text="Pause", icon='POSE_HLT')
72
+ row = col.row(align=True)
73
+
74
+ sub_row = row.row(align=True)
75
+ op = sub_row.operator('wm.context_set_int', icon='ARMATURE_DATA', text="Original")
76
+ op.data_path, op.value = 'scene.frame_current', 1
77
+ if context.scene.frame_current % 2:
78
+ sub_row.enabled = False
79
+
80
+ sub_row = row.row(align=True)
81
+ op = sub_row.operator('wm.context_set_int', icon='POSE_DATA', text="Pose data")
82
+ op.data_path, op.value = 'scene.frame_current', 0
83
+ if not context.scene.frame_current % 2:
84
+ sub_row.enabled = False
85
+
86
+ class decode_cm3d2_bone_names(bpy.types.Operator):
87
+ bl_idname = 'armature.decode_cm3d2_bone_names'
88
+ bl_label = " Decode CM3D2 bone names→Blender bones names"
89
+ bl_description = "Bone names are converted to Blender bone names for mirror functions."
90
+ bl_options = {'REGISTER', 'UNDO'}
91
+
92
+ @classmethod
93
+ def poll(cls, context):
94
+ import re
95
+ ob = context.active_object
96
+ if ob:
97
+ if ob.type == 'ARMATURE':
98
+ arm = ob.data
99
+ for bone in arm.bones:
100
+ if re.search(r'[_ ]([rRlL])[_ ]', bone.name):
101
+ return True
102
+ return False
103
+
104
+ def execute(self, context):
105
+ ob = context.active_object
106
+ arm = ob.data
107
+ convert_count = 0
108
+ for bone in arm.bones:
109
+ bone_name = common.decode_bone_name(bone.name)
110
+ if bone_name != bone.name:
111
+ bone.name = bone_name
112
+ convert_count += 1
113
+ if convert_count == 0:
114
+ self.report(type={'WARNING'}, message="No convertible names were found. Aborting.")
115
+ else:
116
+ self.report(type={'INFO'}, message="Bones names were converted for Blender. Mission Accomplished.")
117
+ return {'FINISHED'}
118
+
119
+ class encode_cm3d2_bone_names(bpy.types.Operator):
120
+ bl_idname = 'armature.encode_cm3d2_bone_names'
121
+ bl_label = "Blender bone names→CM3D2 bone names"
122
+ bl_description = "blender bone names are reverted back to CM3D2 bone names."
123
+ bl_options = {'REGISTER', 'UNDO'}
124
+
125
+ @classmethod
126
+ def poll(cls, context):
127
+ import re
128
+ ob = context.active_object
129
+ if ob:
130
+ if ob.type == 'ARMATURE':
131
+ arm = ob.data
132
+ for bone in arm.bones:
133
+ if bone.name.count('*') == 1 and re.search(r'\.([rRlL])$', bone.name):
134
+ return True
135
+ return False
136
+
137
+ def execute(self, context):
138
+ ob = context.active_object
139
+ arm = ob.data
140
+ convert_count = 0
141
+ for bone in arm.bones:
142
+ bone_name = common.encode_bone_name(bone.name)
143
+ if bone_name != bone.name:
144
+ bone.name = bone_name
145
+ convert_count += 1
146
+ if convert_count == 0:
147
+ self.report(type={'WARNING'}, message="A name that cannot be converted was found, Mission failed")
148
+ else:
149
+ self.report(type={'INFO'}, message="Bone names were converted back to CM3D2 Format. Mission Accomplished.")
150
+ return {'FINISHED'}
151
+
152
+ class copy_armature_bone_data_property(bpy.types.Operator):
153
+ bl_idname = 'object.copy_armature_bone_data_property'
154
+ bl_label = "Copy the bone Data"
155
+ bl_description = "Copy the bone Data in the armature custom properties to the clipboard."
156
+ bl_options = {'REGISTER', 'UNDO'}
157
+
158
+ @classmethod
159
+ def poll(cls, context):
160
+ ob = context.active_object
161
+ if ob:
162
+ if ob.type == 'ARMATURE':
163
+ arm = ob.data
164
+ if 'BoneData:0' in arm and 'LocalBoneData:0' in arm:
165
+ return True
166
+ return False
167
+
168
+ def execute(self, context):
169
+ output_text = ""
170
+ ob = context.active_object.data
171
+ pass_count = 0
172
+ if 'BaseBone' in ob:
173
+ output_text += "BaseBone:" + ob['BaseBone'] + "\n"
174
+ for i in range(99999):
175
+ name = "BoneData:" + str(i)
176
+ if name in ob:
177
+ output_text += "BoneData:" + ob[name] + "\n"
178
+ else:
179
+ pass_count += 1
180
+ if 10 < pass_count:
181
+ break
182
+ pass_count = 0
183
+ for i in range(99999):
184
+ name = "LocalBoneData:" + str(i)
185
+ if name in ob:
186
+ output_text += "LocalBoneData:" + ob[name] + "\n"
187
+ else:
188
+ pass_count += 1
189
+ if 10 < pass_count:
190
+ break
191
+ context.window_manager.clipboard = output_text
192
+ self.report(type={'INFO'}, message="Bone Data was copied, mission accomplished.")
193
+ return {'FINISHED'}
194
+
195
+ class paste_armature_bone_data_property(bpy.types.Operator):
196
+ bl_idname = 'object.paste_armature_bone_data_property'
197
+ bl_label = "Paste Bone Data"
198
+ bl_description = "Bone Data is pasted into the Armature custom properties. NOTE: this wil replace any Data in the custom properties."
199
+ bl_options = {'REGISTER', 'UNDO'}
200
+
201
+ @classmethod
202
+ def poll(cls, context):
203
+ ob = context.active_object
204
+ if ob:
205
+ if ob.type == 'ARMATURE':
206
+ clipboard = context.window_manager.clipboard
207
+ if 'BoneData:' in clipboard and 'LocalBoneData:' in clipboard:
208
+ return True
209
+ return False
210
+
211
+ def execute(self, context):
212
+ import re
213
+ ob = context.active_object.data
214
+ pass_count = 0
215
+ for i in range(99999):
216
+ name = "BoneData:" + str(i)
217
+ if name in ob:
218
+ del ob[name]
219
+ else:
220
+ pass_count += 1
221
+ if 10 < pass_count:
222
+ break
223
+ pass_count = 0
224
+ for i in range(99999):
225
+ name = "LocalBoneData:" + str(i)
226
+ if name in ob:
227
+ del ob[name]
228
+ else:
229
+ pass_count += 1
230
+ if 10 < pass_count:
231
+ break
232
+ bone_data_count = 0
233
+ local_bone_data_count = 0
234
+ for line in context.window_manager.clipboard.split("\n"):
235
+ r = re.search('^BaseBone:(.+)$', line)
236
+ if r:
237
+ ob['BaseBone'] = r.groups()[0]
238
+ r = re.search('^BoneData:(.+)$', line)
239
+ if r:
240
+ if line.count(',') == 4:
241
+ info = r.groups()[0]
242
+ name = "BoneData:" + str(bone_data_count)
243
+ ob[name] = info
244
+ bone_data_count += 1
245
+ r = re.search('^LocalBoneData:(.+)$', line)
246
+ if r:
247
+ if line.count(',') == 1:
248
+ info = r.groups()[0]
249
+ name = "LocalBoneData:" + str(local_bone_data_count)
250
+ ob[name] = info
251
+ local_bone_data_count += 1
252
+ self.report(type={'INFO'}, message="Bone Data was pasted, mission accomplished")
253
+ return {'FINISHED'}
254
+
255
+ class remove_armature_bone_data_property(bpy.types.Operator):
256
+ bl_idname = 'object.remove_armature_bone_data_property'
257
+ bl_label = "Remove Bone Data"
258
+ bl_description = "Removes all Bone Data from the armature's custom properties."
259
+ bl_options = {'REGISTER', 'UNDO'}
260
+
261
+ @classmethod
262
+ def poll(cls, context):
263
+ ob = context.active_object
264
+ if ob:
265
+ if ob.type == 'ARMATURE':
266
+ arm = ob.data
267
+ if 'BoneData:0' in arm and 'LocalBoneData:0' in arm:
268
+ return True
269
+ return False
270
+
271
+ def invoke(self, context, event):
272
+ return context.window_manager.invoke_props_dialog(self)
273
+
274
+ def draw(self, context):
275
+ self.layout.label(text="Removes all bone Data from the armature's custom properties.", icon='CANCEL')
276
+
277
+ def execute(self, context):
278
+ ob = context.active_object.data
279
+ pass_count = 0
280
+ if 'BaseBone' in ob:
281
+ del ob['BaseBone']
282
+ for i in range(99999):
283
+ name = "BoneData:" + str(i)
284
+ if name in ob:
285
+ del ob[name]
286
+ else:
287
+ pass_count += 1
288
+ if 10 < pass_count:
289
+ break
290
+ pass_count = 0
291
+ for i in range(99999):
292
+ name = "LocalBoneData:" + str(i)
293
+ if name in ob:
294
+ del ob[name]
295
+ else:
296
+ pass_count += 1
297
+ if 10 < pass_count:
298
+ break
299
+ self.report(type={'INFO'}, message="Bone data was removed, mission accomplished")
300
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_DATA_PT_modifiers.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # �u�v���p�e�B�v�G���A �� �u���f�B�t�@�C�A�v�^�u
2
+ import os, re, sys, bpy, time, bmesh, mathutils, math
3
+ from . import common
4
+
5
+ # ���j���[���ɍ��ڒlj�
6
+ def menu_func(self, context):
7
+ ob = context.active_object
8
+ if ob:
9
+ if ob.type == 'MESH':
10
+ me = ob.data
11
+ if len(ob.modifiers):
12
+ self.layout.operator('object.forced_modifier_apply', icon_value=common.preview_collections['main']['KISS'].icon_id)
13
+
14
+ class forced_modifier_apply(bpy.types.Operator):
15
+ bl_idname = 'object.forced_modifier_apply'
16
+ bl_label = "Force Modifiers"
17
+ bl_description = "Will force any modifiers if the mesh has shape keys."
18
+ bl_options = {'REGISTER', 'UNDO'}
19
+
20
+ custom_normal_blend = bpy.props.FloatProperty(name="CM3d2 Blending ratio", default=0.5, min=0, max=1, soft_min=0, soft_max=1, step=3, precision=0)
21
+ is_applies = bpy.props.BoolVectorProperty(name="Apply", size=32, options={'SKIP_SAVE'})
22
+
23
+ @classmethod
24
+ def poll(cls, context):
25
+ ob = context.active_object
26
+ return len(ob.modifiers)
27
+
28
+ def invoke(self, context, event):
29
+ ob = context.active_object
30
+ if len(ob.modifiers) == 0:
31
+ return {'CANCELLED'}
32
+ return context.window_manager.invoke_props_dialog(self)
33
+
34
+ def draw(self, context):
35
+ self.layout.prop(self, 'custom_normal_blend', icon='SNAP_NORMAL', slider=True)
36
+ self.layout.label("Apply")
37
+ ob = context.active_object
38
+ for index, mod in enumerate(ob.modifiers):
39
+ icon = 'MOD_%s' % mod.type
40
+ try:
41
+ self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon=icon)
42
+ except:
43
+ self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon='MODIFIER')
44
+
45
+ if mod.show_viewport:
46
+ self.is_applies[index] = True
47
+
48
+ def execute(self, context):
49
+ bpy.ops.object.mode_set(mode='OBJECT')
50
+ ob = context.active_object
51
+ me = ob.data
52
+ is_shaped = bool(me.shape_keys)
53
+
54
+ pre_selected_objects = context.selected_objects[:]
55
+ pre_mode = ob.mode
56
+
57
+ if is_shaped:
58
+ pre_relative_keys = [s.relative_key.name for s in me.shape_keys.key_blocks]
59
+ pre_active_shape_key_index = ob.active_shape_key_index
60
+
61
+ shape_names = [s.name for s in me.shape_keys.key_blocks]
62
+ shape_deforms = []
63
+ for shape in me.shape_keys.key_blocks:
64
+ shape_deforms.append([shape.data[v.index].co.copy() for v in me.vertices])
65
+
66
+ ob.active_shape_key_index = len(me.shape_keys.key_blocks) - 1
67
+ for i in me.shape_keys.key_blocks[:]:
68
+ ob.shape_key_remove(ob.active_shape_key)
69
+
70
+ new_shape_deforms = []
71
+ for shape_index, deforms in enumerate(shape_deforms):
72
+
73
+ temp_ob = ob.copy()
74
+ temp_me = me.copy()
75
+ temp_ob.data = temp_me
76
+ context.scene.objects.link(temp_ob)
77
+
78
+ for vert in temp_me.vertices:
79
+ vert.co = deforms[vert.index].copy()
80
+
81
+ override = context.copy()
82
+ override['object'] = temp_ob
83
+ for index, mod in enumerate(temp_ob.modifiers):
84
+ if self.is_applies[index]:
85
+ try:
86
+ bpy.ops.object.modifier_apply(override, modifier=mod.name)
87
+ except:
88
+ ob.modifiers.remove(mod)
89
+
90
+ new_shape_deforms.append([v.co.copy() for v in temp_me.vertices])
91
+
92
+ common.remove_data(temp_ob)
93
+ common.remove_data(temp_me)
94
+
95
+ if ob.active_shape_key_index != 0:
96
+ ob.active_shape_key_index = 0
97
+ me.update()
98
+
99
+ copy_modifiers = ob.modifiers[:]
100
+
101
+ for index, mod in enumerate(copy_modifiers):
102
+ if self.is_applies[index] and mod.type != 'ARMATURE':
103
+
104
+ if mod.type == 'MIRROR':
105
+ for vg in ob.vertex_groups[:]:
106
+ replace_list = ((r'\.L$', ".R"), (r'\.R$', ".L"), (r'\.l$', ".r"), (r'\.r$', ".l"), (r'_L$', "_R"), (r'_R$', "_L"), (r'_l$', "_r"), (r'_r$', "_l"))
107
+ for before, after in replace_list:
108
+ mirrored_name = re.sub(before, after, vg.name)
109
+ if mirrored_name not in ob.vertex_groups:
110
+ ob.vertex_groups.new(mirrored_name)
111
+
112
+ try:
113
+ bpy.ops.object.modifier_apply(modifier=mod.name)
114
+ except:
115
+ ob.modifiers.remove(mod)
116
+
117
+ arm_ob = None
118
+ for mod in ob.modifiers:
119
+ if mod.type == "ARMATURE":
120
+ arm_ob = mod.object
121
+
122
+ if arm_ob:
123
+ bpy.ops.object.mode_set(mode='EDIT')
124
+ bpy.ops.object.mode_set(mode='OBJECT')
125
+
126
+ arm = arm_ob.data
127
+ arm_pose = arm_ob.pose
128
+
129
+ pose_quats = {}
130
+ for bone in arm.bones:
131
+ pose_bone = arm_pose.bones[bone.name]
132
+
133
+ bone_quat = bone.matrix_local.to_quaternion()
134
+ pose_quat = pose_bone.matrix.to_quaternion()
135
+ result_quat = pose_quat * bone_quat.inverted()
136
+
137
+ pose_quats[bone.name] = result_quat.copy()
138
+
139
+ custom_normals = []
140
+ for loop in me.loops:
141
+ vert = me.vertices[loop.vertex_index]
142
+ no = vert.normal.copy()
143
+
144
+ total_weight = 0.0
145
+ for vge in vert.groups:
146
+ vg = ob.vertex_groups[vge.group]
147
+ try:
148
+ pose_quats[vg.name]
149
+ except KeyError:
150
+ continue
151
+ total_weight += vge.weight
152
+
153
+ total_quat = mathutils.Quaternion()
154
+ for vge in vert.groups:
155
+ vg = ob.vertex_groups[vge.group]
156
+ try:
157
+ total_quat = total_quat.slerp(pose_quats[vg.name], vge.weight / total_weight)
158
+ except KeyError:
159
+ pass
160
+
161
+ no.rotate(total_quat)
162
+ custom_normals.append(no)
163
+
164
+ for index, mod in enumerate(copy_modifiers):
165
+ if self.is_applies[index] and mod.type == 'ARMATURE':
166
+ try:
167
+ bpy.ops.object.modifier_apply(modifier=mod.name)
168
+ except:
169
+ ob.modifiers.remove(mod)
170
+
171
+ context.scene.objects.active = ob
172
+
173
+ if is_shaped:
174
+
175
+ for deforms in new_shape_deforms:
176
+ if len(me.vertices) != len(deforms):
177
+ self.report(type={'ERROR'}, message="Since the number of vertices has changed due to mirror etc, The shape key can not be stored. Please undo with Ctrl + Z or other.")
178
+ return {'CANCELLED'}
179
+
180
+ for shape_index, deforms in enumerate(new_shape_deforms):
181
+
182
+ bpy.ops.object.shape_key_add(from_mix=False)
183
+ shape = ob.active_shape_key
184
+ shape.name = shape_names[shape_index]
185
+
186
+ for vert in me.vertices:
187
+ shape.data[vert.index].co = deforms[vert.index].copy()
188
+
189
+ for shape_index, shape in enumerate(me.shape_keys.key_blocks):
190
+ shape.relative_key = me.shape_keys.key_blocks[pre_relative_keys[shape_index]]
191
+
192
+ ob.active_shape_key_index = pre_active_shape_key_index
193
+
194
+ for temp_ob in pre_selected_objects:
195
+ temp_ob.select = True
196
+ bpy.ops.object.mode_set(mode=pre_mode)
197
+
198
+ if arm_ob:
199
+ for i, loop in enumerate(me.loops):
200
+ vert = me.vertices[loop.vertex_index]
201
+ no = vert.normal.copy()
202
+
203
+ try:
204
+ custom_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(custom_normals[i])
205
+ except:
206
+ continue
207
+ original_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(no)
208
+ output_rot = original_rot.slerp(custom_rot, self.custom_normal_blend)
209
+
210
+ output_no = mathutils.Vector((0.0, 0.0, 1.0))
211
+ output_no.rotate(output_rot)
212
+
213
+ custom_normals[i] = output_no
214
+ me.use_auto_smooth = True
215
+ me.normals_split_custom_set(custom_normals)
216
+
217
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_DATA_PT_vertex_groups.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「メッシュデータ」タブ → 「頂点グループ」パネル
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ import re
8
+ ob = context.active_object
9
+ if not ob: return
10
+ if not len(ob.vertex_groups) and ob.type != 'MESH': return
11
+
12
+ flag = False
13
+ for vertex_group in ob.vertex_groups:
14
+ if not flag and re.search(r'[_ ]([rRlL])[_ ]', vertex_group.name):
15
+ flag = True
16
+ if not flag and vertex_group.name.count('*') == 1:
17
+ if re.search(r'\.([rRlL])$', vertex_group.name):
18
+ flag = True
19
+ if flag:
20
+ col = self.layout.column(align=True)
21
+ col.label(text="Convert names for CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
22
+ row = col.row(align=True)
23
+ row.operator('object.decode_cm3d2_vertex_group_names', icon='BLENDER', text="CM3D2 → Blender")
24
+ row.operator('object.encode_cm3d2_vertex_group_names', icon_value=common.preview_collections['main']['KISS'].icon_id, text="Blender → CM3D2")
25
+ break
26
+
27
+ class decode_cm3d2_vertex_group_names(bpy.types.Operator):
28
+ bl_idname = 'object.decode_cm3d2_vertex_group_names'
29
+ bl_label = "Convert Vertex Group Names for Blender"
30
+ bl_description = "Names are converted for use with Blender's mirror functions."
31
+ bl_options = {'REGISTER', 'UNDO'}
32
+
33
+ @classmethod
34
+ def poll(cls, context):
35
+ import re
36
+ ob = context.active_object
37
+ if ob:
38
+ if ob.type == 'MESH':
39
+ if ob.vertex_groups.active:
40
+ for vg in ob.vertex_groups:
41
+ if re.search(r'[_ ]([rRlL])[_ ]', vg.name):
42
+ return True
43
+ return False
44
+
45
+ def execute(self, context):
46
+ ob = context.active_object
47
+ me = ob.data
48
+ convert_count = 0
49
+ context.window_manager.progress_begin(0, len(ob.vertex_groups))
50
+ for vg_index, vg in enumerate(ob.vertex_groups[:]):
51
+ context.window_manager.progress_update(vg_index)
52
+ vg_name = common.decode_bone_name(vg.name)
53
+ if vg_name != vg.name:
54
+ if vg_name in ob.vertex_groups:
55
+ target_vg = ob.vertex_groups[vg_name]
56
+ for vert in me.vertices:
57
+ try:
58
+ weight = vg.weight(vert.index)
59
+ except:
60
+ weight = 0.0
61
+ try:
62
+ target_weight = target_vg.weight(vert.index)
63
+ except:
64
+ target_weight = 0.0
65
+ if 0.0 < weight + target_weight:
66
+ target_vg.add([vert.index], weight + target_weight, 'REPLACE')
67
+ ob.vertex_groups.remove(vg)
68
+ else:
69
+ vg.name = vg_name
70
+ convert_count += 1
71
+ if convert_count == 0:
72
+ self.report(type={'WARNING'}, message="A Name that could not be converted was found. Mission Failed.")
73
+ else:
74
+ self.report(type={'INFO'}, message="Vertex group names were converted for Blender. Mission Accomplished.")
75
+ context.window_manager.progress_end()
76
+ return {'FINISHED'}
77
+
78
+ class encode_cm3d2_vertex_group_names(bpy.types.Operator):
79
+ bl_idname = 'object.encode_cm3d2_vertex_group_names'
80
+ bl_label = "Convert vertex group names for CM3D2"
81
+ bl_description = "Converts bone names for CM3D2."
82
+ bl_options = {'REGISTER', 'UNDO'}
83
+
84
+ @classmethod
85
+ def poll(cls, context):
86
+ import re
87
+ ob = context.active_object
88
+ if ob:
89
+ if ob.type == 'MESH':
90
+ if ob.vertex_groups.active:
91
+ for vg in ob.vertex_groups:
92
+ if vg.name.count('*') == 1 and re.search(r'\.([rRlL])$', vg.name):
93
+ return True
94
+ return False
95
+
96
+ def execute(self, context):
97
+ ob = context.active_object
98
+ me = ob.data
99
+ convert_count = 0
100
+ context.window_manager.progress_begin(0, len(ob.vertex_groups))
101
+ for vg_index, vg in enumerate(ob.vertex_groups[:]):
102
+ context.window_manager.progress_update(vg_index)
103
+ vg_name = common.encode_bone_name(vg.name)
104
+ if vg_name != vg.name:
105
+ if vg_name in ob.vertex_groups:
106
+ target_vg = ob.vertex_groups[vg_name]
107
+ for vert in me.vertices:
108
+ try:
109
+ weight = vg.weight(vert.index)
110
+ except:
111
+ weight = 0.0
112
+ try:
113
+ target_weight = target_vg.weight(vert.index)
114
+ except:
115
+ target_weight = 0.0
116
+ if 0.0 < weight + target_weight:
117
+ target_vg.add([vert.index], weight + target_weight, 'REPLACE')
118
+ ob.vertex_groups.remove(vg)
119
+ else:
120
+ vg.name = vg_name
121
+ convert_count += 1
122
+ if convert_count == 0:
123
+ self.report(type={'WARNING'}, message="A Name that could not be converted was found. Mission Failed.")
124
+ else:
125
+ self.report(type={'INFO'}, message="Names were converted for CM3D2. Mission Accomplished")
126
+ context.window_manager.progress_end()
127
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_IMAGE_HT_header.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「UV/画像エディター」エリア → ヘッダー
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ if 'edit_image' in dir(context):
8
+ img = context.edit_image
9
+ if img:
10
+ if 'cm3d2_path' in img:
11
+ self.layout.label(text="For CM3D2: Internal Path", icon_value=common.preview_collections['main']['KISS'].icon_id)
12
+ row = self.layout.row()
13
+ row.prop(img, '["cm3d2_path"]', text="")
14
+ row.scale_x = 3.0
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_IMAGE_PT_image_properties.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「UV/画像エディター」エリア → プロパティ → 「画像」パネル
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ if 'edit_image' in dir(context):
8
+ img = context.edit_image
9
+ if 'cm3d2_path' in img:
10
+ box = self.layout.box()
11
+ box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
12
+ box.prop(img, '["cm3d2_path"]', icon='ANIM_DATA', text="Internal Path")
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_HT_header.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 画面右上 (「情報」エリア → ヘッダー)
2
+ import bpy, bmesh
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ self.layout.operator('mesh.vertices_count_checker', icon_value=common.preview_collections['main']['KISS'].icon_id)
8
+
9
+ class vertices_count_checker(bpy.types.Operator):
10
+ bl_idname = 'mesh.vertices_count_checker'
11
+ bl_label = "Check Vertice Count"
12
+ bl_description = "Check whether the exporter can output the selected mesh."
13
+ bl_options = {'REGISTER', 'UNDO'}
14
+
15
+ @classmethod
16
+ def poll(cls, context):
17
+ ob = context.active_object
18
+ if ob:
19
+ if ob.type == 'MESH':
20
+ return True
21
+ return False
22
+
23
+ def execute(self, context):
24
+ me = context.object.data
25
+ if not me.uv_layers.active:
26
+ self.report(type={'ERROR'}, message="No UV Map. Cannot be Counted.")
27
+ return {'FINISHED'}
28
+ bm = bmesh.new()
29
+ bm.from_mesh(me)
30
+
31
+ alreadys = {}
32
+ uv_lay = bm.loops.layers.uv.active
33
+
34
+ for face in bm.faces:
35
+ for loop in face.loops:
36
+ info = (loop.vert.index, loop[uv_lay].uv.x, loop[uv_lay].uv.y)
37
+ if info not in alreadys:
38
+ alreadys[info] = None
39
+ bm.free()
40
+
41
+ inner_count = len(alreadys)
42
+ real_count = len(me.vertices)
43
+ if inner_count <= 65535:
44
+ self.report(type={'ERROR'}, message="Good, There is space for more vertices, you may add %d more vertices (Vertices:%d(+%d) UV Splitting:+%d%)" % (65535 - inner_count, real_count, inner_count - real_count, int(inner_count / real_count * 100)))
45
+ else:
46
+ self.report(type={'ERROR'}, message="X, Too many vertices、please remove %d Vertices (Vertices:%d(+%d) Uv Splitting:+%d%)" % (inner_count - 65535, real_count, inner_count - real_count, int(inner_count / real_count * 100)))
47
+
48
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_MT_add.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「3Dビュー」エリア → 追加(Shift+A) → CM3D2
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ self.layout.separator()
8
+ self.layout.menu('misc_INFO_MT_add_cm3d2', icon_value=common.preview_collections['main']['KISS'].icon_id)
9
+
10
+ # サブメニュー
11
+ class misc_INFO_MT_add_cm3d2(bpy.types.Menu):
12
+ bl_idname = 'misc_INFO_MT_add_cm3d2'
13
+ bl_label = "CM3D2"
14
+
15
+ def draw(self, context):
16
+ self.layout.operator('wm.append_cm3d2_figure', text="body001", icon_value=common.preview_collections['main']['KISS'].icon_id).object_name = "body001.body"
17
+ self.layout.separator()
18
+ self.layout.operator('wm.append_cm3d2_figure', text="Large boob shapekey Body", icon='ROTATECOLLECTION').object_name = "乳袋防止素体"
19
+ self.layout.separator()
20
+ self.layout.operator('wm.append_cm3d2_figure', text="T Pose Body", icon='ARMATURE_DATA').object_name = "Tスタンス素体"
21
+ self.layout.operator('wm.append_cm3d2_figure', text="Legs only T pose Body", icon='SOUND').object_name = "Tスタンス素体 足のみ"
22
+ self.layout.operator('wm.append_cm3d2_figure', text="Arms only T pose Body", icon='OUTLINER_DATA_ARMATURE').object_name = "Tスタンス素体 手のみ"
23
+ self.layout.separator()
24
+ self.layout.operator('wm.append_cm3d2_figure', text="Rig for anm output", icon='OUTLINER_OB_ARMATURE').object_name = "anm出力用リグ・身体メッシュ"
25
+ self.layout.operator('wm.append_cm3d2_figure', text="Alternative Rig (Neerhom's)", icon='OUTLINER_OB_ARMATURE').object_name = "alt_rig_armature"
26
+ self.layout.operator('wm.append_cm3d2_figure', text="Rig for anm output(Man)", icon='MOD_ARMATURE').object_name = "anm出力用リグ(男)・身体メッシュ"
27
+
28
+ class append_cm3d2_figure(bpy.types.Operator):
29
+ bl_idname = 'wm.append_cm3d2_figure'
30
+ bl_label = "Import CM3D2 Body"
31
+ bl_description = "Allows you to import the Body from CM3D2. (Warning: Will not work well with posing and animations.)"
32
+ bl_options = {'REGISTER', 'UNDO'}
33
+
34
+ object_name = bpy.props.StringProperty(name="素体名")
35
+
36
+ def execute(self, context):
37
+ if bpy.ops.object.mode_set.poll():
38
+ bpy.ops.object.mode_set(mode='OBJECT')
39
+ if bpy.ops.object.select_all.poll():
40
+ bpy.ops.object.select_all(action='DESELECT')
41
+
42
+ blend_path = os.path.join(os.path.dirname(__file__), "append_data.blend")
43
+ with context.blend_data.libraries.load(blend_path) as (data_from, data_to):
44
+ data_to.objects = [self.object_name]
45
+
46
+ ob = data_to.objects[0]
47
+ context.scene.objects.link(ob)
48
+ context.scene.objects.active = ob
49
+ ob.select = True
50
+
51
+ for mod in ob.modifiers:
52
+ if mod.type == 'ARMATURE':
53
+ context.scene.objects.link(mod.object)
54
+ mod.object.select = True
55
+
56
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_MT_curve_add.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「3Dビュー」エリア → 追加(Shift+A) → カーブ
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ self.layout.separator()
8
+ self.layout.operator('curve.hair_bunch_add', text="Add Hair Curve", icon_value=common.preview_collections['main']['KISS'].icon_id)
9
+
10
+ class hair_bunch_add(bpy.types.Operator):
11
+ bl_idname = 'curve.hair_bunch_add'
12
+ bl_label = "Add A Lock of Hair"
13
+ bl_description = "Will add an anime style hair lock at the 3D Cursor."
14
+ bl_options = {'REGISTER', 'UNDO'}
15
+
16
+ radius = bpy.props.FloatProperty(name="Radius", default=0.1, min=0, max=10, soft_min=0, soft_max=10, step=10, precision=2)
17
+ random_multi = bpy.props.FloatProperty(name="Randomness", default=0.5, min=0, max=10, soft_min=0, soft_max=10, step=10, precision=2)
18
+ z_plus = bpy.props.FloatProperty(name="Medium Z Axis Height", default=0.1, min=0, max=10, soft_min=0, soft_max=10, step=10, precision=2)
19
+
20
+ @classmethod
21
+ def poll(cls, context):
22
+ return True
23
+
24
+ def invoke(self, context, event):
25
+ import bpy_extras.view3d_utils
26
+
27
+ self.pre_draw = bpy.types.VIEW3D_HT_header.draw
28
+ def header_draw(self, context):
29
+ row = self.layout.row(align=True)
30
+ row.label(text="Mouse Wheel:Change Thickness")
31
+ row.label(text="Middle Mouse Button:Random Intensity Change")
32
+ row.label(text="Z/X Keys:Height Change")
33
+ bpy.types.VIEW3D_HT_header.draw = header_draw
34
+
35
+ if context.active_object:
36
+ if context.active_object.mode != 'OBJECT':
37
+ self.report(type={'ERROR'}, message="Please add in Object mode only.")
38
+ return {'CANCELLED'}
39
+
40
+ self.end_location = bpy_extras.view3d_utils.region_2d_to_location_3d(context.region, context.region_data, (event.mouse_region_x, event.mouse_region_y), context.space_data.cursor_location)
41
+
42
+ curve = context.blend_data.curves.new("Hair Bunch", 'CURVE')
43
+ ob = context.blend_data.objects.new("Hair Bunch", curve)
44
+ context.scene.objects.link(ob)
45
+ context.scene.objects.active = ob
46
+ ob.select = True
47
+
48
+ curve.dimensions = '3D'
49
+ curve.resolution_u = 5
50
+
51
+ spline = curve.splines.new('NURBS')
52
+
53
+ spline.points.add(3)
54
+ spline.points[0].radius = 0.0
55
+ spline.points[-1].radius = 0.0
56
+ spline.use_endpoint_u = True
57
+ spline.order_u = 4
58
+ spline.resolution_u = 5
59
+
60
+ self.set_spline(spline, context)
61
+
62
+ self.object = ob
63
+ self.curve = curve
64
+ self.spline = spline
65
+
66
+ bevel_curve = context.blend_data.curves.new("Hair Bunch Bevel", 'CURVE')
67
+ bevel_ob = context.blend_data.objects.new("Hair Bunch Bevel", bevel_curve)
68
+ context.scene.objects.link(bevel_ob)
69
+ bevel_ob.select = True
70
+ curve.bevel_object = bevel_ob
71
+
72
+ bevel_ob.parent = ob
73
+ bevel_ob.parent_type = 'VERTEX'
74
+ bevel_ob.parent_vertices = (3, 3, 3)
75
+
76
+ bevel_curve.dimensions = '2D'
77
+ bevel_curve.fill_mode = 'NONE'
78
+ bevel_curve.resolution_u = 2
79
+
80
+ spline = bevel_curve.splines.new('NURBS')
81
+ spline.points.add(7)
82
+ spline.use_cyclic_u = True
83
+ spline.order_u = 4
84
+ spline.resolution_u = 2
85
+
86
+ self.bevel_object = bevel_ob
87
+ self.bevel_curve = bevel_curve
88
+ self.bevel_spline = spline
89
+
90
+ self.set_bevel_spline(spline)
91
+
92
+ context.window_manager.modal_handler_add(self)
93
+ return {'RUNNING_MODAL'}
94
+
95
+ def modal(self, context, event):
96
+ import bpy_extras.view3d_utils
97
+
98
+ #print(event.type, event.value)
99
+
100
+ if event.type == 'MOUSEMOVE':
101
+ self.end_location = bpy_extras.view3d_utils.region_2d_to_location_3d(context.region, context.region_data, (event.mouse_region_x, event.mouse_region_y), context.space_data.cursor_location)
102
+ self.execute(context)
103
+
104
+ elif event.type == 'WHEELUPMOUSE' and event.value == 'PRESS':
105
+ self.radius += 0.05
106
+ self.set_bevel_spline(self.bevel_spline)
107
+ self.object.update_tag({'OBJECT', 'DATA'})
108
+ elif event.type == 'WHEELDOWNMOUSE' and event.value == 'PRESS':
109
+ self.radius -= 0.05
110
+ self.set_bevel_spline(self.bevel_spline)
111
+ self.object.update_tag({'OBJECT', 'DATA'})
112
+
113
+ elif event.type == 'MIDDLEMOUSE' and event.value == 'PRESS':
114
+ if 0.9 < self.random_multi:
115
+ self.random_multi = 0.0
116
+ elif 0.4 < self.random_multi:
117
+ self.random_multi = 1.0
118
+ else:
119
+ self.random_multi = 0.5
120
+ self.set_bevel_spline(self.bevel_spline)
121
+
122
+ elif event.type == 'Z' and event.value == 'PRESS':
123
+ self.z_plus += 0.1
124
+ self.execute(context)
125
+ elif event.type == 'X' and event.value == 'PRESS':
126
+ self.z_plus -= 0.1
127
+ self.execute(context)
128
+
129
+ elif event.type == 'LEFTMOUSE' and event.value == 'PRESS':
130
+ bpy.types.VIEW3D_HT_header.draw = self.pre_draw
131
+ context.area.tag_redraw()
132
+ return {'FINISHED'}
133
+
134
+ elif event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'PRESS':
135
+ common.remove_data([self.object, self.bevel_object, self.curve, self.bevel_curve])
136
+ bpy.types.VIEW3D_HT_header.draw = self.pre_draw
137
+ context.area.tag_redraw()
138
+ return {'CANCELLED'}
139
+
140
+ return {'RUNNING_MODAL'}
141
+
142
+ def get_random_point(self, co):
143
+ import random
144
+ r = self.radius * self.random_multi
145
+ co.x = co.x + random.uniform(-r, r)
146
+ co.y = co.y + random.uniform(-r, r)
147
+ return co
148
+
149
+ def set_bevel_spline(self, spline):
150
+ import math, mathutils
151
+ r = self.radius
152
+ vec = mathutils.Vector((0, r, 0))
153
+ min_rad = -math.radians(360 / len(spline.points))
154
+ for index, point in enumerate(spline.points):
155
+ eul = mathutils.Euler((0, 0, min_rad * index), 'XYZ')
156
+ now_vec = vec.copy()
157
+ now_vec.rotate(eul)
158
+ now_vec = self.get_random_point(now_vec)
159
+ point.co = list(now_vec[:]) + [1]
160
+
161
+ def set_spline(self, spline, context):
162
+ diff_co = self.end_location - context.space_data.cursor_location
163
+
164
+ plus_co = diff_co * 0.333333
165
+ plus_co.z = -plus_co.z + self.z_plus
166
+
167
+ point1 = diff_co * 0.333333
168
+ point1 += plus_co * 1
169
+ point1 += context.space_data.cursor_location
170
+
171
+ point2 = diff_co * 0.666666
172
+ point2 += plus_co * 1
173
+ point2 += context.space_data.cursor_location
174
+
175
+ spline.points[0].co = list(context.space_data.cursor_location[:]) + [1]
176
+ spline.points[1].co = list(point1[:]) + [1]
177
+ spline.points[2].co = list(point2[:]) + [1]
178
+ spline.points[-1].co = list(self.end_location[:]) + [1]
179
+
180
+ def execute(self, context):
181
+ try:
182
+ self.set_spline(self.spline, context)
183
+ except:
184
+ self.report(type={'ERROR'}, message="Please run in Object mode. Note: Script is Buggy.")
185
+ return {'CANCELLED'}
186
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_INFO_MT_help.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 画面上部 (「情報」エリア → ヘッダー) → ヘルプ
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ icon_id = common.preview_collections['main']['KISS'].icon_id
8
+ self.layout.separator()
9
+ self.layout.operator('script.update_cm3d2_converter', icon_value=icon_id)
10
+ self.layout.operator('wm.call_menu', icon_value=icon_id, text="CM3D2 Converter Update History").name = 'INFO_MT_help_CM3D2_Converter_RSS'
11
+ self.layout.operator('wm.show_cm3d2_converter_preference', icon_value=icon_id)
12
+
13
+ # 更新履歴メニュー
14
+ class INFO_MT_help_CM3D2_Converter_RSS(bpy.types.Menu):
15
+ bl_idname = 'INFO_MT_help_CM3D2_Converter_RSS'
16
+ bl_label = "CM3D2 Converter Update History"
17
+
18
+ def draw(self, context):
19
+ try:
20
+ import re, urllib, datetime, urllib.request, xml.sax.saxutils
21
+ response = urllib.request.urlopen("https://github.com/CM3Duser/Blender-CM3D2-Converter/commits/master.atom")
22
+ html = response.read().decode('utf-8')
23
+ titles = re.findall(r'\<title\>[ \s]*([^ \s][^\<]*[^ \s])[ \s]*\<\/title\>', html)[1:]
24
+ updates = re.findall(r'\<updated\>([^\<\>]*)\<\/updated\>', html)[1:]
25
+ links = re.findall(r'<link [^\<\>]*href="([^"]+)"/>', html)[2:]
26
+ version_datetime = datetime.datetime.strptime(str(common.bl_info["version"][0]) + "," + str(common.bl_info["version"][1]) + "," + str(common.bl_info["version"][2]) + "," + str(common.bl_info["version"][3]) + "," + str(common.bl_info["version"][4]) + "," + str(common.bl_info["version"][5]), '%Y,%m,%d,%H,%M,%S')
27
+
28
+ output_data = []
29
+ update_diffs = []
30
+ for title, update, link in zip(titles, updates, links):
31
+ title = xml.sax.saxutils.unescape(title, {'&quot;': '"'})
32
+
33
+ rss_datetime = datetime.datetime.strptime(update, '%Y-%m-%dT%H:%M:%SZ') + datetime.timedelta(hours=9)
34
+ diff_seconds = datetime.datetime.now() - rss_datetime
35
+ icon = 'SORTTIME'
36
+ if 60 * 60 * 24 * 7 < diff_seconds.total_seconds():
37
+ icon = 'NLA'
38
+ elif 60 * 60 * 24 * 3 < diff_seconds.total_seconds():
39
+ icon = 'COLLAPSEMENU'
40
+ elif 60 * 60 * 24 < diff_seconds.total_seconds():
41
+ icon = 'TIME'
42
+ elif 60 * 60 < diff_seconds.total_seconds():
43
+ icon = 'RECOVER_LAST'
44
+ else:
45
+ icon = 'PREVIEW_RANGE'
46
+
47
+ if 60 * 60 * 24 <= diff_seconds.total_seconds():
48
+ date_str = "%d日前" % int(diff_seconds.total_seconds() / 60 / 60 / 24)
49
+ elif 60 * 60 <= diff_seconds.total_seconds():
50
+ date_str = "%d時間前" % int(diff_seconds.total_seconds() / 60 / 60)
51
+ elif 60 <= diff_seconds.total_seconds():
52
+ date_str = "%d分前" % int(diff_seconds.total_seconds() / 60)
53
+ else:
54
+ date_str = "%d秒前" % diff_seconds.total_seconds()
55
+
56
+ text = "(" + date_str + ") " + title
57
+
58
+ update_diff = abs( (version_datetime - rss_datetime).total_seconds() )
59
+
60
+ output_data.append((text, icon, link, update_diff))
61
+ update_diffs.append(update_diff)
62
+
63
+ min_update_diff = sorted(update_diffs)[0]
64
+ for text, icon, link, update_diff in output_data:
65
+
66
+ if update_diff == min_update_diff:
67
+ text = "Now! " + text
68
+ icon = 'QUESTION'
69
+
70
+ self.layout.operator('wm.url_open', text=text, icon=icon).url = link
71
+ except:
72
+ self.layout.label(text="Failed to Download Update.", icon='ERROR')
73
+
74
+ class update_cm3d2_converter(bpy.types.Operator):
75
+ bl_idname = 'script.update_cm3d2_converter'
76
+ bl_label = "Update CM3D2 Converter (WARNING: COULD REMOVE TRANSLATIONS)"
77
+ bl_description = "Will quickly download the latest CM3D2 Converter from the Github Page."
78
+ bl_options = {'REGISTER'}
79
+
80
+ is_restart = bpy.props.BoolProperty(name="Restart Blender After Updating", default=True)
81
+ is_toggle_console = bpy.props.BoolProperty(name="Close the Console after Restart", default=True)
82
+
83
+ def invoke(self, context, event):
84
+ return context.window_manager.invoke_props_dialog(self)
85
+
86
+ def draw(self, context):
87
+ self.layout.menu('INFO_MT_help_CM3D2_Converter_RSS', icon='INFO')
88
+ self.layout.prop(self, 'is_restart', icon='BLENDER')
89
+ self.layout.prop(self, 'is_toggle_console', icon='CONSOLE')
90
+
91
+ def execute(self, context):
92
+ import os, sys, urllib, zipfile, subprocess, urllib.request
93
+
94
+ zip_path = os.path.join(bpy.app.tempdir, "Blender-CM3D2-Converter-master.zip")
95
+ addon_path = os.path.dirname(__file__)
96
+
97
+ response = urllib.request.urlopen("https://github.com/CM3Duser/Blender-CM3D2-Converter/archive/master.zip")
98
+ zip_file = open(zip_path, "wb")
99
+ zip_file.write(response.read())
100
+ zip_file.close()
101
+
102
+ zip_file = zipfile.ZipFile(zip_path, "r")
103
+ for path in zip_file.namelist():
104
+ if not os.path.basename(path):
105
+ continue
106
+ sub_dir = os.path.split( os.path.split(path)[0] )[1]
107
+ if sub_dir == "CM3D2 Converter":
108
+ file = open(os.path.join(addon_path, os.path.basename(path)), 'wb')
109
+ file.write(zip_file.read(path))
110
+ file.close()
111
+ zip_file.close()
112
+
113
+ if self.is_restart:
114
+ filepath = bpy.data.filepath
115
+ command_line = [sys.argv[0]]
116
+ if filepath:
117
+ command_line.append(filepath)
118
+ if self.is_toggle_console:
119
+ py = os.path.join(os.path.dirname(__file__), "console_toggle.py")
120
+ command_line.append('-P')
121
+ command_line.append(py)
122
+ subprocess.Popen(command_line)
123
+ bpy.ops.wm.quit_blender()
124
+ else:
125
+ self.report(type={'INFO'}, message="Converter Updated. Please Reboot Blender.")
126
+ return {'FINISHED'}
127
+
128
+ class show_cm3d2_converter_preference(bpy.types.Operator):
129
+ bl_idname = 'wm.show_cm3d2_converter_preference'
130
+ bl_label = "CM3D2 Converter Settings Screen"
131
+ bl_description = "Will open the plugin's settings in the addon window."
132
+ bl_options = {'REGISTER', 'UNDO'}
133
+
134
+ def execute(self, context):
135
+ import addon_utils
136
+ my_info = None
137
+ for module in addon_utils.modules():
138
+ info = addon_utils.module_bl_info(module)
139
+ if info['name'] == common.addon_name:
140
+ my_info = info
141
+ break
142
+ area = common.get_request_area(context, 'USER_PREFERENCES')
143
+ if area and my_info:
144
+ context.user_preferences.active_section = 'ADDONS'
145
+ context.window_manager.addon_search = my_info['name']
146
+ context.window_manager.addon_filter = 'All'
147
+ if 'COMMUNITY' not in context.window_manager.addon_support:
148
+ context.window_manager.addon_support = {'OFFICIAL', 'COMMUNITY'}
149
+ if not my_info['show_expanded']:
150
+ bpy.ops.wm.addon_expand(module=__name__.split('.')[0])
151
+ else:
152
+ self.report(type={'ERROR'}, message="Could not open the settings window.")
153
+ return {'CANCELLED'}
154
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_MATERIAL_PT_context_material.py ADDED
@@ -0,0 +1,822 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「マテリアル」タブ
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ mate = context.material
8
+ if not mate:
9
+ col = self.layout.column(align=True)
10
+ col.operator('material.new_cm3d2', icon_value=common.preview_collections['main']['KISS'].icon_id)
11
+ row = col.row(align=True)
12
+ row.operator('material.import_cm3d2_mate', icon='FILE_FOLDER', text="Import .Mate")
13
+ row.operator('material.paste_material', icon='PASTEDOWN', text="Paste")
14
+ else:
15
+ if 'shader1' in mate and 'shader2' in mate:
16
+ box = self.layout.box()
17
+ #row = box.split(percentage=0.3)
18
+ row = box.split(percentage=0.5)
19
+ row.label(text="CM3D2 Material", icon_value=common.preview_collections['main']['KISS'].icon_id)
20
+ sub_row = row.row(align=True)
21
+ sub_row.operator('material.export_cm3d2_mate', icon='FILE_FOLDER', text="Export .Mate")
22
+ sub_row.operator('material.copy_material', icon='COPYDOWN', text="Copy")
23
+ sub_row.operator('material.paste_material2', icon='PASTEDOWN', text="Paste")
24
+
25
+ type_name = "Unknown"
26
+ icon = 'ERROR'
27
+ if mate['shader1'] == 'CM3D2/Toony_Lighted':
28
+ type_name = "Toony"
29
+ icon = 'SOLID'
30
+ elif mate['shader1'] == 'CM3D2/Toony_Lighted_Hair':
31
+ type_name = "Toony Hair"
32
+ icon = 'PARTICLEMODE'
33
+ elif mate['shader1'] == 'CM3D2/Toony_Lighted_Trans':
34
+ type_name = "Toony Lighted Trans"
35
+ icon = 'WIRE'
36
+ elif mate['shader1'] == 'CM3D2/Toony_Lighted_Trans_NoZ':
37
+ type_name = "Toony Lighted Trans NoZ"
38
+ icon = 'DRIVER'
39
+ elif mate['shader1'] == 'CM3D2/Toony_Lighted_Outline':
40
+ type_name = "Toony Lighted Outline"
41
+ icon = 'ANTIALIASED'
42
+ elif mate['shader1'] == 'CM3D2/Toony_Lighted_Hair_Outline':
43
+ type_name = "Toony Light Hair Outline"
44
+ icon = 'PARTICLEMODE'
45
+ elif mate['shader1'] == 'CM3D2/Toony_Lighted_Outline_Trans':
46
+ type_name = "Toony Lighted Outline Trans"
47
+ icon = 'PROP_OFF'
48
+ elif mate['shader1'] == 'CM3D2/Lighted_Trans':
49
+ type_name = "Lighted Trans"
50
+ icon = 'VISIBLE_IPO_OFF'
51
+ elif mate['shader1'] == 'CM3D2/Lighted':
52
+ type_name = "Lighted"
53
+ icon = 'MATSPHERE'
54
+ elif mate['shader1'] == 'Unlit/Texture':
55
+ type_name = "Unlit Texture"
56
+ icon = 'PARTICLES'
57
+ elif mate['shader1'] == 'Unlit/Transparent':
58
+ type_name = "Unlit Trans"
59
+ icon = 'MOD_PARTICLES'
60
+ elif mate['shader1'] == 'CM3D2/Mosaic':
61
+ type_name = "Mosiac"
62
+ icon = 'ALIASED'
63
+ elif mate['shader1'] == 'CM3D2/Man':
64
+ type_name = "Man"
65
+ icon = 'ARMATURE_DATA'
66
+ elif mate['shader1'] == 'Diffuse':
67
+ type_name = "Diffuse"
68
+ icon = 'BRUSH_CLAY_STRIPS'
69
+ elif mate['shader1'] == 'Transparent/Diffuse':
70
+ type_name = "Transparent Diffuse"
71
+ icon = 'MATCAP_09'
72
+ elif mate['shader1'] == 'CM3D2_Debug/Debug_CM3D2_Normal2Color':
73
+ type_name = "Debug"
74
+ icon = 'MATCAP_23'
75
+
76
+ row = box.split(percentage=0.333333333333333333333)
77
+ row.label(text="Type:")
78
+ row.label(text=type_name, icon=icon)
79
+ box.prop(mate, 'name', icon='SORTALPHA', text="Material Name")
80
+ box.prop(mate, '["shader1"]', icon='MATERIAL', text="Shader 1")
81
+ box.prop(mate, '["shader2"]', icon='SMOOTH', text="Shader 2")
82
+
83
+ box.operator('material.decorate_material', icon='TEXTURE_SHADED')
84
+
85
+
86
+ if 'CM3D2 Texture Expand' not in mate:
87
+ mate['CM3D2 Texture Expand'] = True
88
+ box = self.layout.box()
89
+ if mate['CM3D2 Texture Expand']:
90
+
91
+ row = box.row()
92
+ row.alignment = 'LEFT'
93
+ op = row.operator('wm.context_set_int', icon='DOWNARROW_HLT', text="", emboss=False)
94
+ op.data_path, op.value, op.relative = 'material["CM3D2 Texture Expand"]', 0, False
95
+ row.label(text="Texture Info", icon_value=common.preview_collections['main']['KISS'].icon_id)
96
+
97
+ for slot in mate.texture_slots:
98
+ if not slot: continue
99
+ if not slot.texture: continue
100
+ tex = slot.texture
101
+ name = common.remove_serial_number(tex.name).replace("_", "") + " "
102
+
103
+ if slot.use: type = 'tex'
104
+ else: type = 'col' if slot.use_rgb_to_intensity else 'f'
105
+
106
+ if type == 'tex':
107
+ row = box.row(align=True)
108
+ sub_row = row.split(percentage=0.333333333333333333333, align=True)
109
+ sub_row.label(text=name, icon_value=sub_row.icon(tex))
110
+ if 'image' in dir(tex):
111
+ if tex.image:
112
+ sub_row.template_ID(tex, 'image')
113
+ row.operator('material.quick_texture_show', text="", icon='RIGHTARROW').texture_name = tex.name
114
+ elif type == 'col':
115
+ row = box.row(align=True)
116
+ sub_row = row.split(percentage=0.333333333333333333333, align=True)
117
+ sub_row.label(text=name, icon_value=sub_row.icon(tex))
118
+ sub_row.prop(slot, 'color', text="")
119
+ sub_row.prop(slot, 'diffuse_color_factor', icon='IMAGE_RGB_ALPHA', text="Alpha", slider=True)
120
+ row.operator('material.quick_texture_show', text="", icon='RIGHTARROW').texture_name = tex.name
121
+ elif type == 'f':
122
+ row = box.row(align=True)
123
+ sub_row = row.split(percentage=0.333333333333333333333, align=True)
124
+ sub_row.label(text=name, icon_value=sub_row.icon(tex))
125
+ sub_row.prop(slot, 'diffuse_color_factor', icon='ARROW_LEFTRIGHT', text="Value")
126
+ row.operator('material.quick_texture_show', text="", icon='RIGHTARROW').texture_name = tex.name
127
+
128
+ box.operator('texture.sync_tex_color_ramps', icon='LINKED')
129
+
130
+ else:
131
+ row = box.row()
132
+ row.alignment = 'LEFT'
133
+ op = row.operator('wm.context_set_int', icon='RIGHTARROW', text="", emboss=False)
134
+ op.data_path, op.value, op.relative = 'material["CM3D2 Texture Expand"]', 1, False
135
+ row.label(text="Texture Info", icon_value=common.preview_collections['main']['KISS'].icon_id)
136
+
137
+ else:
138
+ self.layout.operator('material.new_cm3d2', text="Create CM3D2 Material", icon_value=common.preview_collections['main']['KISS'].icon_id)
139
+
140
+ class new_cm3d2(bpy.types.Operator):
141
+ bl_idname = 'material.new_cm3d2'
142
+ bl_label = "Create a Material for CM3D2"
143
+ bl_description = "Blender-CM3D2-Create a material that can be exported."
144
+ bl_options = {'REGISTER', 'UNDO'}
145
+
146
+ items = [
147
+ ('CM3D2/Toony_Lighted', "Toony", "", 'SOLID', 0),
148
+ ('CM3D2/Toony_Lighted_Hair', "Toony Lighted Hair", "", 'PARTICLEMODE', 1),
149
+ ('CM3D2/Toony_Lighted_Trans', "Toony Lighted Trans", "", 'WIRE', 2),
150
+ ('CM3D2/Toony_Lighted_Trans_NoZ', "Toony Lighted Trans NoZ", "", 'DRIVER', 3),
151
+ ('CM3D2/Toony_Lighted_Outline', "Toony Lighted Outline", "", 'ANTIALIASED', 4),
152
+ ('CM3D2/Toony_Lighted_Hair_Outline', "Toony Lighted Hair Outline", "", 'PARTICLEMODE', 5),
153
+ ('CM3D2/Toony_Lighted_Outline_Trans', "Toony Lighted Outline Trans", "", 'PROP_OFF', 6),
154
+ ('CM3D2/Lighted_Trans', "Lighted Trans", "", 'VISIBLE_IPO_OFF', 7),
155
+ ('CM3D2/Lighted', "Lighted", "", 'MATSPHERE', 8),
156
+ ('Unlit/Texture', "Unlit/Texture", "", 'PARTICLES', 9),
157
+ ('Unlit/Transparent', "Unlit/Trans", "", 'MOD_PARTICLES', 10),
158
+ ('CM3D2/Mosaic', "Mosiac", "", 'ALIASED', 11),
159
+ ('CM3D2/Man', "Man", "", 'ARMATURE_DATA', 12),
160
+ ('Diffuse', "Diffuse", "", 'BRUSH_CLAY_STRIPS', 13),
161
+ ('Transparent/Diffuse', "Trans Diffuse", "", 'MATCAP_09', 14),
162
+ ('CM3D2_Debug/Debug_CM3D2_Normal2Color', "Debug", "", 'MATCAP_23', 15),
163
+ ]
164
+ type = bpy.props.EnumProperty(items=items, name="Shaders:", default='CM3D2/Toony_Lighted_Outline')
165
+ is_decorate = bpy.props.BoolProperty(name="Decorate Material", default=True)
166
+ is_replace_cm3d2_tex = bpy.props.BoolProperty(name="Find Textures", default=False, description="Will Search for any corresponding textures and will apply them.")
167
+
168
+ @classmethod
169
+ def poll(cls, context):
170
+ return True
171
+
172
+ def invoke(self, context, event):
173
+ self.is_replace_cm3d2_tex = common.preferences().is_replace_cm3d2_tex
174
+ return context.window_manager.invoke_props_dialog(self)
175
+
176
+ def draw(self, context):
177
+ self.layout.separator()
178
+ self.layout.prop(self, 'type', icon='MATERIAL')
179
+ self.layout.prop(self, 'is_decorate', icon='TEXTURE_SHADED')
180
+ self.layout.prop(self, 'is_replace_cm3d2_tex', icon='BORDERMOVE')
181
+
182
+ def execute(self, context):
183
+ ob = context.active_object
184
+ me = ob.data
185
+ ob_names = common.remove_serial_number(ob.name).split('.')
186
+ ob_name = ob_names[0]
187
+
188
+ if context.material:
189
+ mate = context.material
190
+ for index, slot in enumerate(mate.texture_slots):
191
+ mate.texture_slots.clear(index)
192
+ else:
193
+ if not context.material_slot:
194
+ bpy.ops.object.material_slot_add()
195
+ mate = context.blend_data.materials.new(ob_name)
196
+
197
+ context.material_slot.material = mate
198
+ tex_list, col_list, f_list = [], [], []
199
+
200
+ base_path = "Assets\\texture\\texture\\"
201
+ pref = common.preferences()
202
+
203
+ _MainTex = ("_MainTex", ob_name, base_path + ob_name + ".png")
204
+ _ToonRamp = ("_ToonRamp", pref.new_mate_toonramp_name, pref.new_mate_toonramp_path)
205
+ _ShadowTex = ("_ShadowTex", ob_name + "_shadow", base_path + ob_name + "_shadow.png")
206
+ _ShadowRateToon = ("_ShadowRateToon", pref.new_mate_shadowratetoon_name, pref.new_mate_shadowratetoon_path)
207
+ _HiTex = ("_HiTex", ob_name + "_s", base_path + ob_name + "_s.png")
208
+
209
+ _Color = ("_Color", pref.new_mate_color)
210
+ _ShadowColor = ("_ShadowColor", pref.new_mate_shadowcolor)
211
+ _RimColor = ("_RimColor", pref.new_mate_rimcolor)
212
+ _OutlineColor = ("_OutlineColor", pref.new_mate_outlinecolor)
213
+
214
+ _Shininess = ("_Shininess", pref.new_mate_shininess)
215
+ _OutlineWidth = ("_OutlineWidth", pref.new_mate_outlinewidth)
216
+ _RimPower = ("_RimPower", pref.new_mate_rimpower)
217
+ _RimShift = ("_RimShift", pref.new_mate_rimshift)
218
+ _HiRate = ("_HiRate", pref.new_mate_hirate)
219
+ _HiPow = ("_HiPow", pref.new_mate_hipow)
220
+
221
+ if False:
222
+ pass
223
+ elif self.type == 'CM3D2/Toony_Lighted_Outline':
224
+ mate['shader1'] = 'CM3D2/Toony_Lighted_Outline'
225
+ mate['shader2'] = 'CM3D2__Toony_Lighted_Outline'
226
+ tex_list.append(_MainTex)
227
+ tex_list.append(_ToonRamp)
228
+ tex_list.append(_ShadowTex)
229
+ tex_list.append(_ShadowRateToon)
230
+ col_list.append(_Color)
231
+ col_list.append(_ShadowColor)
232
+ col_list.append(_RimColor)
233
+ col_list.append(_OutlineColor)
234
+ f_list.append(_Shininess)
235
+ f_list.append(_OutlineWidth)
236
+ f_list.append(_RimPower)
237
+ f_list.append(_RimShift)
238
+ elif self.type == 'CM3D2/Toony_Lighted_Trans':
239
+ mate['shader1'] = 'CM3D2/Toony_Lighted_Trans'
240
+ mate['shader2'] = 'CM3D2__Toony_Lighted_Trans'
241
+ tex_list.append(_MainTex)
242
+ tex_list.append(_ToonRamp)
243
+ tex_list.append(_ShadowTex)
244
+ tex_list.append(_ShadowRateToon)
245
+ col_list.append(_Color)
246
+ col_list.append(_ShadowColor)
247
+ col_list.append(_RimColor)
248
+ f_list.append(_Shininess)
249
+ f_list.append(_RimPower)
250
+ f_list.append(_RimShift)
251
+ elif self.type == 'CM3D2/Toony_Lighted_Hair_Outline':
252
+ mate['shader1'] = 'CM3D2/Toony_Lighted_Hair_Outline'
253
+ mate['shader2'] = 'CM3D2__Toony_Lighted_Hair_Outline'
254
+ tex_list.append(_MainTex)
255
+ tex_list.append(_ToonRamp)
256
+ tex_list.append(_ShadowTex)
257
+ tex_list.append(_ShadowRateToon)
258
+ tex_list.append(_HiTex)
259
+ col_list.append(_Color)
260
+ col_list.append(_ShadowColor)
261
+ col_list.append(_RimColor)
262
+ col_list.append(_OutlineColor)
263
+ f_list.append(_Shininess)
264
+ f_list.append(_OutlineWidth)
265
+ f_list.append(_RimPower)
266
+ f_list.append(_RimShift)
267
+ f_list.append(_HiRate)
268
+ f_list.append(_HiPow)
269
+ elif self.type == 'CM3D2/Mosaic':
270
+ mate['shader1'] = 'CM3D2/Mosaic'
271
+ mate['shader2'] = 'CM3D2__Mosaic'
272
+ tex_list.append(("_RenderTex", ""))
273
+ f_list.append(("_FloatValue1", 30))
274
+ elif self.type == 'Unlit/Texture':
275
+ mate['shader1'] = 'Unlit/Texture'
276
+ mate['shader2'] = 'Unlit__Texture'
277
+ tex_list.append(_MainTex)
278
+ col_list.append(_Color)
279
+ elif self.type == 'Unlit/Transparent':
280
+ mate['shader1'] = 'Unlit/Transparent'
281
+ mate['shader2'] = 'Unlit__Transparent'
282
+ tex_list.append(_MainTex)
283
+ col_list.append(_Color)
284
+ col_list.append(_ShadowColor)
285
+ col_list.append(_RimColor)
286
+ f_list.append(_Shininess)
287
+ f_list.append(_RimPower)
288
+ f_list.append(_RimShift)
289
+ elif self.type == 'CM3D2/Man':
290
+ mate['shader1'] = 'CM3D2/Man'
291
+ mate['shader2'] = 'CM3D2__Man'
292
+ col_list.append(_Color)
293
+ f_list.append(("_FloatValue2", 0.5))
294
+ f_list.append(("_FloatValue3", 1))
295
+ elif self.type == 'Diffuse':
296
+ mate['shader1'] = 'Diffuse'
297
+ mate['shader2'] = 'Diffuse'
298
+ tex_list.append(_MainTex)
299
+ col_list.append(_Color)
300
+ elif self.type == 'CM3D2/Toony_Lighted_Trans_NoZ':
301
+ mate['shader1'] = 'CM3D2/Toony_Lighted_Trans_NoZ'
302
+ mate['shader2'] = 'CM3D2__Toony_Lighted_Trans_NoZ'
303
+ tex_list.append(_MainTex)
304
+ tex_list.append(_ToonRamp)
305
+ tex_list.append(_ShadowTex)
306
+ tex_list.append(_ShadowRateToon)
307
+ col_list.append(_Color)
308
+ col_list.append(_ShadowColor)
309
+ col_list.append(_RimColor)
310
+ col_list.append(_OutlineColor)
311
+ f_list.append(_Shininess)
312
+ f_list.append(_OutlineWidth)
313
+ f_list.append(_RimPower)
314
+ f_list.append(_RimShift)
315
+ elif self.type == 'CM3D2/Toony_Lighted_Outline_Trans':
316
+ mate['shader1'] = 'CM3D2/Toony_Lighted_Outline_Trans'
317
+ mate['shader2'] = 'CM3D2__Toony_Lighted_Outline_Trans'
318
+ tex_list.append(_MainTex)
319
+ tex_list.append(_ToonRamp)
320
+ tex_list.append(_ShadowTex)
321
+ tex_list.append(_ShadowRateToon)
322
+ col_list.append(_Color)
323
+ col_list.append(_ShadowColor)
324
+ col_list.append(_RimColor)
325
+ col_list.append(_OutlineColor)
326
+ f_list.append(_Shininess)
327
+ f_list.append(_OutlineWidth)
328
+ f_list.append(_RimPower)
329
+ f_list.append(_RimShift)
330
+ elif self.type == 'CM3D2/Lighted_Trans':
331
+ mate['shader1'] = 'CM3D2/Lighted_Trans'
332
+ mate['shader2'] = 'CM3D2__Lighted_Trans'
333
+ tex_list.append(_MainTex)
334
+ col_list.append(_Color)
335
+ col_list.append(_ShadowColor)
336
+ f_list.append(_Shininess)
337
+ elif self.type == 'CM3D2/Lighted':
338
+ mate['shader1'] = 'CM3D2/Lighted'
339
+ mate['shader2'] = 'CM3D2__Lighted'
340
+ tex_list.append(_MainTex)
341
+ col_list.append(_Color)
342
+ col_list.append(_ShadowColor)
343
+ f_list.append(_Shininess)
344
+ elif self.type == 'CM3D2/Toony_Lighted':
345
+ mate['shader1'] = 'CM3D2/Toony_Lighted'
346
+ mate['shader2'] = 'CM3D2__Toony_Lighted'
347
+ tex_list.append(_MainTex)
348
+ tex_list.append(_ToonRamp)
349
+ tex_list.append(_ShadowTex)
350
+ tex_list.append(_ShadowRateToon)
351
+ col_list.append(_Color)
352
+ col_list.append(_ShadowColor)
353
+ col_list.append(_RimColor)
354
+ f_list.append(_Shininess)
355
+ f_list.append(_RimPower)
356
+ f_list.append(_RimShift)
357
+ elif self.type == 'CM3D2/Toony_Lighted_Hair':
358
+ mate['shader1'] = 'CM3D2/Toony_Lighted_Hair_Outline'
359
+ mate['shader2'] = 'CM3D2__Toony_Lighted_Hair_Outline'
360
+ tex_list.append(_MainTex)
361
+ tex_list.append(_ToonRamp)
362
+ tex_list.append(_ShadowTex)
363
+ tex_list.append(_ShadowRateToon)
364
+ tex_list.append(_HiTex)
365
+ col_list.append(_Color)
366
+ col_list.append(_ShadowColor)
367
+ col_list.append(_RimColor)
368
+ f_list.append(_Shininess)
369
+ f_list.append(_RimPower)
370
+ f_list.append(_RimShift)
371
+ f_list.append(_HiRate)
372
+ f_list.append(_HiPow)
373
+ elif self.type == 'Transparent/Diffuse':
374
+ mate['shader1'] = 'Transparent/Diffuse'
375
+ mate['shader2'] = 'Transparent__Diffuse'
376
+ tex_list.append(_MainTex)
377
+ col_list.append(_Color)
378
+ col_list.append(_ShadowColor)
379
+ col_list.append(_RimColor)
380
+ col_list.append(_OutlineColor)
381
+ f_list.append(_Shininess)
382
+ f_list.append(_OutlineWidth)
383
+ f_list.append(_RimPower)
384
+ f_list.append(_RimShift)
385
+ elif self.type == 'CM3D2_Debug/Debug_CM3D2_Normal2Color':
386
+ mate['shader1'] = 'CM3D2_Debug/Debug_CM3D2_Normal2Color'
387
+ mate['shader2'] = 'CM3D2_Debug__Debug_CM3D2_Normal2Color'
388
+ col_list.append(_Color)
389
+ col_list.append(_RimColor)
390
+ col_list.append(_OutlineColor)
391
+ col_list.append(("_SpecColor", (1, 1, 1, 1)))
392
+ f_list.append(_Shininess)
393
+ f_list.append(_OutlineWidth)
394
+ f_list.append(_RimPower)
395
+ f_list.append(_RimShift)
396
+
397
+ tex_storage_files = common.get_tex_storage_files()
398
+ slot_count = 0
399
+ for data in tex_list:
400
+ slot = mate.texture_slots.create(slot_count)
401
+ tex = context.blend_data.textures.new(data[0], 'IMAGE')
402
+ slot.texture = tex
403
+ if data[1] == "":
404
+ slot_count += 1
405
+ continue
406
+ slot.color = pref.new_mate_tex_color[:3]
407
+ slot.diffuse_color_factor = pref.new_mate_tex_color[3]
408
+ img = context.blend_data.images.new(data[1], 128, 128)
409
+ img.filepath = data[2]
410
+ img['cm3d2_path'] = data[2]
411
+ img.source = 'FILE'
412
+ tex.image = img
413
+ slot_count += 1
414
+
415
+ # tex探し
416
+ if self.is_replace_cm3d2_tex:
417
+ if common.replace_cm3d2_tex(img, tex_storage_files) and data[0]=='_MainTex':
418
+ for face in me.polygons:
419
+ if face.material_index == ob.active_material_index:
420
+ me.uv_textures.active.data[face.index].image = img
421
+
422
+ for data in col_list:
423
+ slot = mate.texture_slots.create(slot_count)
424
+ mate.use_textures[slot_count] = False
425
+ slot.color = data[1][:3]
426
+ slot.diffuse_color_factor = data[1][3]
427
+ slot.use_rgb_to_intensity = True
428
+ tex = context.blend_data.textures.new(data[0], 'BLEND')
429
+ slot.texture = tex
430
+ slot_count += 1
431
+
432
+ for data in f_list:
433
+ slot = mate.texture_slots.create(slot_count)
434
+ mate.use_textures[slot_count] = False
435
+ slot.diffuse_color_factor = data[1]
436
+ tex = context.blend_data.textures.new(data[0], 'BLEND')
437
+ slot.texture = tex
438
+ slot_count += 1
439
+
440
+ common.decorate_material(mate, self.is_decorate, me, ob.active_material_index)
441
+ return {'FINISHED'}
442
+
443
+ class paste_material(bpy.types.Operator):
444
+ bl_idname = 'material.paste_material'
445
+ bl_label = "Paste Material"
446
+ bl_description = "Create a new material from the material data in the clipboard."
447
+ bl_options = {'REGISTER', 'UNDO'}
448
+
449
+ is_decorate = bpy.props.BoolProperty(name="Decorate Material", default=True)
450
+ is_replace_cm3d2_tex = bpy.props.BoolProperty(name="Find texture", default=False, description="Will Search for any corresponding textures and will apply them")
451
+
452
+ @classmethod
453
+ def poll(cls, context):
454
+ data = context.window_manager.clipboard
455
+ lines = data.split('\n')
456
+ if len(lines) < 10:
457
+ return False
458
+ match_strs = ['\ntex\n', '\ncol\n', '\nf\n', '\n\t_MainTex\n', '\n\t_Color\n', '\n\t_Shininess\n']
459
+ for s in match_strs:
460
+ if s in data:
461
+ return True
462
+ return False
463
+
464
+ def invoke(self, context, event):
465
+ self.is_replace_cm3d2_tex = common.preferences().is_replace_cm3d2_tex
466
+ return context.window_manager.invoke_props_dialog(self)
467
+
468
+ def draw(self, context):
469
+ self.layout.prop(self, 'is_decorate')
470
+ self.layout.prop(self, 'is_replace_cm3d2_tex', icon='BORDERMOVE')
471
+
472
+ def execute(self, context):
473
+ data = context.window_manager.clipboard
474
+ lines = data.split('\n')
475
+
476
+ ob = context.active_object
477
+ me = ob.data
478
+
479
+ if not context.material_slot:
480
+ bpy.ops.object.material_slot_add()
481
+ mate = context.blend_data.materials.new(lines[2])
482
+ context.material_slot.material = mate
483
+
484
+ mate['shader1'] = lines[3]
485
+ mate['shader2'] = lines[4]
486
+
487
+ slot_index = 0
488
+ line_seek = 5
489
+ for i in range(99999):
490
+ if len(lines) <= line_seek:
491
+ break
492
+ type = common.line_trim(lines[line_seek])
493
+ if not type:
494
+ line_seek += 1
495
+ continue
496
+ if type == 'tex':
497
+ slot = mate.texture_slots.create(slot_index)
498
+ tex = context.blend_data.textures.new(common.line_trim(lines[line_seek+1]), 'IMAGE')
499
+ slot.texture = tex
500
+ sub_type = common.line_trim(lines[line_seek+2])
501
+ line_seek += 3
502
+ if sub_type == 'tex2d':
503
+ img = context.blend_data.images.new(common.line_trim(lines[line_seek]), 128, 128)
504
+ img['cm3d2_path'] = common.line_trim(lines[line_seek+1])
505
+ img.filepath = img['cm3d2_path']
506
+ img.source = 'FILE'
507
+ tex.image = img
508
+ fs = common.line_trim(lines[line_seek+2]).split(' ')
509
+ for fi in range(len(fs)):
510
+ fs[fi] = float(fs[fi])
511
+ slot.color = fs[:3]
512
+ slot.diffuse_color_factor = fs[3]
513
+ line_seek += 3
514
+
515
+ # tex探し
516
+ if self.is_replace_cm3d2_tex:
517
+ if common.replace_cm3d2_tex(img) and data[0]=='_MainTex':
518
+ for face in me.polygons:
519
+ if face.material_index == ob.active_material_index:
520
+ me.uv_textures.active.data[face.index].image = img
521
+
522
+ elif type == 'col':
523
+ slot = mate.texture_slots.create(slot_index)
524
+ tex_name = common.line_trim(lines[line_seek+1])
525
+ tex = context.blend_data.textures.new(tex_name, 'BLEND')
526
+ mate.use_textures[slot_index] = False
527
+ slot.use_rgb_to_intensity = True
528
+ fs = common.line_trim(lines[line_seek+2]).split(' ')
529
+ for fi in range(len(fs)):
530
+ fs[fi] = float(fs[fi])
531
+ slot.color = fs[:3]
532
+ slot.diffuse_color_factor = fs[3]
533
+ slot.texture = tex
534
+ line_seek += 3
535
+
536
+ elif type == 'f':
537
+ slot = mate.texture_slots.create(slot_index)
538
+ tex_name = common.line_trim(lines[line_seek+1])
539
+ tex = context.blend_data.textures.new(tex_name, 'BLEND')
540
+ mate.use_textures[slot_index] = False
541
+ slot.diffuse_color_factor = float(common.line_trim(lines[line_seek+2]))
542
+ slot.texture = tex
543
+ line_seek += 3
544
+
545
+ else:
546
+ self.report(type={'ERROR'}, message="Unknown value found, mission aborted.")
547
+ return {'CANCELLED'}
548
+ slot_index += 1
549
+
550
+ common.decorate_material(mate, self.is_decorate, me, ob.active_material_index)
551
+ self.report(type={'INFO'}, message="Material Pasted.")
552
+ return {'FINISHED'}
553
+
554
+ class paste_material2(bpy.types.Operator):
555
+ bl_idname = 'material.paste_material2'
556
+ bl_label = "Paste Material"
557
+ bl_description = "Material data will be pasted from the clipboard."
558
+ bl_options = {'REGISTER', 'UNDO'}
559
+
560
+ @classmethod
561
+ def poll(cls, context):
562
+ data = context.window_manager.clipboard
563
+ lines = data.split('\n')
564
+ if len(lines) < 10:
565
+ return False
566
+ match_strs = ['\ntex\n', '\ncol\n', '\nf\n', '\n\t_MainTex\n', '\n\t_Color\n', '\n\t_Shininess\n']
567
+ for s in match_strs:
568
+ if s in data:
569
+ return True
570
+ return False
571
+
572
+ def execute(self, context):
573
+ data = context.window_manager.clipboard
574
+ lines = data.split('\n')
575
+
576
+ ob = context.active_object
577
+ me = ob.data
578
+
579
+ mate = context.material
580
+ # シリアル番号が異なる場合は変更しない
581
+ if common.remove_serial_number(lines[2]) != common.remove_serial_number(mate.name):
582
+ mate.name = lines[2]
583
+ mate['shader1'] = lines[3]
584
+ mate['shader2'] = lines[4]
585
+
586
+ slot_index = 0
587
+ line_seek = 5
588
+ olds_slots = {}
589
+
590
+ def search_or_create_slot(slot_index, prop_name, tex_type):
591
+ tex = None
592
+ slot_item = mate.texture_slots[slot_index]
593
+ name = slot_item.name if slot_item else ''
594
+
595
+ slot_item_name = common.remove_serial_number(name)
596
+ if prop_name == slot_item_name:
597
+ slot = slot_item
598
+ tex = slot_item.texture
599
+ else:
600
+ if slot_item: olds_slots[slot_item_name] = slot_item
601
+ slot = mate.texture_slots.create(slot_index)
602
+
603
+ if prop_name in olds_slots:
604
+ tex = olds_slots.pop(prop_name).texture
605
+ else:
606
+ for item_index in range(slot_index+1, len(mate.texture_slots)):
607
+ slot_item = mate.texture_slots[item_index]
608
+ if slot_item is None: break
609
+ if prop_name == common.remove_serial_number(slot_item.name):
610
+ tex = slot_item.texture
611
+ break
612
+ if tex is None:
613
+ tex = context.blend_data.textures.new(prop_name, tex_type)
614
+ slot.texture = tex
615
+ return slot
616
+
617
+ for i in range(99999):
618
+ if len(lines) <= line_seek:
619
+ break
620
+ type = common.line_trim(lines[line_seek])
621
+ if not type:
622
+ line_seek += 1
623
+ continue
624
+ if type == 'tex':
625
+ prop_name = common.line_trim(lines[line_seek+1])
626
+ sub_type = common.line_trim(lines[line_seek+2])
627
+
628
+ slot = search_or_create_slot(slot_index, prop_name, 'IMAGE')
629
+ slot.use_rgb_to_intensity = False
630
+ mate.use_textures[slot_index] = True
631
+
632
+ line_seek += 3
633
+ if sub_type == 'tex2d':
634
+ tex = slot.texture
635
+ tex_name = common.line_trim(lines[line_seek])
636
+ tex_path = common.line_trim(lines[line_seek+1])
637
+ if tex.image is None:
638
+ img = context.blend_data.images.new(tex_name, 128, 128)
639
+ img.source = 'FILE'
640
+ tex.image = img
641
+
642
+ # シリアル番号を残す
643
+ if tex_name != common.remove_serial_number(tex.image.name):
644
+ tex.image.name = tex_name
645
+ tex.image['cm3d2_path'] = tex_path
646
+ tex.image.filepath = tex.image['cm3d2_path']
647
+
648
+ fs = common.line_trim(lines[line_seek+2]).split(' ')
649
+ for fi in range(len(fs)):
650
+ fs[fi] = float(fs[fi])
651
+ slot.color = fs[:3]
652
+ slot.diffuse_color_factor = fs[3]
653
+ line_seek += 3
654
+
655
+ elif type == 'col':
656
+ prop_name = common.line_trim(lines[line_seek+1])
657
+
658
+ slot = search_or_create_slot(slot_index, prop_name, 'BLEND')
659
+
660
+ slot.use_rgb_to_intensity = True
661
+ mate.use_textures[slot_index] = False
662
+
663
+ fs = common.line_trim(lines[line_seek+2]).split(' ')
664
+ for fi in range(len(fs)):
665
+ fs[fi] = float(fs[fi])
666
+ slot.color = fs[:3]
667
+ slot.diffuse_color_factor = fs[3]
668
+ line_seek += 3
669
+
670
+ elif type == 'f':
671
+ prop_name = common.line_trim(lines[line_seek+1])
672
+
673
+ slot = search_or_create_slot(slot_index, prop_name, 'BLEND')
674
+
675
+ slot.use_rgb_to_intensity = False
676
+ mate.use_textures[slot_index] = False
677
+ slot.diffuse_color_factor = float(common.line_trim(lines[line_seek+2]))
678
+ line_seek += 3
679
+
680
+ else:
681
+ self.report(type={'ERROR'}, message="Unknown value found, mission aborted.")
682
+ return {'CANCELLED'}
683
+ slot_index += 1
684
+
685
+ # 存在しないスロットをクリア
686
+ for item_index in range(slot_index, len(mate.texture_slots)):
687
+ mate.texture_slots.clear(item_index)
688
+
689
+ # プレビューへの反映
690
+ for slot in mate.texture_slots:
691
+ if slot: common.set_texture_color(slot)
692
+
693
+ self.report(type={'INFO'}, message="Material was pasted.")
694
+ return {'FINISHED'}
695
+
696
+ class copy_material(bpy.types.Operator):
697
+ bl_idname = 'material.copy_material'
698
+ bl_label = "Copy Material to Clipboard"
699
+ bl_description = "Displayed material will be copied to the clipboard in text format."
700
+ bl_options = {'REGISTER', 'UNDO'}
701
+
702
+ @classmethod
703
+ def poll(cls, context):
704
+ if 'material' in dir(context):
705
+ mate = context.material
706
+ if mate:
707
+ return 'shader1' in mate and 'shader2' in mate
708
+ return False
709
+
710
+ def execute(self, context):
711
+ import re, os.path
712
+
713
+ mate = context.material
714
+
715
+ output_text = "1000" + "\n"
716
+ output_text += mate.name.lower() + "\n"
717
+ output_text += mate.name + "\n"
718
+ output_text += mate['shader1'] + "\n"
719
+ output_text += mate['shader2'] + "\n"
720
+ output_text += "\n"
721
+
722
+ for tex_slot in mate.texture_slots:
723
+ if not tex_slot:
724
+ continue
725
+ tex = tex_slot.texture
726
+ if tex_slot.use:
727
+ type = 'tex'
728
+ else:
729
+ if tex_slot.use_rgb_to_intensity:
730
+ type = 'col'
731
+ else:
732
+ type = 'f'
733
+ output_text += type + "\n"
734
+ output_text += "\t" + common.remove_serial_number(tex.name) + "\n"
735
+ if type == 'tex':
736
+ try:
737
+ img = tex.image
738
+ except:
739
+ self.report(type={'ERROR'}, message="Failed to acquire texture type. Mission aborted.")
740
+ return {'CANCELLED'}
741
+ if img:
742
+ output_text += '\ttex2d' + "\n"
743
+ output_text += "\t" + common.remove_serial_number(img.name) + "\n"
744
+ if 'cm3d2_path' in img:
745
+ path = img['cm3d2_path']
746
+ else:
747
+ path = bpy.path.abspath( bpy.path.abspath(img.filepath) )
748
+ path = path.replace('\\', '/')
749
+ path = re.sub(r'^[\/\.]*', "", path)
750
+ if not re.search(r'^assets/texture/', path, re.I):
751
+ path = "Assets/texture/texture/" + os.path.basename(path)
752
+ output_text += "\t" + path + "\n"
753
+ col = tex_slot.color
754
+ output_text += "\t" + " ".join([str(col[0]), str(col[1]), str(col[2]), str(tex_slot.diffuse_color_factor)]) + "\n"
755
+ else:
756
+ output_text += "\tnull" + "\n"
757
+ elif type == 'col':
758
+ col = tex_slot.color
759
+ output_text += "\t" + " ".join([str(col[0]), str(col[1]), str(col[2]), str(tex_slot.diffuse_color_factor)]) + "\n"
760
+ elif type == 'f':
761
+ output_text += "\t" + str(tex_slot.diffuse_color_factor) + "\n"
762
+
763
+ context.window_manager.clipboard = output_text
764
+ self.report(type={'INFO'}, message="Material copied to clipboard.")
765
+ return {'FINISHED'}
766
+
767
+ class decorate_material(bpy.types.Operator):
768
+ bl_idname = 'material.decorate_material'
769
+ bl_label = "Decorate Material"
770
+ bl_description = "Materials will be given the correct properties according to the settings."
771
+ bl_options = {'REGISTER', 'UNDO'}
772
+
773
+ @classmethod
774
+ def poll(cls, context):
775
+ ob = context.active_object
776
+ if not ob: return False
777
+ if ob.type != 'MESH': return False
778
+ for slot in ob.material_slots:
779
+ mate = slot.material
780
+ if mate:
781
+ if 'shader1' in mate and 'shader2' in mate:
782
+ return True
783
+ return False
784
+
785
+ def execute(self, context):
786
+ ob = context.active_object
787
+ me = ob.data
788
+
789
+ for slot_index, slot in enumerate(ob.material_slots):
790
+ mate = slot.material
791
+ if mate:
792
+ if 'shader1' in mate and 'shader2' in mate:
793
+ common.decorate_material(mate, True, me, slot_index)
794
+
795
+ return {'FINISHED'}
796
+
797
+ class quick_texture_show(bpy.types.Operator):
798
+ bl_idname = 'material.quick_texture_show'
799
+ bl_label = "See Texture"
800
+ bl_description = "See the texture."
801
+ bl_options = {'REGISTER'}
802
+
803
+ texture_name = bpy.props.StringProperty(name="Texture Name")
804
+
805
+ @classmethod
806
+ def poll(cls, context):
807
+ mate = context.material
808
+ if mate:
809
+ if 'shader1' in mate and 'shader2' in mate:
810
+ return True
811
+ return False
812
+
813
+ def execute(self, context):
814
+ mate = context.material
815
+ for index, slot in enumerate(mate.texture_slots):
816
+ if not slot: continue
817
+ if not slot.texture: continue
818
+ if slot.texture.name == self.texture_name:
819
+ mate.active_texture_index = index
820
+ context.space_data.context = 'TEXTURE'
821
+ break
822
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_MESH_MT_shape_key_specials.py ADDED
@@ -0,0 +1,575 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「メッシュデータ」タブ → 「シェイプキー」パネル → ▼ボタン
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ icon_id = common.preview_collections['main']['KISS'].icon_id
8
+ self.layout.separator()
9
+ self.layout.operator('object.quick_shape_key_transfer', icon_value=icon_id)
10
+ self.layout.operator('object.precision_shape_key_transfer', icon_value=icon_id)
11
+ self.layout.separator()
12
+ self.layout.operator('object.multiply_shape_key', icon_value=icon_id)
13
+ self.layout.separator()
14
+ self.layout.operator('object.blur_shape_key', icon_value=icon_id)
15
+ self.layout.separator()
16
+ self.layout.operator('object.change_base_shape_key', icon_value=icon_id)
17
+
18
+ class quick_shape_key_transfer(bpy.types.Operator):
19
+ bl_idname = 'object.quick_shape_key_transfer'
20
+ bl_label = "Quick shape key transfer"
21
+ bl_description = "The shape keys from a previously selected object are transferred to the current object."
22
+ bl_options = {'REGISTER', 'UNDO'}
23
+
24
+ is_first_remove_all = bpy.props.BoolProperty(name="Remove All Previous Keys", default=True)
25
+ subdivide_number = bpy.props.IntProperty(name="Subdivide Amount", default=1, min=0, max=10, soft_min=0, soft_max=10)
26
+ is_remove_empty = bpy.props.BoolProperty(name="Remove Empty Keys", default=True)
27
+
28
+ @classmethod
29
+ def poll(cls, context):
30
+ active_ob = context.active_object
31
+ obs = context.selected_objects
32
+ if len(obs) != 2: return False
33
+ for ob in obs:
34
+ if ob.type != 'MESH':
35
+ return False
36
+ if ob.name != active_ob.name:
37
+ if ob.data.shape_keys:
38
+ return True
39
+ return False
40
+
41
+ def invoke(self, context, event):
42
+ return context.window_manager.invoke_props_dialog(self)
43
+
44
+ def draw(self, context):
45
+ self.layout.prop(self, 'is_first_remove_all', icon='ERROR')
46
+ self.layout.prop(self, 'subdivide_number', icon='LATTICE_DATA')
47
+ self.layout.prop(self, 'is_remove_empty', icon='X')
48
+
49
+ def execute(self, context):
50
+ import mathutils, time
51
+ start_time = time.time()
52
+
53
+ target_ob = context.active_object
54
+ target_me = target_ob.data
55
+
56
+ pre_mode = target_ob.mode
57
+ bpy.ops.object.mode_set(mode='OBJECT')
58
+
59
+ for ob in context.selected_objects:
60
+ if ob.name != target_ob.name:
61
+ source_original_ob = ob
62
+ break
63
+ source_ob = source_original_ob.copy()
64
+ source_me = source_original_ob.data.copy()
65
+ source_ob.data = source_me
66
+ context.scene.objects.link(source_ob)
67
+ context.scene.objects.active = source_ob
68
+ bpy.ops.object.mode_set(mode='EDIT')
69
+ bpy.ops.mesh.reveal()
70
+ bpy.ops.mesh.select_all(action='SELECT')
71
+ bpy.ops.mesh.subdivide(number_cuts=self.subdivide_number, smoothness=0.0, quadtri=False, quadcorner='STRAIGHT_CUT', fractal=0.0, fractal_along_normal=0.0, seed=0)
72
+ source_ob.active_shape_key_index = 0
73
+ bpy.ops.object.mode_set(mode='OBJECT')
74
+
75
+ if self.is_first_remove_all:
76
+ try:
77
+ target_ob.active_shape_key_index = 1
78
+ bpy.ops.object.shape_key_remove(all=True)
79
+ except:
80
+ pass
81
+
82
+ kd = mathutils.kdtree.KDTree(len(source_me.vertices))
83
+ for vert in source_me.vertices:
84
+ co = source_ob.matrix_world * vert.co
85
+ kd.insert(co, vert.index)
86
+ kd.balance()
87
+
88
+ near_vert_indexs = [kd.find(target_ob.matrix_world * v.co)[1] for v in target_me.vertices]
89
+
90
+ is_shapeds = {}
91
+ relative_keys = []
92
+ context.window_manager.progress_begin(0, len(source_me.shape_keys.key_blocks))
93
+ context.window_manager.progress_update(0)
94
+ for source_shape_key_index, source_shape_key in enumerate(source_me.shape_keys.key_blocks):
95
+
96
+ if target_me.shape_keys:
97
+ if source_shape_key.name in target_me.shape_keys.key_blocks:
98
+ target_shape_key = target_me.shape_keys.key_blocks[source_shape_key.name]
99
+ else:
100
+ target_shape_key = target_ob.shape_key_add(name=source_shape_key.name, from_mix=False)
101
+ else:
102
+ target_shape_key = target_ob.shape_key_add(name=source_shape_key.name, from_mix=False)
103
+
104
+ relative_key_name = source_shape_key.relative_key.name
105
+ if relative_key_name not in relative_keys:
106
+ relative_keys.append(relative_key_name)
107
+ is_shapeds[source_shape_key.name] = False
108
+
109
+ try:
110
+ target_shape_key.relative_key = target_me.shape_keys.key_blocks[relative_key_name]
111
+ except:
112
+ pass
113
+
114
+ mat1, mat2 = source_ob.matrix_world, target_ob.matrix_world
115
+ source_shape_keys = [(mat1 * source_shape_key.data[v.index].co * mat2) - (mat1 * source_me.vertices[v.index].co * mat2) for v in source_me.vertices]
116
+
117
+ for target_vert in target_me.vertices:
118
+
119
+ near_vert_index = near_vert_indexs[target_vert.index]
120
+ near_shape_co = source_shape_keys[near_vert_index]
121
+
122
+ target_shape_key.data[target_vert.index].co = target_me.vertices[target_vert.index].co + near_shape_co
123
+ if 0.01 < near_shape_co.length:
124
+ is_shapeds[source_shape_key.name] = True
125
+
126
+ context.window_manager.progress_update(source_shape_key_index)
127
+ context.window_manager.progress_end()
128
+
129
+ if self.is_remove_empty:
130
+ for source_shape_key_name, is_shaped in is_shapeds.items():
131
+ if source_shape_key_name not in relative_keys and not is_shaped:
132
+ target_shape_key = target_me.shape_keys.key_blocks[source_shape_key_name]
133
+ target_ob.shape_key_remove(target_shape_key)
134
+
135
+ target_ob.active_shape_key_index = 0
136
+
137
+ common.remove_data([source_ob, source_me])
138
+ context.scene.objects.active = target_ob
139
+ bpy.ops.object.mode_set(mode=pre_mode)
140
+
141
+ diff_time = time.time() - start_time
142
+ self.report(type={'INFO'}, message=str(round(diff_time, 1)) + " Seconds")
143
+ return {'FINISHED'}
144
+
145
+ class precision_shape_key_transfer(bpy.types.Operator):
146
+ bl_idname = 'object.precision_shape_key_transfer'
147
+ bl_label = "Precision Shape key Transfer"
148
+ bl_description = "High precision transfer of shape keys from a previously selected object to the active object."
149
+ bl_options = {'REGISTER', 'UNDO'}
150
+
151
+ is_first_remove_all = bpy.props.BoolProperty(name="Remove All Previous Keys", default=True)
152
+ subdivide_number = bpy.props.IntProperty(name="Subdivide Amount", default=1, min=0, max=10, soft_min=0, soft_max=10)
153
+ extend_range = bpy.props.FloatProperty(name="Range", default=1.5, min=1.1, max=5.0, soft_min=1.1, soft_max=5.0, step=10, precision=2)
154
+ is_remove_empty = bpy.props.BoolProperty(name="Remove Empty Keys", default=True)
155
+
156
+ @classmethod
157
+ def poll(cls, context):
158
+ active_ob = context.active_object
159
+ obs = context.selected_objects
160
+ if len(obs) != 2: return False
161
+ for ob in obs:
162
+ if ob.type != 'MESH':
163
+ return False
164
+ if ob.name != active_ob.name:
165
+ if ob.data.shape_keys:
166
+ return True
167
+ return False
168
+
169
+ def invoke(self, context, event):
170
+ return context.window_manager.invoke_props_dialog(self)
171
+
172
+ def draw(self, context):
173
+ self.layout.prop(self, 'is_first_remove_all', icon='ERROR')
174
+ self.layout.prop(self, 'subdivide_number', icon='LATTICE_DATA')
175
+ self.layout.prop(self, 'extend_range', icon='META_EMPTY')
176
+ self.layout.prop(self, 'is_remove_empty', icon='X')
177
+
178
+ def execute(self, context):
179
+ import mathutils, time
180
+ start_time = time.time()
181
+
182
+ target_ob = context.active_object
183
+ target_me = target_ob.data
184
+
185
+ pre_mode = target_ob.mode
186
+ bpy.ops.object.mode_set(mode='OBJECT')
187
+
188
+ for ob in context.selected_objects:
189
+ if ob.name != target_ob.name:
190
+ source_original_ob = ob
191
+ break
192
+ source_ob = source_original_ob.copy()
193
+ source_me = source_original_ob.data.copy()
194
+ source_ob.data = source_me
195
+ context.scene.objects.link(source_ob)
196
+ context.scene.objects.active = source_ob
197
+ bpy.ops.object.mode_set(mode='EDIT')
198
+ bpy.ops.mesh.reveal()
199
+ bpy.ops.mesh.select_all(action='SELECT')
200
+ bpy.ops.mesh.subdivide(number_cuts=self.subdivide_number, smoothness=0.0, quadtri=False, quadcorner='STRAIGHT_CUT', fractal=0.0, fractal_along_normal=0.0, seed=0)
201
+ source_ob.active_shape_key_index = 0
202
+ bpy.ops.object.mode_set(mode='OBJECT')
203
+
204
+ if self.is_first_remove_all:
205
+ try:
206
+ target_ob.active_shape_key_index = 1
207
+ bpy.ops.object.shape_key_remove(all=True)
208
+ except:
209
+ pass
210
+
211
+ kd = mathutils.kdtree.KDTree(len(source_me.vertices))
212
+ for vert in source_me.vertices:
213
+ co = source_ob.matrix_world * vert.co
214
+ kd.insert(co, vert.index)
215
+ kd.balance()
216
+
217
+ context.window_manager.progress_begin(0, len(target_me.vertices))
218
+ progress_reduce = len(target_me.vertices) // 200 + 1
219
+ near_vert_data = []
220
+ near_vert_multi_total = []
221
+ near_vert_multi_total_append = near_vert_multi_total.append
222
+ for vert in target_me.vertices:
223
+ near_vert_data.append([])
224
+ near_vert_data_append = near_vert_data[-1].append
225
+
226
+ target_co = target_ob.matrix_world * vert.co
227
+ mini_co, mini_index, mini_dist = kd.find(target_co)
228
+ radius = mini_dist * self.extend_range
229
+ diff_radius = radius - mini_dist
230
+
231
+ multi_total = 0.0
232
+ for co, index, dist in kd.find_range(target_co, radius):
233
+ if 0 < diff_radius:
234
+ multi = (diff_radius - (dist - mini_dist)) / diff_radius
235
+ else:
236
+ multi = 1.0
237
+ near_vert_data_append((index, multi))
238
+ multi_total += multi
239
+ near_vert_multi_total_append(multi_total)
240
+
241
+ if vert.index % progress_reduce == 0:
242
+ context.window_manager.progress_update(vert.index)
243
+ context.window_manager.progress_end()
244
+
245
+ is_shapeds = {}
246
+ relative_keys = []
247
+ context.window_manager.progress_begin(0, len(source_me.shape_keys.key_blocks))
248
+ context.window_manager.progress_update(0)
249
+ for source_shape_key_index, source_shape_key in enumerate(source_me.shape_keys.key_blocks):
250
+
251
+ if target_me.shape_keys:
252
+ if source_shape_key.name in target_me.shape_keys.key_blocks:
253
+ target_shape_key = target_me.shape_keys.key_blocks[source_shape_key.name]
254
+ else:
255
+ target_shape_key = target_ob.shape_key_add(name=source_shape_key.name, from_mix=False)
256
+ else:
257
+ target_shape_key = target_ob.shape_key_add(name=source_shape_key.name, from_mix=False)
258
+
259
+ relative_key_name = source_shape_key.relative_key.name
260
+ if relative_key_name not in relative_keys:
261
+ relative_keys.append(relative_key_name)
262
+ is_shapeds[source_shape_key.name] = False
263
+
264
+ try:
265
+ target_shape_key.relative_key = target_me.shape_keys.key_blocks[relative_key_name]
266
+ except:
267
+ pass
268
+
269
+ mat1, mat2 = source_ob.matrix_world, target_ob.matrix_world
270
+ source_shape_keys = [(mat1 * source_shape_key.data[v.index].co * mat2) - (mat1 * source_me.vertices[v.index].co * mat2) for v in source_me.vertices]
271
+
272
+ for target_vert in target_me.vertices:
273
+
274
+ if 0 < near_vert_multi_total[target_vert.index]:
275
+
276
+ total_diff_co = mathutils.Vector((0, 0, 0))
277
+
278
+ for near_index, near_multi in near_vert_data[target_vert.index]:
279
+ total_diff_co += source_shape_keys[near_index] * near_multi
280
+
281
+ average_diff_co = total_diff_co / near_vert_multi_total[target_vert.index]
282
+
283
+ else:
284
+ average_diff_co = mathutils.Vector((0, 0, 0))
285
+
286
+ target_shape_key.data[target_vert.index].co = target_me.vertices[target_vert.index].co + average_diff_co
287
+ if 0.01 < average_diff_co.length:
288
+ is_shapeds[source_shape_key.name] = True
289
+
290
+ context.window_manager.progress_update(source_shape_key_index)
291
+ context.window_manager.progress_end()
292
+
293
+ if self.is_remove_empty:
294
+ for source_shape_key_name, is_shaped in is_shapeds.items():
295
+ if source_shape_key_name not in relative_keys and not is_shaped:
296
+ target_shape_key = target_me.shape_keys.key_blocks[source_shape_key_name]
297
+ target_ob.shape_key_remove(target_shape_key)
298
+
299
+ target_ob.active_shape_key_index = 0
300
+
301
+ common.remove_data([source_ob, source_me])
302
+ context.scene.objects.active = target_ob
303
+ bpy.ops.object.mode_set(mode=pre_mode)
304
+
305
+ diff_time = time.time() - start_time
306
+ self.report(type={'INFO'}, message=str(round(diff_time, 1)) + " Seconds")
307
+ return {'FINISHED'}
308
+
309
+ class multiply_shape_key(bpy.types.Operator):
310
+ bl_idname = 'object.multiply_shape_key'
311
+ bl_label = "Multiply Shape Key"
312
+ bl_description = "Multiply the current shape key so that other shape keys are more affected by it"
313
+ bl_options = {'REGISTER', 'UNDO'}
314
+
315
+ multi = bpy.props.FloatProperty(name="Scale", description="Shape Key Scale Ratio", default=1.1, min=-10, max=10, soft_min=-10, soft_max=10, step=10, precision=2)
316
+ items = [
317
+ ('ACTIVE', "Active only", "", 'HAND', 1),
318
+ ('UP', "Above Active", "", 'TRIA_UP_BAR', 2),
319
+ ('DOWN', "Below Active", "", 'TRIA_DOWN_BAR', 3),
320
+ ('ALL', "All", "", 'ARROW_LEFTRIGHT', 4),
321
+ ]
322
+ mode = bpy.props.EnumProperty(items=items, name="対象", default='ACTIVE')
323
+
324
+ @classmethod
325
+ def poll(cls, context):
326
+ if context.active_object:
327
+ ob = context.active_object
328
+ if ob.type == 'MESH':
329
+ return ob.active_shape_key
330
+ return False
331
+
332
+ def invoke(self, context, event):
333
+ return context.window_manager.invoke_props_dialog(self)
334
+
335
+ def draw(self, context):
336
+ self.layout.prop(self, 'multi', icon='ARROW_LEFTRIGHT')
337
+ self.layout.prop(self, 'mode', icon='VIEWZOOM')
338
+
339
+ def execute(self, context):
340
+ ob = context.active_object
341
+ me = ob.data
342
+ shape_keys = me.shape_keys
343
+ pre_mode = ob.mode
344
+ bpy.ops.object.mode_set(mode='OBJECT')
345
+
346
+ target_shapes = []
347
+ if self.mode == 'ACTIVE':
348
+ target_shapes.append(ob.active_shape_key)
349
+ elif self.mode == 'UP':
350
+ for index, key_block in enumerate(shape_keys.key_blocks):
351
+ if index <= ob.active_shape_key_index:
352
+ target_shapes.append(key_block)
353
+ elif self.mode == 'UP':
354
+ for index, key_block in enumerate(shape_keys.key_blocks):
355
+ if ob.active_shape_key_index <= index:
356
+ target_shapes.append(key_block)
357
+ elif self.mode == 'ALL':
358
+ for key_block in shape_keys.key_blocks:
359
+ target_shapes.append(key_block)
360
+
361
+ for shape in target_shapes:
362
+ data = shape.data
363
+ for i, vert in enumerate(me.vertices):
364
+ diff = data[i].co - vert.co
365
+ diff *= self.multi
366
+ data[i].co = vert.co + diff
367
+ bpy.ops.object.mode_set(mode=pre_mode)
368
+ return {'FINISHED'}
369
+
370
+ class blur_shape_key(bpy.types.Operator):
371
+ bl_idname = 'object.blur_shape_key'
372
+ bl_label = "Blur Shape Key"
373
+ bl_description = "Blur all shape keys or just the active key."
374
+ bl_options = {'REGISTER', 'UNDO'}
375
+
376
+ items = [
377
+ ('ACTIVE', "Active Only", "", 'HAND', 1),
378
+ ('UP', "Above Active", "", 'TRIA_UP_BAR', 2),
379
+ ('DOWN', "Below Active", "", 'TRIA_DOWN_BAR', 3),
380
+ ('ALL', "All", "", 'ARROW_LEFTRIGHT', 4),
381
+ ]
382
+ target = bpy.props.EnumProperty(items=items, name="Active", default='ACTIVE')
383
+ radius = bpy.props.FloatProperty(name="Radius", default=3, min=0.1, max=50, soft_min=0.1, soft_max=50, step=50, precision=2)
384
+ strength = bpy.props.IntProperty(name="Strength", default=1, min=1, max=10, soft_min=1, soft_max=10)
385
+ items = [
386
+ ('BOTH', "Both", "", 'AUTOMERGE_ON', 1),
387
+ ('ADD', "Add", "", 'TRIA_UP', 2),
388
+ ('SUB', "Subtract", "", 'TRIA_DOWN', 3),
389
+ ]
390
+ effect = bpy.props.EnumProperty(items=items, name="Blur Effect", default='BOTH')
391
+ items = [
392
+ ('LINER', "Liner", "", 'LINCURVE', 1),
393
+ ('SMOOTH1', "Smooth 1", "", 'SMOOTHCURVE', 2),
394
+ ('SMOOTH2', "Smooth 2", "", 'SMOOTHCURVE', 3),
395
+ ]
396
+ blend = bpy.props.EnumProperty(items=items, name="Damping Type", default='LINER')
397
+
398
+ @classmethod
399
+ def poll(cls, context):
400
+ ob = context.active_object
401
+ if ob:
402
+ if ob.type == 'MESH':
403
+ me = ob.data
404
+ return me.shape_keys
405
+ return False
406
+
407
+ def invoke(self, context, event):
408
+ return context.window_manager.invoke_props_dialog(self)
409
+
410
+ def draw(self, context):
411
+ self.layout.prop(self, 'target', icon='VIEWZOOM')
412
+ self.layout.prop(self, 'radius', icon='META_EMPTY')
413
+ self.layout.prop(self, 'strength', icon='ARROW_LEFTRIGHT')
414
+ self.layout.prop(self, 'effect', icon='BRUSH_BLUR')
415
+ self.layout.prop(self, 'blend', icon='IPO_SINE')
416
+
417
+ def execute(self, context):
418
+ import bmesh, mathutils
419
+ ob = context.active_object
420
+ me = ob.data
421
+
422
+ pre_mode = ob.mode
423
+ bpy.ops.object.mode_set(mode='OBJECT')
424
+
425
+ bm = bmesh.new()
426
+ bm.from_mesh(me)
427
+ edge_lengths = [e.calc_length() for e in bm.edges]
428
+ bm.free()
429
+ edge_lengths.sort()
430
+ average_edge_length = sum(edge_lengths) / len(edge_lengths)
431
+ center_index = int( (len(edge_lengths) - 1) / 2.0 )
432
+ average_edge_length = (average_edge_length + edge_lengths[center_index]) / 2
433
+ radius = average_edge_length * self.radius
434
+
435
+ context.window_manager.progress_begin(0, len(me.vertices))
436
+ progress_reduce = len(me.vertices) // 200 + 1
437
+ near_vert_data = []
438
+ kd = mathutils.kdtree.KDTree(len(me.vertices))
439
+ for vert in me.vertices:
440
+ kd.insert(vert.co.copy(), vert.index)
441
+ kd.balance()
442
+ for vert in me.vertices:
443
+ near_vert_data.append([])
444
+ near_vert_data_append = near_vert_data[-1].append
445
+ for co, index, dist in kd.find_range(vert.co, radius):
446
+ multi = (radius - dist) / radius
447
+ if self.blend == 'SMOOTH1':
448
+ multi = common.in_out_quad_blend(multi)
449
+ elif self.blend == 'SMOOTH2':
450
+ multi = common.bezier_blend(multi)
451
+ near_vert_data_append((index, multi))
452
+ if vert.index % progress_reduce == 0:
453
+ context.window_manager.progress_update(vert.index)
454
+ context.window_manager.progress_end()
455
+
456
+ target_shape_keys = []
457
+ if self.target == 'ACTIVE':
458
+ target_shape_keys.append(ob.active_shape_key)
459
+ elif self.target == 'UP':
460
+ for index, shape_key in enumerate(me.shape_keys.key_blocks):
461
+ if index <= ob.active_shape_key_index:
462
+ target_shape_keys.append(shape_key)
463
+ elif self.target == 'DOWN':
464
+ for index, shape_key in enumerate(me.shape_keys.key_blocks):
465
+ if ob.active_shape_key_index <= index:
466
+ target_shape_keys.append(shape_key)
467
+ elif self.target == 'ALL':
468
+ for index, shape_key in enumerate(me.shape_keys.key_blocks):
469
+ target_shape_keys.append(shape_key)
470
+
471
+ progress_total = len(target_shape_keys) * self.strength * len(me.vertices)
472
+ context.window_manager.progress_begin(0, progress_total)
473
+ progress_reduce = progress_total // 200 + 1
474
+ progress_count = 0
475
+ for strength_count in range(self.strength):
476
+ for shape_key in target_shape_keys:
477
+
478
+ shapes = []
479
+ shapes_append = shapes.append
480
+ for index, vert in enumerate(me.vertices):
481
+ co = shape_key.data[index].co - vert.co
482
+ shapes_append(co)
483
+
484
+ for vert in me.vertices:
485
+
486
+ target_shape = shapes[vert.index]
487
+
488
+ total_shape = mathutils.Vector()
489
+ total_multi = 0.0
490
+ for index, multi in near_vert_data[vert.index]:
491
+ co = shapes[index]
492
+ if self.effect == 'ADD':
493
+ if target_shape.length <= co.length:
494
+ total_shape += co * multi
495
+ total_multi += multi
496
+ elif self.effect == 'SUB':
497
+ if co.length <= target_shape.length:
498
+ total_shape += co * multi
499
+ total_multi += multi
500
+ else:
501
+ total_shape += co * multi
502
+ total_multi += multi
503
+
504
+ if 0 < total_multi:
505
+ average_shape = total_shape / total_multi
506
+ else:
507
+ average_shape = mathutils.Vector()
508
+
509
+ shape_key.data[vert.index].co = vert.co + average_shape
510
+
511
+ progress_count += 1
512
+ if progress_count % progress_reduce == 0:
513
+ context.window_manager.progress_update(progress_count)
514
+
515
+ context.window_manager.progress_end()
516
+ bpy.ops.object.mode_set(mode=pre_mode)
517
+ return {'FINISHED'}
518
+
519
+ class change_base_shape_key(bpy.types.Operator):
520
+ bl_idname = 'object.change_base_shape_key'
521
+ bl_label = "Change Base Key"
522
+ bl_description = "Will change the key on which the mesh is based."
523
+ bl_options = {'REGISTER', 'UNDO'}
524
+
525
+ is_deform_mesh = bpy.props.BoolProperty(name="Deform Mesh", default=True)
526
+ is_deform_other_shape = bpy.props.BoolProperty(name="Deform other Keys", default=True)
527
+
528
+ @classmethod
529
+ def poll(cls, context):
530
+ ob = context.active_object
531
+ if ob:
532
+ return ob.type=='MESH' and 1 <= ob.active_shape_key_index
533
+ return False
534
+
535
+ def invoke(self, context, event):
536
+ return context.window_manager.invoke_props_dialog(self)
537
+
538
+ def draw(self, context):
539
+ self.layout.prop(self, 'is_deform_mesh', icon='MESH_DATA')
540
+ self.layout.prop(self, 'is_deform_other_shape', icon='SHAPEKEY_DATA')
541
+
542
+ def execute(self, context):
543
+ ob = context.active_object
544
+ me = ob.data
545
+
546
+ pre_mode = ob.mode
547
+ bpy.ops.object.mode_set(mode='OBJECT')
548
+
549
+ target_shape_key = ob.active_shape_key
550
+ old_shape_key = me.shape_keys.key_blocks[0]
551
+
552
+ for i in range(9**9):
553
+ bpy.ops.object.shape_key_move(type='UP')
554
+ if ob.active_shape_key_index == 0:
555
+ break
556
+
557
+ target_shape_key.relative_key = target_shape_key
558
+ old_shape_key.relative_key = target_shape_key
559
+
560
+ if self.is_deform_mesh:
561
+ for vert in me.vertices:
562
+ vert.co = target_shape_key.data[vert.index].co.copy()
563
+
564
+ if self.is_deform_other_shape:
565
+ for shape_key in me.shape_keys.key_blocks:
566
+ if shape_key.name == target_shape_key.name or shape_key.name == old_shape_key.name:
567
+ continue
568
+ if shape_key.relative_key.name == old_shape_key.name:
569
+ shape_key.relative_key = target_shape_key
570
+ for vert in me.vertices:
571
+ diff_co = target_shape_key.data[vert.index].co - old_shape_key.data[vert.index].co
572
+ shape_key.data[vert.index].co = shape_key.data[vert.index].co + diff_co
573
+
574
+ bpy.ops.object.mode_set(mode=pre_mode)
575
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_MESH_MT_vertex_group_specials.py ADDED
@@ -0,0 +1,672 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「メッシュデータ」タブ → 「頂点グループ」パネル → ▼ボタン
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ icon_id = common.preview_collections['main']['KISS'].icon_id
8
+ self.layout.separator()
9
+ self.layout.operator('object.quick_transfer_vertex_group', icon_value=icon_id)
10
+ self.layout.operator('object.precision_transfer_vertex_group', icon_value=icon_id)
11
+ self.layout.separator()
12
+ self.layout.operator('object.quick_blur_vertex_group', icon_value=icon_id)
13
+ self.layout.operator('object.blur_vertex_group', icon_value=icon_id)
14
+ self.layout.separator()
15
+ self.layout.operator('object.multiply_vertex_group', icon_value=icon_id)
16
+ self.layout.separator()
17
+ self.layout.operator('object.remove_noassign_vertex_groups', icon_value=icon_id)
18
+
19
+ class quick_transfer_vertex_group(bpy.types.Operator):
20
+ bl_idname = 'object.quick_transfer_vertex_group'
21
+ bl_label = "Quick Vertex Group Transfer"
22
+ bl_description = "Quickly Transfers the vertex groups of the previously selected mesh to active mesh."
23
+ bl_options = {'REGISTER', 'UNDO'}
24
+
25
+ is_remove_old_vertex_groups = bpy.props.BoolProperty(name="すでにある頂点グループを削除 (ロックで保護)", default=False)
26
+ is_source_select_vert_only = bpy.props.BoolProperty(name="選択頂点のみ(参照)", default=False)
27
+ is_target_select_vert_only = bpy.props.BoolProperty(name="選択頂点のみ(対象)", default=False)
28
+ items = [
29
+ ('NEAREST', "Nearest", "", 'VERTEXSEL', 1),
30
+ ('EDGEINTERP_NEAREST', "Nearest Side", "", 'EDGESEL', 2),
31
+ ('POLYINTERP_NEAREST', "Nearest Face", "", 'FACESEL', 3),
32
+ ('POLYINTERP_VNORPROJ', "Projection", "", 'MOD_UVPROJECT', 4),
33
+ ]
34
+ vert_mapping = bpy.props.EnumProperty(items=items, name="Reference element", default='POLYINTERP_NEAREST')
35
+ is_clean = bpy.props.BoolProperty(name="Clean after Transfer", default=True)
36
+ is_remove_noassign = bpy.props.BoolProperty(name="Delete unassigned vertex groups after transfer", default=True)
37
+
38
+ @classmethod
39
+ def poll(cls, context):
40
+ active_ob = context.active_object
41
+ obs = context.selected_objects
42
+ if len(obs) < 2: return False
43
+ for ob in obs:
44
+ if ob.type != 'MESH':
45
+ return False
46
+ if ob.name != active_ob.name:
47
+ if not len(ob.vertex_groups):
48
+ return False
49
+ return True
50
+
51
+ def invoke(self, context, event):
52
+ return context.window_manager.invoke_props_dialog(self)
53
+
54
+ def draw(self, context):
55
+ self.layout.prop(self, 'is_remove_old_vertex_groups', icon='ERROR')
56
+
57
+ row = self.layout.row(align=True)
58
+ row.prop(self, 'is_source_select_vert_only', icon='UV_SYNC_SELECT')
59
+ row.prop(self, 'is_target_select_vert_only', icon='UV_SYNC_SELECT')
60
+
61
+ self.layout.prop(self, 'vert_mapping')
62
+ self.layout.prop(self, 'is_clean', icon='DISCLOSURE_TRI_DOWN')
63
+ self.layout.prop(self, 'is_remove_noassign', icon='X')
64
+
65
+ def execute(self, context):
66
+ class MyVertexGroupElement: pass
67
+
68
+ target_ob = context.active_object
69
+ target_me = target_ob.data
70
+
71
+ pre_mode = target_ob.mode
72
+ bpy.ops.object.mode_set(mode='OBJECT')
73
+
74
+ original_source_obs = []
75
+ for ob in context.selected_objects:
76
+ if ob.name != target_ob.name:
77
+ original_source_obs.append(ob)
78
+
79
+ target_ob.select = False
80
+ context.scene.objects.active = original_source_obs[0]
81
+ bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
82
+ bpy.ops.object.join()
83
+ join_source_ob = context.selected_objects[0]
84
+ join_source_me = join_source_ob.data
85
+ target_ob.select = True
86
+ context.scene.objects.active = target_ob
87
+
88
+ temp_source_ob = join_source_ob.copy()
89
+ temp_source_me = join_source_me.copy()
90
+ temp_source_ob.data = temp_source_me
91
+ context.scene.objects.link(temp_source_ob)
92
+ temp_source_ob.select = True
93
+ join_source_ob.select = False
94
+ context.scene.objects.active = temp_source_ob
95
+ if self.is_source_select_vert_only:
96
+ bpy.ops.object.mode_set(mode='EDIT')
97
+ bpy.ops.mesh.select_all(action='INVERT')
98
+ bpy.ops.mesh.delete(type='VERT')
99
+ bpy.ops.object.mode_set(mode='OBJECT')
100
+ context.scene.objects.active = target_ob
101
+
102
+ if self.vert_mapping == 'POLYINTERP_VNORPROJ' and len(temp_source_me.polygons) == 0:
103
+ self.vert_mapping = 'EDGEINTERP_NEAREST'
104
+ self.report(type={'WARNING'}, message="There is no face, change to edge mode")
105
+ if self.vert_mapping == 'POLYINTERP_NEAREST' and len(temp_source_me.polygons) == 0:
106
+ self.vert_mapping = 'EDGEINTERP_NEAREST'
107
+ self.report(type={'WARNING'}, message="There is no face, change to edge mode")
108
+ if self.vert_mapping == 'EDGEINTERP_NEAREST' and len(temp_source_me.edges) == 0:
109
+ self.vert_mapping = 'NEAREST'
110
+ self.report(type={'WARNING'}, message="There is no edge, change to vertex mode")
111
+ if self.vert_mapping == 'NEAREST' and len(temp_source_me.vertices) == 0:
112
+ self.report(type={'ERROR'}, message="There is no edge, change to vertex mode")
113
+ return {'CANCELLED'}
114
+
115
+ if self.is_remove_old_vertex_groups:
116
+ for vg in target_ob.vertex_groups[:]:
117
+ if not vg.lock_weight:
118
+ target_ob.vertex_groups.remove(vg)
119
+
120
+ old_vertex_groups = []
121
+ for vert in target_me.vertices:
122
+ mvges = []
123
+ for vge in vert.groups:
124
+ mvge = MyVertexGroupElement()
125
+ mvge.vertex_group = target_ob.vertex_groups[vge.group]
126
+ mvge.weight = vge.weight
127
+ mvges.append(mvge)
128
+ old_vertex_groups.append(mvges)
129
+
130
+ if self.is_remove_noassign:
131
+ pre_vertex_group_names = [vg.name for vg in target_ob.vertex_groups]
132
+
133
+ bpy.ops.object.data_transfer(use_reverse_transfer=True, use_freeze=False, data_type='VGROUP_WEIGHTS', use_create=True, vert_mapping=self.vert_mapping, use_auto_transform=False, use_object_transform=True, use_max_distance=False, ray_radius=0, layers_select_src='NAME', layers_select_dst='ALL', mix_mode='REPLACE', mix_factor=1)
134
+ if self.is_clean: bpy.ops.object.vertex_group_clean(group_select_mode='ALL', limit=0.00000000001)
135
+
136
+ bpy.ops.object.mode_set(mode='EDIT')
137
+ bpy.ops.object.mode_set(mode='OBJECT')
138
+
139
+ if self.is_remove_noassign:
140
+ is_keeps = [False for i in range(len(target_ob.vertex_groups))]
141
+ for vert in target_me.vertices:
142
+ for vge in vert.groups:
143
+ if not is_keeps[vge.group]:
144
+ if 0.000001 < vge.weight:
145
+ is_keeps[vge.group] = True
146
+ copy_vertex_groups = target_ob.vertex_groups[:]
147
+ for i in range(len(copy_vertex_groups)):
148
+ if not is_keeps[i] and not copy_vertex_groups[i].lock_weight:
149
+ if copy_vertex_groups[i].name not in pre_vertex_group_names:
150
+ target_ob.vertex_groups.remove(copy_vertex_groups[i])
151
+
152
+ if self.is_target_select_vert_only:
153
+ for vert in target_me.vertices:
154
+ if not vert.select:
155
+ for vg in target_ob.vertex_groups:
156
+ vg.remove([vert.index])
157
+ for mvge in old_vertex_groups[vert.index]:
158
+ mvge.vertex_group.add([vert.index], mvge.weight, 'REPLACE')
159
+
160
+ for vert in target_me.vertices:
161
+ for vg in target_ob.vertex_groups:
162
+ if vg.lock_weight:
163
+ vg.remove([vert.index])
164
+ for mvge in old_vertex_groups[vert.index]:
165
+ if mvge.vertex_group.lock_weight:
166
+ mvge.vertex_group.add([vert.index], mvge.weight, 'REPLACE')
167
+
168
+ common.remove_data([temp_source_ob, temp_source_me])
169
+ join_source_ob.select = True
170
+
171
+ common.remove_data([join_source_ob, join_source_me])
172
+ for ob in original_source_obs:
173
+ ob.select = True
174
+
175
+ context.scene.objects.active = target_ob
176
+ bpy.ops.object.mode_set(mode=pre_mode)
177
+ return {'FINISHED'}
178
+
179
+ class precision_transfer_vertex_group(bpy.types.Operator):
180
+ bl_idname = 'object.precision_transfer_vertex_group'
181
+ bl_label = "High Precision Vertex Group transfer"
182
+ bl_description = "Will transfer the vertex groups from the previously selected mesh to the active mesh with more precision."
183
+ bl_options = {'REGISTER', 'UNDO'}
184
+
185
+ is_first_remove_all = bpy.props.BoolProperty(name="Remove Previous Groups", default=False)
186
+ subdivide_number = bpy.props.IntProperty(name="Subdivide Amount", default=1, min=0, max=10, soft_min=0, soft_max=10)
187
+ extend_range = bpy.props.FloatProperty(name="Range", default=1.1, min=1.0001, max=5.0, soft_min=1.0001, soft_max=5.0, step=10, precision=2)
188
+ is_remove_empty = bpy.props.BoolProperty(name="Remove Empty Vertex Groups", default=True)
189
+
190
+ @classmethod
191
+ def poll(cls, context):
192
+ active_ob = context.active_object
193
+ obs = context.selected_objects
194
+ if len(obs) != 2: return False
195
+ for ob in obs:
196
+ if ob.type != 'MESH':
197
+ return False
198
+ if ob.name != active_ob.name:
199
+ if len(ob.vertex_groups):
200
+ return True
201
+ return False
202
+
203
+ def invoke(self, context, event):
204
+ return context.window_manager.invoke_props_dialog(self)
205
+
206
+ def draw(self, context):
207
+ self.layout.prop(self, 'is_first_remove_all', icon='ERROR')
208
+ self.layout.prop(self, 'subdivide_number', icon='LATTICE_DATA')
209
+ self.layout.prop(self, 'extend_range', icon='META_EMPTY')
210
+ self.layout.prop(self, 'is_remove_empty', icon='X')
211
+
212
+ def execute(self, context):
213
+ import mathutils, time
214
+ start_time = time.time()
215
+
216
+ target_ob = context.active_object
217
+ target_me = target_ob.data
218
+
219
+ pre_mode = target_ob.mode
220
+ bpy.ops.object.mode_set(mode='OBJECT')
221
+
222
+ for ob in context.selected_objects:
223
+ if ob.name != target_ob.name:
224
+ source_original_ob = ob
225
+ break
226
+ source_ob = source_original_ob.copy()
227
+ source_me = source_original_ob.data.copy()
228
+ source_ob.data = source_me
229
+ context.scene.objects.link(source_ob)
230
+ context.scene.objects.active = source_ob
231
+ bpy.ops.object.mode_set(mode='EDIT')
232
+ bpy.ops.mesh.reveal()
233
+ bpy.ops.mesh.select_all(action='SELECT')
234
+ bpy.ops.mesh.subdivide(number_cuts=self.subdivide_number, smoothness=0.0, quadtri=False, quadcorner='STRAIGHT_CUT', fractal=0.0, fractal_along_normal=0.0, seed=0)
235
+ bpy.ops.object.mode_set(mode='OBJECT')
236
+
237
+ if self.is_first_remove_all:
238
+ for vg in target_ob.vertex_groups[:]:
239
+ if not vg.lock_weight:
240
+ target_ob.vertex_groups.remove(vg)
241
+
242
+ kd = mathutils.kdtree.KDTree(len(source_me.vertices))
243
+ for vert in source_me.vertices:
244
+ co = source_ob.matrix_world * vert.co
245
+ kd.insert(co, vert.index)
246
+ kd.balance()
247
+
248
+ context.window_manager.progress_begin(0, len(target_me.vertices))
249
+ progress_reduce = len(target_me.vertices) // 200 + 1
250
+ near_vert_data = []
251
+ near_vert_multi_total = []
252
+ near_vert_multi_total_append = near_vert_multi_total.append
253
+ for vert in target_me.vertices:
254
+ near_vert_data.append([])
255
+ near_vert_data_append = near_vert_data[-1].append
256
+
257
+ target_co = target_ob.matrix_world * vert.co
258
+
259
+ mini_co, mini_index, mini_dist = kd.find(target_co)
260
+ radius = mini_dist * self.extend_range
261
+ diff_radius = radius - mini_dist
262
+
263
+ multi_total = 0.0
264
+ for co, index, dist in kd.find_range(target_co, radius):
265
+ if 0 < diff_radius:
266
+ multi = (diff_radius - (dist - mini_dist)) / diff_radius
267
+ else:
268
+ multi = 1.0
269
+ near_vert_data_append((index, multi))
270
+ multi_total += multi
271
+ near_vert_multi_total_append(multi_total)
272
+
273
+ if vert.index % progress_reduce == 0:
274
+ context.window_manager.progress_update(vert.index)
275
+ context.window_manager.progress_end()
276
+
277
+ context.window_manager.progress_begin(0, len(source_ob.vertex_groups))
278
+ for source_vertex_group in source_ob.vertex_groups:
279
+
280
+ if source_vertex_group.name in target_ob.vertex_groups:
281
+ target_vertex_group = target_ob.vertex_groups[source_vertex_group.name]
282
+ else:
283
+ target_vertex_group = target_ob.vertex_groups.new(source_vertex_group.name)
284
+
285
+ is_waighted = False
286
+
287
+ source_weights = []
288
+ source_weights_append = source_weights.append
289
+ for source_vert in source_me.vertices:
290
+ for elem in source_vert.groups:
291
+ if elem.group == source_vertex_group.index:
292
+ source_weights_append(elem.weight)
293
+ break
294
+ else:
295
+ source_weights_append(0.0)
296
+
297
+ for target_vert in target_me.vertices:
298
+
299
+ if 0 < near_vert_multi_total[target_vert.index]:
300
+
301
+ total_weight = [source_weights[i] * m for i, m in near_vert_data[target_vert.index]]
302
+ total_weight = sum(total_weight)
303
+
304
+ average_weight = total_weight / near_vert_multi_total[target_vert.index]
305
+ else:
306
+ average_weight = 0.0
307
+
308
+ if 0.000001 < average_weight:
309
+ target_vertex_group.add([target_vert.index], average_weight, 'REPLACE')
310
+ is_waighted = True
311
+ else:
312
+ if not self.is_first_remove_all:
313
+ target_vertex_group.remove([target_vert.index])
314
+
315
+ context.window_manager.progress_update(source_vertex_group.index)
316
+
317
+ if not is_waighted and self.is_remove_empty:
318
+ target_ob.vertex_groups.remove(target_vertex_group)
319
+ context.window_manager.progress_end()
320
+
321
+ target_ob.vertex_groups.active_index = 0
322
+
323
+ common.remove_data([source_ob, source_me])
324
+ context.scene.objects.active = target_ob
325
+ bpy.ops.object.mode_set(mode=pre_mode)
326
+
327
+ diff_time = time.time() - start_time
328
+ self.report(type={'INFO'}, message=str(round(diff_time, 1)) + " Seconds")
329
+ return {'FINISHED'}
330
+
331
+ class quick_blur_vertex_group(bpy.types.Operator):
332
+ bl_idname = 'object.quick_blur_vertex_group'
333
+ bl_label = "Blur Vertex Group"
334
+ bl_description = "Will Blur the active vertex group or all vertex groups."
335
+ bl_options = {'REGISTER', 'UNDO'}
336
+
337
+ items = [
338
+ ('ACTIVE', "Active", "", 'HAND', 1),
339
+ ('ALL', "All", "", 'ARROW_LEFTRIGHT', 2),
340
+ ]
341
+ target = bpy.props.EnumProperty(items=items, name="Target", default='ALL')
342
+ strength = bpy.props.FloatProperty(name="Strength", default=1.0, min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, step=10, precision=3)
343
+ count = bpy.props.IntProperty(name="Count", default=1, min=1, max=256, soft_min=1, soft_max=256)
344
+ size = bpy.props.FloatProperty(name="Size", default=0.0, min=-1.0, max=1.0, soft_min=-1.0, soft_max=1.0, step=10, precision=3)
345
+
346
+ @classmethod
347
+ def poll(cls, context):
348
+ ob = context.active_object
349
+ if ob:
350
+ if ob.type == 'MESH':
351
+ return ob.vertex_groups.active
352
+ return False
353
+
354
+ def invoke(self, context, event):
355
+ return context.window_manager.invoke_props_dialog(self)
356
+
357
+ def draw(self, context):
358
+ self.layout.prop(self, 'target', icon='VIEWZOOM')
359
+ self.layout.prop(self, 'strength')
360
+ self.layout.prop(self, 'count')
361
+ self.layout.prop(self, 'size')
362
+
363
+ def execute(self, context):
364
+ target_ob = context.active_object
365
+ target_me = target_ob.data
366
+
367
+ pre_mode = target_ob.mode
368
+ bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
369
+
370
+ pre_use_paint_mask_vertex = target_me.use_paint_mask_vertex
371
+ target_me.use_paint_mask_vertex = True
372
+
373
+ bpy.ops.paint.vert_select_all(action='SELECT')
374
+ bpy.ops.object.vertex_group_smooth(group_select_mode=self.target, factor=self.strength, repeat=self.count, expand=self.size, source='ALL')
375
+
376
+ target_me.use_paint_mask_vertex = pre_use_paint_mask_vertex
377
+
378
+ bpy.ops.object.mode_set(mode=pre_mode)
379
+ return {'FINISHED'}
380
+
381
+ class blur_vertex_group(bpy.types.Operator):
382
+ bl_idname = 'object.blur_vertex_group'
383
+ bl_label = "Blur Vertex Group"
384
+ bl_description = "Blur or all just the active Vertex Group"
385
+ bl_options = {'REGISTER', 'UNDO'}
386
+
387
+ items = [
388
+ ('ACTIVE', "Active", "", 'HAND', 1),
389
+ ('UP', "Above Active", "", 'TRIA_UP_BAR', 2),
390
+ ('DOWN', "Below Active", "", 'TRIA_DOWN_BAR', 3),
391
+ ('ALL', "All", "", 'ARROW_LEFTRIGHT', 4),
392
+ ]
393
+ target = bpy.props.EnumProperty(items=items, name="Target", default='ACTIVE')
394
+ radius = bpy.props.FloatProperty(name="Radius", default=3, min=0.1, max=50, soft_min=0.1, soft_max=50, step=50, precision=2)
395
+ strength = bpy.props.IntProperty(name="Strength", default=1, min=1, max=10, soft_min=1, soft_max=10)
396
+ items = [
397
+ ('BOTH', "Both", "", 'AUTOMERGE_ON', 1),
398
+ ('ADD', "Add", "", 'TRIA_UP', 2),
399
+ ('SUB', "Subtract", "", 'TRIA_DOWN', 3),
400
+ ]
401
+ effect = bpy.props.EnumProperty(items=items, name="Blur Effect", default='BOTH')
402
+ is_normalize = bpy.props.BoolProperty(name="Normalize", default=True)
403
+
404
+ @classmethod
405
+ def poll(cls, context):
406
+ ob = context.active_object
407
+ if ob:
408
+ if ob.type == 'MESH':
409
+ return ob.vertex_groups.active
410
+ return False
411
+
412
+ def invoke(self, context, event):
413
+ return context.window_manager.invoke_props_dialog(self)
414
+
415
+ def draw(self, context):
416
+ self.layout.prop(self, 'target', icon='VIEWZOOM')
417
+ self.layout.prop(self, 'radius', icon='META_EMPTY')
418
+ self.layout.prop(self, 'strength', icon='ARROW_LEFTRIGHT')
419
+ self.layout.prop(self, 'effect', icon='BRUSH_BLUR')
420
+ self.layout.prop(self, 'is_normalize', icon='ALIGN')
421
+
422
+ def execute(self, context):
423
+ import bmesh, mathutils
424
+ ob = context.active_object
425
+ me = ob.data
426
+
427
+ pre_mode = ob.mode
428
+ bpy.ops.object.mode_set(mode='OBJECT')
429
+
430
+ bm = bmesh.new()
431
+ bm.from_mesh(me)
432
+ edge_lengths = [e.calc_length() for e in bm.edges]
433
+ bm.free()
434
+ edge_lengths.sort()
435
+ average_edge_length = sum(edge_lengths) / len(edge_lengths)
436
+ center_index = int( (len(edge_lengths) - 1) / 2.0 )
437
+ average_edge_length = (average_edge_length + edge_lengths[center_index]) / 2
438
+ radius = average_edge_length * self.radius
439
+
440
+ context.window_manager.progress_begin(0, len(me.vertices))
441
+ progress_reduce = len(me.vertices) // 200 + 1
442
+ near_vert_data = []
443
+ kd = mathutils.kdtree.KDTree(len(me.vertices))
444
+ for vert in me.vertices:
445
+ kd.insert(vert.co.copy(), vert.index)
446
+ kd.balance()
447
+ for vert in me.vertices:
448
+ near_vert_data.append([])
449
+ near_vert_data_append = near_vert_data[-1].append
450
+ for co, index, dist in kd.find_range(vert.co, radius):
451
+ multi = (radius - dist) / radius
452
+ near_vert_data_append((index, multi))
453
+ if vert.index % progress_reduce == 0:
454
+ context.window_manager.progress_update(vert.index)
455
+ context.window_manager.progress_end()
456
+
457
+ target_vertex_groups = []
458
+ if self.target == 'ACTIVE':
459
+ target_vertex_groups.append(ob.vertex_groups.active)
460
+ elif self.target == 'UP':
461
+ for vertex_group in ob.vertex_groups:
462
+ if vertex_group.index <= ob.vertex_groups.active_index:
463
+ target_vertex_groups.append(vertex_group)
464
+ elif self.target == 'DOWN':
465
+ for vertex_group in ob.vertex_groups:
466
+ if ob.vertex_groups.active_index <= vertex_group.index:
467
+ target_vertex_groups.append(vertex_group)
468
+ elif self.target == 'ALL':
469
+ for vertex_group in ob.vertex_groups:
470
+ target_vertex_groups.append(vertex_group)
471
+
472
+ progress_total = len(target_vertex_groups) * self.strength * len(me.vertices)
473
+ context.window_manager.progress_begin(0, progress_total)
474
+ progress_reduce = progress_total // 200 + 1
475
+ progress_count = 0
476
+ for strength_count in range(self.strength):
477
+ for vertex_group in target_vertex_groups:
478
+
479
+ weights = []
480
+ weights_append = weights.append
481
+ for vert in me.vertices:
482
+ for elem in vert.groups:
483
+ if elem.group == vertex_group.index:
484
+ weights_append(elem.weight)
485
+ break
486
+ else:
487
+ weights_append(0.0)
488
+
489
+ for vert in me.vertices:
490
+
491
+ target_weight = weights[vert.index]
492
+
493
+ total_weight = 0.0
494
+ total_multi = 0.0
495
+ for index, multi in near_vert_data[vert.index]:
496
+ if self.effect == 'ADD':
497
+ if target_weight <= weights[index]:
498
+ total_weight += weights[index] * multi
499
+ total_multi += multi
500
+ elif self.effect == 'SUB':
501
+ if weights[index] <= target_weight:
502
+ total_weight += weights[index] * multi
503
+ total_multi += multi
504
+ else:
505
+ total_weight += weights[index] * multi
506
+ total_multi += multi
507
+
508
+ if 0 < total_multi:
509
+ average_weight = total_weight / total_multi
510
+ else:
511
+ average_weight = 0.0
512
+
513
+ if 0.001 < average_weight:
514
+ vertex_group.add([vert.index], average_weight, 'REPLACE')
515
+ else:
516
+ vertex_group.remove([vert.index])
517
+
518
+ progress_count += 1
519
+ if progress_count % progress_reduce == 0:
520
+ context.window_manager.progress_update(progress_count)
521
+
522
+ if self.is_normalize:
523
+
524
+ other_weight_total = 0.0
525
+ for elem in vert.groups:
526
+ if elem.group != vertex_group.index:
527
+ other_weight_total += elem.weight
528
+
529
+ diff_weight = average_weight - target_weight
530
+ new_other_weight_total = other_weight_total - diff_weight
531
+ if 0 < other_weight_total:
532
+ other_weight_multi = new_other_weight_total / other_weight_total
533
+ else:
534
+ other_weight_multi = 0.0
535
+
536
+ for elem in vert.groups:
537
+ if elem.group != vertex_group.index:
538
+ vg = ob.vertex_groups[elem.group]
539
+ vg.add([vert.index], elem.weight * other_weight_multi, 'REPLACE')
540
+
541
+ context.window_manager.progress_end()
542
+ bpy.ops.object.mode_set(mode=pre_mode)
543
+ return {'FINISHED'}
544
+
545
+ class multiply_vertex_group(bpy.types.Operator):
546
+ bl_idname = 'object.multiply_vertex_group'
547
+ bl_label = "Multiply vertex groups"
548
+ bl_description = "Multiply the weight of the vertex group by a numerical value to increase or decrease the weight strength"
549
+ bl_options = {'REGISTER', 'UNDO'}
550
+
551
+ items = [
552
+ ('ACTIVE', "Active Only", "", 'HAND', 1),
553
+ ('UP', "Above Active", "", 'TRIA_UP_BAR', 2),
554
+ ('DOWN', "Below Active", "", 'TRIA_DOWN_BAR', 3),
555
+ ('ALL', "All", "", 'ARROW_LEFTRIGHT', 4),
556
+ ]
557
+ target = bpy.props.EnumProperty(items=items, name="Target", default='ACTIVE')
558
+ value = bpy.props.FloatProperty(name="Value", default=1.1, min=0.1, max=10, soft_min=0.1, soft_max=10, step=10, precision=2)
559
+ is_normalize = bpy.props.BoolProperty(name="Normalize", default=True)
560
+
561
+ @classmethod
562
+ def poll(cls, context):
563
+ ob = context.active_object
564
+ if ob:
565
+ if ob.type == 'MESH':
566
+ return ob.vertex_groups.active
567
+ return False
568
+
569
+ def invoke(self, context, event):
570
+ return context.window_manager.invoke_props_dialog(self)
571
+
572
+ def draw(self, context):
573
+ self.layout.prop(self, 'target', icon='VIEWZOOM')
574
+ self.layout.prop(self, 'value', icon='ARROW_LEFTRIGHT')
575
+ self.layout.prop(self, 'is_normalize', icon='ALIGN')
576
+
577
+ def execute(self, context):
578
+ ob = context.active_object
579
+ me = ob.data
580
+
581
+ pre_mode = ob.mode
582
+ bpy.ops.object.mode_set(mode='OBJECT')
583
+
584
+ target_vertex_groups = []
585
+ if self.target == 'ACTIVE':
586
+ target_vertex_groups.append(ob.vertex_groups.active)
587
+ elif self.target == 'UP':
588
+ for vertex_group in ob.vertex_groups:
589
+ if vertex_group.index <= ob.vertex_groups.active_index:
590
+ target_vertex_groups.append(vertex_group)
591
+ elif self.target == 'DOWN':
592
+ for vertex_group in ob.vertex_groups:
593
+ if ob.vertex_groups.active_index <= vertex_group.index:
594
+ target_vertex_groups.append(vertex_group)
595
+ elif self.target == 'ALL':
596
+ for vertex_group in ob.vertex_groups:
597
+ target_vertex_groups.append(vertex_group)
598
+
599
+ for vertex_group in target_vertex_groups:
600
+ for vert in me.vertices:
601
+
602
+ old_weight = -1
603
+ other_weight_total = 0.0
604
+ for elem in vert.groups:
605
+ if elem.group == vertex_group.index:
606
+ old_weight = elem.weight
607
+ else:
608
+ other_weight_total += elem.weight
609
+ if old_weight == -1:
610
+ continue
611
+
612
+ new_weight = old_weight * self.value
613
+ vertex_group.add([vert.index], new_weight, 'REPLACE')
614
+
615
+ if self.is_normalize:
616
+
617
+ diff_weight = new_weight - old_weight
618
+
619
+ new_other_weight_total = other_weight_total - diff_weight
620
+ if 0 < other_weight_total:
621
+ other_weight_multi = new_other_weight_total / other_weight_total
622
+ else:
623
+ other_weight_multi = 0.0
624
+
625
+ for elem in vert.groups:
626
+ if elem.group != vertex_group.index:
627
+ vg = ob.vertex_groups[elem.group]
628
+ vg.add([vert.index], elem.weight * other_weight_multi, 'REPLACE')
629
+
630
+ bpy.ops.object.mode_set(mode=pre_mode)
631
+ return {'FINISHED'}
632
+
633
+ class remove_noassign_vertex_groups(bpy.types.Operator):
634
+ bl_idname = 'object.remove_noassign_vertex_groups'
635
+ bl_label = "Delete Empty Vertex Groups"
636
+ bl_description = "Will delete any vertex groups which do not have any vertices assigned to it"
637
+ bl_options = {'REGISTER', 'UNDO'}
638
+
639
+ threshold = bpy.props.FloatProperty(name="Threshold", default=0.000001, min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, step=1, precision=10)
640
+
641
+ @classmethod
642
+ def poll(cls, context):
643
+ ob = context.active_object
644
+ if ob:
645
+ if ob.type == 'MESH':
646
+ return bool(len(ob.vertex_groups))
647
+ return False
648
+
649
+ def invoke(self, context, event):
650
+ return context.window_manager.invoke_props_dialog(self)
651
+
652
+ def draw(self, context):
653
+ self.layout.prop(self, 'threshold')
654
+
655
+ def execute(self, context):
656
+ ob = context.active_object
657
+ me = ob.data
658
+
659
+ is_keeps = [False for i in range(len(ob.vertex_groups))]
660
+
661
+ for vert in me.vertices:
662
+ for vge in vert.groups:
663
+ if not is_keeps[vge.group]:
664
+ if self.threshold < vge.weight:
665
+ is_keeps[vge.group] = True
666
+
667
+ copy_vertex_groups = ob.vertex_groups[:]
668
+ for i in range(len(copy_vertex_groups)):
669
+ if not is_keeps[i] and not copy_vertex_groups[i].lock_weight:
670
+ ob.vertex_groups.remove(copy_vertex_groups[i])
671
+
672
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_OBJECT_PT_context_object.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「オブジェクト」タブ
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ import re
8
+ ob = context.active_object
9
+ if not ob: return
10
+ if ob.type != 'MESH': return
11
+
12
+ bone_data_count = 0
13
+ if 'BoneData:0' in ob and 'LocalBoneData:0' in ob:
14
+ for key in ob.keys():
15
+ if re.search(r'^(Local)?BoneData:\d+$', key):
16
+ bone_data_count += 1
17
+ enabled_clipboard = False
18
+ clipboard = context.window_manager.clipboard
19
+ if 'BoneData:' in clipboard and 'LocalBoneData:' in clipboard:
20
+ enabled_clipboard = True
21
+
22
+ if bone_data_count or enabled_clipboard:
23
+ col = self.layout.column(align=True)
24
+ row = col.row(align=True)
25
+ row.label(text="CM3D2 Bone Data", icon_value=common.preview_collections['main']['KISS'].icon_id)
26
+ sub_row = row.row()
27
+ sub_row.alignment = 'RIGHT'
28
+ if 'BoneData:0' in ob and 'LocalBoneData:0' in ob:
29
+ bone_data_count = 0
30
+ for key in ob.keys():
31
+ if re.search(r'^(Local)?BoneData:\d+$', key):
32
+ bone_data_count += 1
33
+ sub_row.label(text=str(bone_data_count), icon='CHECKBOX_HLT')
34
+ else:
35
+ sub_row.label(text="0", icon='CHECKBOX_DEHLT')
36
+ row = col.row(align=True)
37
+ row.operator('object.copy_object_bone_data_property', icon='COPYDOWN', text="Copy")
38
+ row.operator('object.paste_object_bone_data_property', icon='PASTEDOWN', text="Paste")
39
+ row.operator('object.remove_object_bone_data_property', icon='X', text="")
40
+
41
+ class copy_object_bone_data_property(bpy.types.Operator):
42
+ bl_idname = 'object.copy_object_bone_data_property'
43
+ bl_label = "Copy the Bone Data from the object's custom properties"
44
+ bl_description = "Copies the bone Data in the object's custom properties to the clipboard."
45
+ bl_options = {'REGISTER', 'UNDO'}
46
+
47
+ @classmethod
48
+ def poll(cls, context):
49
+ ob = context.active_object
50
+ if ob:
51
+ if 'BoneData:0' in ob and 'LocalBoneData:0' in ob:
52
+ return True
53
+ return False
54
+
55
+ def execute(self, context):
56
+ output_text = ""
57
+ ob = context.active_object
58
+ pass_count = 0
59
+ if 'BaseBone' in ob:
60
+ output_text += "BaseBone:" + ob['BaseBone'] + "\n"
61
+ for i in range(99999):
62
+ name = "BoneData:" + str(i)
63
+ if name in ob:
64
+ output_text += "BoneData:" + ob[name] + "\n"
65
+ else:
66
+ pass_count += 1
67
+ if 10 < pass_count:
68
+ break
69
+ pass_count = 0
70
+ for i in range(99999):
71
+ name = "LocalBoneData:" + str(i)
72
+ if name in ob:
73
+ output_text += "LocalBoneData:" + ob[name] + "\n"
74
+ else:
75
+ pass_count += 1
76
+ if 10 < pass_count:
77
+ break
78
+ context.window_manager.clipboard = output_text
79
+ self.report(type={'INFO'}, message="Bone Data was copied to the clipboard.")
80
+ return {'FINISHED'}
81
+
82
+ class paste_object_bone_data_property(bpy.types.Operator):
83
+ bl_idname = 'object.paste_object_bone_data_property'
84
+ bl_label = "Paste Bone Data"
85
+ bl_description = "Paste Bone Data from the clipboard into the object's custom properties. NOTE:Any data in custom properties will be replaced."
86
+ bl_options = {'REGISTER', 'UNDO'}
87
+
88
+ @classmethod
89
+ def poll(cls, context):
90
+ ob = context.active_object
91
+ if ob:
92
+ clipboard = context.window_manager.clipboard
93
+ if 'BoneData:' in clipboard and 'LocalBoneData:' in clipboard:
94
+ return True
95
+ return False
96
+
97
+ def execute(self, context):
98
+ import re
99
+ ob = context.active_object
100
+ pass_count = 0
101
+ for i in range(99999):
102
+ name = "BoneData:" + str(i)
103
+ if name in ob:
104
+ del ob[name]
105
+ else:
106
+ pass_count += 1
107
+ if 10 < pass_count:
108
+ break
109
+ pass_count = 0
110
+ for i in range(99999):
111
+ name = "LocalBoneData:" + str(i)
112
+ if name in ob:
113
+ del ob[name]
114
+ else:
115
+ pass_count += 1
116
+ if 10 < pass_count:
117
+ break
118
+ bone_data_count = 0
119
+ local_bone_data_count = 0
120
+ for line in context.window_manager.clipboard.split("\n"):
121
+ r = re.search('^BaseBone:(.+)$', line)
122
+ if r:
123
+ ob['BaseBone'] = r.groups()[0]
124
+ r = re.search('^BoneData:(.+)$', line)
125
+ if r:
126
+ if line.count(',') == 4:
127
+ info = r.groups()[0]
128
+ name = "BoneData:" + str(bone_data_count)
129
+ ob[name] = info
130
+ bone_data_count += 1
131
+ r = re.search('^LocalBoneData:(.+)$', line)
132
+ if r:
133
+ if line.count(',') == 1:
134
+ info = r.groups()[0]
135
+ name = "LocalBoneData:" + str(local_bone_data_count)
136
+ ob[name] = info
137
+ local_bone_data_count += 1
138
+ self.report(type={'INFO'}, message="Data was pasted, mission accomplished")
139
+ return {'FINISHED'}
140
+
141
+ class remove_object_bone_data_property(bpy.types.Operator):
142
+ bl_idname = 'object.remove_object_bone_data_property'
143
+ bl_label = "Remove the bone Data"
144
+ bl_description = "Remove all bone Data for the custom properties"
145
+ bl_options = {'REGISTER', 'UNDO'}
146
+
147
+ @classmethod
148
+ def poll(cls, context):
149
+ ob = context.active_object
150
+ if ob:
151
+ if 'BoneData:0' in ob and 'LocalBoneData:0' in ob:
152
+ return True
153
+ return False
154
+
155
+ def invoke(self, context, event):
156
+ return context.window_manager.invoke_props_dialog(self)
157
+
158
+ def draw(self, context):
159
+ self.layout.label(text="Remove all bone Data form the custom properties?", icon='CANCEL')
160
+
161
+ def execute(self, context):
162
+ ob = context.active_object
163
+ pass_count = 0
164
+ if 'BaseBone' in ob:
165
+ del ob['BaseBone']
166
+ for i in range(99999):
167
+ name = "BoneData:" + str(i)
168
+ if name in ob:
169
+ del ob[name]
170
+ else:
171
+ pass_count += 1
172
+ if 10 < pass_count:
173
+ break
174
+ pass_count = 0
175
+ for i in range(99999):
176
+ name = "LocalBoneData:" + str(i)
177
+ if name in ob:
178
+ del ob[name]
179
+ else:
180
+ pass_count += 1
181
+ if 10 < pass_count:
182
+ break
183
+ self.report(type={'INFO'}, message="Bone Data was removed. Mission Accomplished.")
184
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_OBJECT_PT_transform.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「オブジェクト」タブ → 「トランスフォーム」パネル
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ self.layout.operator('object.sync_object_transform', icon_value=common.preview_collections['main']['KISS'].icon_id)
8
+
9
+ class sync_object_transform(bpy.types.Operator):
10
+ bl_idname = 'object.sync_object_transform'
11
+ bl_label = "Copy Origin Position"
12
+ bl_description = "The previously selected item's origin is copied onto the active object."
13
+ bl_options = {'REGISTER', 'UNDO'}
14
+
15
+ @classmethod
16
+ def poll(cls, context):
17
+ obs = context.selected_objects
18
+ return len(obs) == 2
19
+
20
+ def execute(self, context):
21
+ target_ob = context.active_object
22
+ for ob in context.selected_objects:
23
+ if target_ob.name != ob.name:
24
+ source_ob = ob
25
+ break
26
+
27
+ for area in context.screen.areas:
28
+ if area.type == 'VIEW_3D':
29
+ for space in area.spaces:
30
+ if space.type == 'VIEW_3D':
31
+ target_space = space
32
+ break
33
+
34
+ pre_cursor_location = target_space.cursor_location[:]
35
+ target_space.cursor_location = source_ob.location[:]
36
+
37
+ source_ob.select = False
38
+ bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
39
+ source_ob.select = True
40
+
41
+ target_space.cursor_location = pre_cursor_location[:]
42
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_RENDER_PT_bake.py ADDED
@@ -0,0 +1,1680 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「レンダー」タブ → 「ベイク」パネル
2
+ import os, re, sys, bpy, time, numpy, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ col = self.layout.column(align=True)
8
+ col.label(text="CM3D2 Bake", icon_value=common.preview_collections['main']['KISS'].icon_id)
9
+ row = col.row(align=True)
10
+ row.operator('object.add_bake_image', icon='IMAGE_COL', text="New image")
11
+ row.operator('object.quick_ao_bake_image', icon='BRUSH_TEXFILL', text="AO (Weight)")
12
+ row.operator('object.quick_dirty_bake_image', icon='MATSPHERE', text="Pseudo-AO")
13
+ row = col.row(align=True)
14
+ row.operator('object.quick_hemi_bake_image', icon='LAMP_HEMI', text="Hemi Lamp")
15
+ row.operator('object.quick_shadow_bake_image', icon='IMAGE_ALPHA', text="Shadow (Heavy)")
16
+ row.operator('object.quick_side_shadow_bake_image', icon='ARROW_LEFTRIGHT', text="Side Shade")
17
+ row = col.row(align=True)
18
+ row.operator('object.quick_gradation_bake_image', icon='MESH_PLANE', text="Gradation")
19
+ row.operator('object.quick_uv_border_bake_image', icon='MATCAP_24', text="UV Border")
20
+ row.operator('object.quick_mesh_border_bake_image', icon='EDIT_VEC', text="Mesh Edge")
21
+ row = col.row(align=True)
22
+ row.operator('object.quick_density_bake_image', icon='STICKY_UVS_LOC', text="Density")
23
+ row.operator('object.quick_bulge_bake_image', icon='BRUSH_INFLATE', text="Bulge")
24
+ row.operator('object.quick_mesh_distance_bake_image', icon='RETOPO', text="Mesh distance")
25
+ row = col.row(align=True)
26
+ row.operator('object.quick_metal_bake_image', icon='MATCAP_19', text="Metal")
27
+ row.operator('object.quick_hair_bake_image', icon='PARTICLEMODE', text="Hair")
28
+ row.operator('object.quick_semen_bake_image', icon='MOD_FLUIDSIM', text="Semen")
29
+
30
+ class add_bake_image(bpy.types.Operator):
31
+ bl_idname = 'object.add_bake_image'
32
+ bl_label = "Create an image for baking"
33
+ bl_description = "Prepares an empty image for baking in the active object"
34
+ bl_options = {'REGISTER', 'UNDO'}
35
+
36
+ image_name = bpy.props.StringProperty(name="Image Name")
37
+ items = [
38
+ ('128', "128 px", "", 'LAYER_USED', 1),
39
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
40
+ ('512', "512 px", "", 'HAND', 3),
41
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
42
+ ('2048', "2048 px", "", 'ERROR', 5),
43
+ ('4096', "4096 px", "", 'CANCEL', 6),
44
+ ]
45
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
46
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
47
+ image_color = bpy.props.FloatVectorProperty(name="Color", default=(1, 1, 1, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=4)
48
+
49
+ @classmethod
50
+ def poll(cls, context):
51
+ if len(context.selected_objects) != 1:
52
+ return False
53
+ ob = context.active_object
54
+ if ob:
55
+ if ob.type == 'MESH':
56
+ me = ob.data
57
+ if len(me.uv_layers):
58
+ return True
59
+ return False
60
+
61
+ def invoke(self, context, event):
62
+ ob = context.active_object
63
+ self.image_name = ob.name + " Bake"
64
+ return context.window_manager.invoke_props_dialog(self)
65
+
66
+ def draw(self, context):
67
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
68
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
69
+ row = self.layout.row(align=True)
70
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
71
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
72
+ self.layout.prop(self, 'image_color', icon='COLOR')
73
+
74
+ def execute(self, context):
75
+ ob = context.active_object
76
+ me = ob.data
77
+ ob.hide_render = False
78
+
79
+ image_width, image_height = int(self.image_width), int(self.image_height)
80
+
81
+ if self.image_name in context.blend_data.images:
82
+ img = context.blend_data.images[self.image_name]
83
+ else:
84
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
85
+
86
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
87
+ common.set_area_space_attr(area, 'image', img)
88
+
89
+ img.generated_color = self.image_color
90
+
91
+ for elem in me.uv_textures.active.data:
92
+ elem.image = img
93
+
94
+ return {'FINISHED'}
95
+
96
+ class quick_ao_bake_image(bpy.types.Operator):
97
+ bl_idname = 'object.quick_ao_bake_image'
98
+ bl_label = "AO Bake"
99
+ bl_description = "Quickly bake AO to active object"
100
+ bl_options = {'REGISTER', 'UNDO'}
101
+
102
+ image_name = bpy.props.StringProperty(name="Image Name")
103
+ items = [
104
+ ('128', "128 px", "", 'LAYER_USED', 1),
105
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
106
+ ('512', "512 px", "", 'HAND', 3),
107
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
108
+ ('2048', "2048 px", "", 'ERROR', 5),
109
+ ('4096', "4096 px", "", 'CANCEL', 6),
110
+ ]
111
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
112
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
113
+
114
+ items = [
115
+ ('RAYTRACE', "Ray Trace", "", 'BRUSH_TEXFILL', 1),
116
+ ('APPROXIMATE', "Approximate(AAO)", "", 'MATSPHERE', 2),
117
+ ]
118
+ ao_gather_method = bpy.props.EnumProperty(items=items, name="Gather method", default='RAYTRACE')
119
+ ao_samples = bpy.props.IntProperty(name="Accuracy", default=20, min=1, max=50, soft_min=1, soft_max=50)
120
+ ao_hide_other = bpy.props.BoolProperty(name="Hide other objects", default=True)
121
+
122
+ @classmethod
123
+ def poll(cls, context):
124
+ if len(context.selected_objects) != 1:
125
+ return False
126
+ ob = context.active_object
127
+ if ob:
128
+ if ob.type == 'MESH':
129
+ me = ob.data
130
+ if len(me.uv_layers):
131
+ return True
132
+ return False
133
+
134
+ def invoke(self, context, event):
135
+ ob = context.active_object
136
+ self.image_name = ob.name + " AO Bake"
137
+ return context.window_manager.invoke_props_dialog(self)
138
+
139
+ def draw(self, context):
140
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
141
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
142
+ row = self.layout.row(align=True)
143
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
144
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
145
+ self.layout.label(text="AO Setting", icon='BRUSH_TEXFILL')
146
+ self.layout.prop(self, 'ao_gather_method', icon='NODETREE', expand=True)
147
+ self.layout.prop(self, 'ao_samples', icon='ANIM_DATA')
148
+ self.layout.prop(self, 'ao_hide_other', icon='VISIBLE_IPO_OFF')
149
+
150
+ def execute(self, context):
151
+ ob = context.active_object
152
+ me = ob.data
153
+ ob.hide_render = False
154
+
155
+ image_width, image_height = int(self.image_width), int(self.image_height)
156
+
157
+ if self.image_name in context.blend_data.images:
158
+ img = context.blend_data.images[self.image_name]
159
+ else:
160
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
161
+
162
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
163
+ common.set_area_space_attr(area, 'image', img)
164
+
165
+ for elem in me.uv_textures.active.data:
166
+ elem.image = img
167
+
168
+ context.scene.world.light_settings.gather_method = self.ao_gather_method
169
+ context.scene.world.light_settings.samples = self.ao_samples
170
+
171
+ if self.ao_hide_other: hide_render_restore = common.hide_render_restore()
172
+
173
+ context.scene.render.bake_type = 'AO'
174
+ context.scene.render.use_bake_normalize = True
175
+ context.scene.render.use_bake_selected_to_active = False
176
+ bpy.ops.object.bake_image()
177
+
178
+ if self.ao_hide_other: hide_render_restore.restore()
179
+
180
+ return {'FINISHED'}
181
+
182
+ class quick_dirty_bake_image(bpy.types.Operator):
183
+ bl_idname = 'object.quick_dirty_bake_image'
184
+ bl_label = "Pseudo AO bake"
185
+ bl_description = "bake a quick psuedo AO in the active object"
186
+ bl_options = {'REGISTER', 'UNDO'}
187
+
188
+ image_name = bpy.props.StringProperty(name="Image name")
189
+ items = [
190
+ ('128', "128 px", "", 'LAYER_USED', 1),
191
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
192
+ ('512', "512 px", "", 'HAND', 3),
193
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
194
+ ('2048', "2048 px", "", 'ERROR', 5),
195
+ ('4096', "4096 px", "", 'CANCEL', 6),
196
+ ]
197
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
198
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
199
+
200
+ blur_strength = bpy.props.FloatProperty(name="Blur strength", default=1, min=0.01, max=1, soft_min=0.01, soft_max=1, step=10, precision=2)
201
+ blur_iterations = bpy.props.IntProperty(name="Blur iterations", default=1, min=0, max=40, soft_min=0, soft_max=40)
202
+ clean_angle = bpy.props.FloatProperty(name="Highlight angles", default=3.14159, min=0, max=3.14159, soft_min=0, soft_max=3.14159, step=3, precision=0, subtype='ANGLE')
203
+ dirt_angle = bpy.props.FloatProperty(name="Pseudo AO Angle", default=0, min=0, max=3.14159, soft_min=0, soft_max=3.14159, step=3, precision=0, subtype='ANGLE')
204
+ dirt_only = bpy.props.BoolProperty(name="Pseudo AO only", default=True)
205
+
206
+ @classmethod
207
+ def poll(cls, context):
208
+ if len(context.selected_objects) != 1:
209
+ return False
210
+ ob = context.active_object
211
+ if ob:
212
+ if ob.type == 'MESH':
213
+ me = ob.data
214
+ if len(me.uv_layers):
215
+ return True
216
+ return False
217
+
218
+ def invoke(self, context, event):
219
+ ob = context.active_object
220
+ self.image_name = ob.name + " Dirty AO Bake"
221
+ return context.window_manager.invoke_props_dialog(self)
222
+
223
+ def draw(self, context):
224
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
225
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
226
+ row = self.layout.row(align=True)
227
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
228
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
229
+ self.layout.label(text="Pseudo AO Setting", icon='BRUSH_TEXFILL')
230
+ row = self.layout.row(align=True)
231
+ row.prop(self, 'blur_strength', icon='NONE', slider=True)
232
+ row.prop(self, 'blur_iterations', icon='NONE')
233
+ self.layout.prop(self, 'clean_angle', icon='NONE', slider=True)
234
+ row = self.layout.row(align=True)
235
+ row.prop(self, 'dirt_angle', icon='NONE', slider=True)
236
+ row.prop(self, 'dirt_only', icon='FILE_TICK')
237
+
238
+ def execute(self, context):
239
+ ob = context.active_object
240
+ me = ob.data
241
+ ob.select = False
242
+ ob.hide_render = False
243
+
244
+ image_width, image_height = int(self.image_width), int(self.image_height)
245
+
246
+ if self.image_name in context.blend_data.images:
247
+ img = context.blend_data.images[self.image_name]
248
+ else:
249
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
250
+
251
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
252
+ common.set_area_space_attr(area, 'image', img)
253
+ for elem in me.uv_textures.active.data:
254
+ elem.image = img
255
+
256
+ temp_me = ob.to_mesh(scene=context.scene, apply_modifiers=True, settings='PREVIEW')
257
+ temp_ob = context.blend_data.objects.new("quick_dirty_bake_image_temp", temp_me)
258
+ context.scene.objects.link(temp_ob)
259
+ for vc in temp_me.vertex_colors:
260
+ temp_me.vertex_colors.remove(vc)
261
+ temp_vertex_color = temp_me.vertex_colors.new(name="quick_dirty_bake_image_temp")
262
+ context.scene.objects.active = temp_ob
263
+ temp_ob.select = True
264
+
265
+ override = context.copy()
266
+ override['object'] = temp_ob
267
+ bpy.ops.paint.vertex_color_dirt(override, blur_strength=self.blur_strength, blur_iterations=self.blur_iterations, clean_angle=self.clean_angle, dirt_angle=self.dirt_angle, dirt_only=self.dirt_only)
268
+
269
+ temp_ob.update_tag(refresh={'OBJECT', 'DATA'})
270
+ context.scene.render.bake_type = 'VERTEX_COLORS'
271
+ context.scene.render.use_bake_selected_to_active = False
272
+ bpy.ops.object.bake_image(context.copy())
273
+
274
+ common.remove_data([temp_me, temp_ob])
275
+ context.scene.objects.active = ob
276
+ ob.select = True
277
+
278
+ return {'FINISHED'}
279
+
280
+ class quick_hemi_bake_image(bpy.types.Operator):
281
+ bl_idname = 'object.quick_hemi_bake_image'
282
+ bl_label = "Hemi lamp bake"
283
+ bl_description = "Bake the shadow of a hemi lamp"
284
+ bl_options = {'REGISTER', 'UNDO'}
285
+
286
+ image_name = bpy.props.StringProperty(name="Image name")
287
+ items = [
288
+ ('128', "128 px", "", 'LAYER_USED', 1),
289
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
290
+ ('512', "512 px", "", 'HAND', 3),
291
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
292
+ ('2048', "2048 px", "", 'ERROR', 5),
293
+ ('4096', "4096 px", "", 'CANCEL', 6),
294
+ ]
295
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
296
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
297
+
298
+ lamp_energy = bpy.props.FloatProperty(name="Light intensity", default=1, min=0, max=2, soft_min=0, soft_max=2, step=50, precision=2)
299
+
300
+ use_ao = bpy.props.BoolProperty(name="Use the AO", default=False)
301
+ ao_samples = bpy.props.IntProperty(name="Accuracy", default=20, min=1, max=50, soft_min=1, soft_max=50)
302
+ ao_hide_other = bpy.props.BoolProperty(name="Hide other objects", default=True)
303
+
304
+ @classmethod
305
+ def poll(cls, context):
306
+ if len(context.selected_objects) != 1:
307
+ return False
308
+ ob = context.active_object
309
+ if ob:
310
+ if ob.type == 'MESH':
311
+ me = ob.data
312
+ if len(me.uv_layers):
313
+ return True
314
+ return False
315
+
316
+ def invoke(self, context, event):
317
+ ob = context.active_object
318
+ self.image_name = ob.name + " Hemi Bake"
319
+ return context.window_manager.invoke_props_dialog(self)
320
+
321
+ def draw(self, context):
322
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
323
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
324
+ row = self.layout.row(align=True)
325
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
326
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
327
+ self.layout.label(text="Hemi lamp settings", icon='LAMP_HEMI')
328
+ self.layout.prop(self, 'lamp_energy', icon='LAMP_POINT', slider=True)
329
+ self.layout.label(text="AO setting", icon='BRUSH_TEXFILL')
330
+ row = self.layout.row(align=True)
331
+ row.prop(self, 'use_ao', icon='FILE_TICK')
332
+ row.prop(self, 'ao_samples', icon='ANIM_DATA')
333
+ self.layout.prop(self, 'ao_hide_other', icon='VISIBLE_IPO_OFF')
334
+
335
+ def execute(self, context):
336
+ ob = context.active_object
337
+ me = ob.data
338
+ ob.hide_render = False
339
+
340
+ override = context.copy()
341
+ override['object'] = ob
342
+
343
+ image_width, image_height = int(self.image_width), int(self.image_height)
344
+
345
+ if self.image_name in context.blend_data.images:
346
+ img = context.blend_data.images[self.image_name]
347
+ else:
348
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
349
+
350
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
351
+ common.set_area_space_attr(area, 'image', img)
352
+ for elem in me.uv_textures.active.data:
353
+ elem.image = img
354
+
355
+ if self.ao_hide_other: hide_render_restore = common.hide_render_restore()
356
+ material_restore = common.material_restore(ob)
357
+
358
+ bpy.ops.object.material_slot_add(override)
359
+ temp_mate = context.blend_data.materials.new("quick_hemi_bake_image_temp")
360
+ ob.material_slots[0].material = temp_mate
361
+ temp_mate.diffuse_intensity = 1.0
362
+ temp_mate.diffuse_color = (1, 1, 1)
363
+
364
+ temp_lamp = context.blend_data.lamps.new("quick_hemi_bake_image_temp", 'HEMI')
365
+ temp_ob = context.blend_data.objects.new("quick_hemi_bake_image_temp", temp_lamp)
366
+ context.scene.objects.link(temp_ob)
367
+ temp_lamp.energy = self.lamp_energy
368
+
369
+ context.scene.world.light_settings.use_ambient_occlusion = self.use_ao
370
+ if self.use_ao:
371
+ context.scene.world.light_settings.samples = self.ao_samples
372
+ context.scene.world.light_settings.ao_blend_type = 'MULTIPLY'
373
+
374
+ context.scene.render.bake_type = 'FULL'
375
+ context.scene.render.use_bake_selected_to_active = False
376
+ bpy.ops.object.bake_image()
377
+
378
+ common.remove_data([temp_lamp, temp_ob, temp_mate])
379
+
380
+ material_restore.restore()
381
+ if self.ao_hide_other: hide_render_restore.restore()
382
+
383
+ return {'FINISHED'}
384
+
385
+ class quick_shadow_bake_image(bpy.types.Operator):
386
+ bl_idname = 'object.quick_shadow_bake_image'
387
+ bl_label = "Shadow Bake"
388
+ bl_description = "Quickly bake a shadow on the active object"
389
+ bl_options = {'REGISTER', 'UNDO'}
390
+
391
+ image_name = bpy.props.StringProperty(name="Image name")
392
+ items = [
393
+ ('128', "128 px", "", 'LAYER_USED', 1),
394
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
395
+ ('512', "512 px", "", 'HAND', 3),
396
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
397
+ ('2048', "2048 px", "", 'ERROR', 5),
398
+ ('4096', "4096 px", "", 'CANCEL', 6),
399
+ ]
400
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
401
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
402
+
403
+ lamp_max_angle = bpy.props.FloatProperty(name="Lamp max angle", default=0.5236, min=0, max=1.5708, soft_min=0, soft_max=1.5708, step=100, precision=0, subtype='ANGLE', unit='ROTATION')
404
+ lamp_count = bpy.props.IntProperty(name="Number of light sources", default=8, min=1, max=20, soft_min=1, soft_max=20)
405
+ is_shadow_only = bpy.props.BoolProperty(name="Shadow focus", default=False)
406
+
407
+ @classmethod
408
+ def poll(cls, context):
409
+ if not len(context.selected_objects):
410
+ return False
411
+ ob = context.active_object
412
+ if ob:
413
+ if ob.type == 'MESH':
414
+ me = ob.data
415
+ if len(me.uv_layers):
416
+ return True
417
+ return False
418
+
419
+ def invoke(self, context, event):
420
+ self.image_name = context.active_object.name + " Shadow Bake"
421
+ return context.window_manager.invoke_props_dialog(self)
422
+
423
+ def draw(self, context):
424
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
425
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
426
+ row = self.layout.row(align=True)
427
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
428
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
429
+ self.layout.label(text="Light source setting", icon='LAMP_SUN')
430
+ self.layout.prop(self, 'lamp_max_angle', icon='LAMP_AREA', slider=True)
431
+ self.layout.prop(self, 'lamp_count', icon='LAMP_POINT')
432
+ self.layout.prop(self, 'is_shadow_only', icon='IMAGE_ALPHA')
433
+
434
+ def execute(self, context):
435
+ import mathutils
436
+
437
+ ob = context.active_object
438
+ me = ob.data
439
+ ob.hide_render = False
440
+
441
+ override = context.copy()
442
+ override['object'] = ob
443
+
444
+ image_width, image_height = int(self.image_width), int(self.image_height)
445
+
446
+ if self.image_name in context.blend_data.images:
447
+ img = context.blend_data.images[self.image_name]
448
+ else:
449
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
450
+
451
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
452
+ common.set_area_space_attr(area, 'image', img)
453
+ for elem in me.uv_textures.active.data:
454
+ elem.image = img
455
+
456
+ hide_render_restore = common.hide_render_restore()
457
+ material_restore = common.material_restore(ob)
458
+
459
+ bpy.ops.object.material_slot_add(override)
460
+ temp_mate = context.blend_data.materials.new("quick_shadow_bake_image_temp")
461
+ ob.material_slots[0].material = temp_mate
462
+
463
+ if self.is_shadow_only:
464
+ temp_hemi = context.blend_data.lamps.new("quick_hemi_bake_image_lamp_temp", 'HEMI')
465
+ temp_hemi_ob = context.blend_data.objects.new("quick_hemi_bake_image_lamp_temp", temp_hemi)
466
+ context.scene.objects.link(temp_hemi_ob)
467
+ temp_hemi.energy = 0.00001
468
+
469
+ new_lamps = []
470
+ lamp_count = (self.lamp_count * 2) - 1
471
+ angle_interval = self.lamp_max_angle / self.lamp_count
472
+ for x_index in range(lamp_count):
473
+ x_angle = angle_interval * (x_index - self.lamp_count + 1)
474
+
475
+ for y_index in range(lamp_count):
476
+ y_angle = angle_interval * (y_index - self.lamp_count + 1)
477
+
478
+ temp_lamp = context.blend_data.lamps.new("quick_shadow_bake_image_temp", 'SUN')
479
+ temp_lamp.shadow_method = 'RAY_SHADOW'
480
+ temp_lamp_ob = context.blend_data.objects.new("quick_shadow_bake_image_temp", temp_lamp)
481
+ context.scene.objects.link(temp_lamp_ob)
482
+ temp_lamp_ob.rotation_mode = 'XYZ'
483
+ temp_lamp_ob.rotation_euler = mathutils.Euler((x_angle, y_angle, 0), 'XYZ')
484
+
485
+ new_lamps.append(temp_lamp)
486
+ new_lamps.append(temp_lamp_ob)
487
+
488
+ context.scene.render.bake_type = 'SHADOW'
489
+ context.scene.render.use_bake_selected_to_active = False
490
+ bpy.ops.object.bake_image()
491
+
492
+ common.remove_data([temp_mate] + new_lamps)
493
+ if self.is_shadow_only: common.remove_data([temp_hemi_ob, temp_hemi])
494
+
495
+ material_restore.restore()
496
+ hide_render_restore.restore()
497
+
498
+ return {'FINISHED'}
499
+
500
+ class quick_side_shadow_bake_image(bpy.types.Operator):
501
+ bl_idname = 'object.quick_side_shadow_bake_image'
502
+ bl_label = "Side shadow bake"
503
+ bl_description = "A quick side shadow is baked on the active object"
504
+ bl_options = {'REGISTER', 'UNDO'}
505
+
506
+ image_name = bpy.props.StringProperty(name="Image name")
507
+ items = [
508
+ ('128', "128 px", "", 'LAYER_USED', 1),
509
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
510
+ ('512', "512 px", "", 'HAND', 3),
511
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
512
+ ('2048', "2048 px", "", 'ERROR', 5),
513
+ ('4096', "4096 px", "", 'CANCEL', 6),
514
+ ]
515
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
516
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
517
+
518
+ is_bipolarization = bpy.props.BoolProperty(name="Enable polarization", default=True)
519
+ bipolarization_threshold = bpy.props.FloatProperty(name="Threshold of polarization", default=0.5, min=0, max=1, soft_min=0, soft_max=1, step=5, precision=2)
520
+ bipolarization_blur = bpy.props.FloatProperty(name="Blur of polarization", default=0.05, min=0, max=1, soft_min=0, soft_max=1, step=1, precision=2)
521
+
522
+ @classmethod
523
+ def poll(cls, context):
524
+ if len(context.selected_objects) != 1:
525
+ return False
526
+ ob = context.active_object
527
+ if ob:
528
+ if ob.type == 'MESH':
529
+ me = ob.data
530
+ if len(me.uv_layers):
531
+ return True
532
+ return False
533
+
534
+ def invoke(self, context, event):
535
+ self.image_name = context.active_object.name + " SideShade Bake"
536
+ return context.window_manager.invoke_props_dialog(self)
537
+
538
+ def draw(self, context):
539
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
540
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
541
+ row = self.layout.row(align=True)
542
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
543
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
544
+ self.layout.separator()
545
+ self.layout.prop(self, 'is_bipolarization', icon='IMAGE_ALPHA')
546
+ row = self.layout.row(align=True)
547
+ row.prop(self, 'bipolarization_threshold', icon='NONE', text="Threshold")
548
+ row.prop(self, 'bipolarization_blur', icon='NONE', text="Blur")
549
+
550
+ def execute(self, context):
551
+ ob = context.active_object
552
+ me = ob.data
553
+ ob.hide_render = False
554
+
555
+ override = context.copy()
556
+ override['object'] = ob
557
+
558
+ image_width, image_height = int(self.image_width), int(self.image_height)
559
+
560
+ if self.image_name in context.blend_data.images:
561
+ img = context.blend_data.images[self.image_name]
562
+ else:
563
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True, float_buffer=True)
564
+
565
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
566
+ common.set_area_space_attr(area, 'image', img)
567
+ for elem in me.uv_textures.active.data:
568
+ elem.image = img
569
+
570
+ material_restore = common.material_restore(ob)
571
+
572
+ blend_path = os.path.join(os.path.dirname(__file__), "append_data.blend")
573
+ with context.blend_data.libraries.load(blend_path) as (data_from, data_to):
574
+ data_to.materials = ["Side Shadow"]
575
+
576
+ bpy.ops.object.material_slot_add(override)
577
+ temp_mate = data_to.materials[0]
578
+ ob.material_slots[0].material = temp_mate
579
+
580
+ temp_lamp = context.blend_data.lamps.new("quick_side_shadow_bake_image_lamp_temp", 'HEMI')
581
+ temp_lamp_ob = context.blend_data.objects.new("quick_side_shadow_bake_image_lamp_temp", temp_lamp)
582
+ context.scene.objects.link(temp_lamp_ob)
583
+
584
+ pre_scene_camera = context.scene.camera
585
+ temp_camera = context.blend_data.cameras.new("quick_side_shadow_bake_image_camera_temp")
586
+ temp_camera_ob = context.blend_data.objects.new("quick_side_shadow_bake_image_camera_temp", temp_camera)
587
+ context.scene.objects.link(temp_camera_ob)
588
+ temp_camera_ob.rotation_euler[0] = 1.5708
589
+ context.scene.camera = temp_camera_ob
590
+
591
+ context.scene.world.light_settings.use_ambient_occlusion = False
592
+
593
+ context.scene.render.bake_type = 'FULL'
594
+ context.scene.render.use_bake_selected_to_active = False
595
+ bpy.ops.object.bake_image()
596
+
597
+ common.remove_data([temp_mate, temp_lamp_ob, temp_lamp, temp_camera_ob, temp_camera])
598
+ context.scene.camera = pre_scene_camera
599
+
600
+ material_restore.restore()
601
+
602
+ if self.is_bipolarization:
603
+ img_w, img_h, img_c = img.size[0], img.size[1], img.channels
604
+ pixels = numpy.array(img.pixels).reshape(img_h, img_w, img_c)
605
+ min = self.bipolarization_threshold - (self.bipolarization_blur / 2.0)
606
+ max = self.bipolarization_threshold + (self.bipolarization_blur / 2.0)
607
+ i = numpy.where(pixels[:,:,:3] <= min)
608
+ pixels[:,:,:3][i] = 0.0
609
+ i = numpy.where(max <= pixels[:,:,:3])
610
+ pixels[:,:,:3][i] = 1.0
611
+ if 0.0 < max - min:
612
+ i = numpy.where((min < pixels[:,:,:3]) & (pixels[:,:,:3] < max))
613
+ pixels[:,:,:3][i] -= min
614
+ pixels[:,:,:3][i] *= 1.0 / (max - min)
615
+ img.pixels = pixels.flatten()
616
+
617
+ return {'FINISHED'}
618
+
619
+ class quick_gradation_bake_image(bpy.types.Operator):
620
+ bl_idname = 'object.quick_gradation_bake_image'
621
+ bl_label = "Gradient bake"
622
+ bl_description = "Quickly bakes a gradient to the active object"
623
+ bl_options = {'REGISTER', 'UNDO'}
624
+
625
+ image_name = bpy.props.StringProperty(name="Image Name")
626
+ items = [
627
+ ('128', "128 px", "", 'LAYER_USED', 1),
628
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
629
+ ('512', "512 px", "", 'HAND', 3),
630
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
631
+ ('2048', "2048 px", "", 'ERROR', 5),
632
+ ('4096', "4096 px", "", 'CANCEL', 6),
633
+ ]
634
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
635
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
636
+
637
+ @classmethod
638
+ def poll(cls, context):
639
+ if len(context.selected_objects) != 1:
640
+ return False
641
+ ob = context.active_object
642
+ if ob:
643
+ if ob.type == 'MESH':
644
+ me = ob.data
645
+ if len(me.uv_layers):
646
+ return True
647
+ return False
648
+
649
+ def invoke(self, context, event):
650
+ self.image_name = context.active_object.name + " Gradation Bake"
651
+ return context.window_manager.invoke_props_dialog(self)
652
+
653
+ def draw(self, context):
654
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
655
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
656
+ row = self.layout.row(align=True)
657
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
658
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
659
+
660
+ def execute(self, context):
661
+ ob = context.active_object
662
+ me = ob.data
663
+ ob.hide_render = False
664
+
665
+ override = context.copy()
666
+ override['object'] = ob
667
+
668
+ image_width, image_height = int(self.image_width), int(self.image_height)
669
+
670
+ if self.image_name in context.blend_data.images:
671
+ img = context.blend_data.images[self.image_name]
672
+ else:
673
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
674
+
675
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
676
+ common.set_area_space_attr(area, 'image', img)
677
+ for elem in me.uv_textures.active.data:
678
+ elem.image = img
679
+
680
+ temp_me = ob.to_mesh(scene=context.scene, apply_modifiers=True, settings='PREVIEW')
681
+ zs = [(ob.matrix_world * v.co).z for v in temp_me.vertices]
682
+ zs.sort()
683
+ me_conter = (zs[0] + zs[-1]) / 2
684
+ me_height = zs[-1] - zs[0]
685
+
686
+ material_restore = common.material_restore(ob)
687
+
688
+ bpy.ops.object.material_slot_add(override)
689
+ temp_mate = context.blend_data.materials.new("quick_gradation_bake_image_temp")
690
+ ob.material_slots[0].material = temp_mate
691
+ temp_slot = temp_mate.texture_slots.create(0)
692
+ temp_tex = context.blend_data.textures.new("quick_gradation_bake_image_temp", 'BLEND')
693
+ temp_slot.texture = temp_tex
694
+ temp_tex.use_color_ramp = True
695
+ temp_slot.mapping_y = 'Z'
696
+ temp_slot.mapping_z = 'Y'
697
+ temp_slot.texture_coords = 'GLOBAL'
698
+ temp_tex.color_ramp.elements[0].color = (0, 0, 0, 1)
699
+ temp_tex.use_flip_axis = 'VERTICAL'
700
+ temp_slot.offset[1] = -me_conter
701
+ temp_slot.scale[1] = 1 / (me_height / 2)
702
+
703
+ context.scene.render.bake_type = 'TEXTURE'
704
+ context.scene.render.use_bake_selected_to_active = False
705
+ bpy.ops.object.bake_image()
706
+
707
+ common.remove_data([temp_me, temp_mate, temp_tex])
708
+
709
+ material_restore.restore()
710
+
711
+ return {'FINISHED'}
712
+
713
+ class quick_metal_bake_image(bpy.types.Operator):
714
+ bl_idname = 'object.quick_metal_bake_image'
715
+ bl_label = "Metal Bake"
716
+ bl_description = "Quickly bake metal object"
717
+ bl_options = {'REGISTER', 'UNDO'}
718
+
719
+ image_name = bpy.props.StringProperty(name="Image Name")
720
+ items = [
721
+ ('128', "128 px", "", 'LAYER_USED', 1),
722
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
723
+ ('512', "512 px", "", 'HAND', 3),
724
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
725
+ ('2048', "2048 px", "", 'ERROR', 5),
726
+ ('4096', "4096 px", "", 'CANCEL', 6),
727
+ ]
728
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
729
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
730
+
731
+ mate_color = bpy.props.FloatVectorProperty(name="Color", default=(0.22, 0.22, 0.22), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR')
732
+ environment_strength = bpy.props.FloatProperty(name="Strength Reflection", default=1, min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2)
733
+ highlight_strength = bpy.props.FloatProperty(name="Highlights strength", default=0.5, min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2)
734
+
735
+ @classmethod
736
+ def poll(cls, context):
737
+ if len(context.selected_objects) != 1:
738
+ return False
739
+ ob = context.active_object
740
+ if ob:
741
+ if ob.type == 'MESH':
742
+ me = ob.data
743
+ if len(me.uv_layers):
744
+ return True
745
+ return False
746
+
747
+ def invoke(self, context, event):
748
+ self.image_name = context.active_object.name + " Metal Bake"
749
+ return context.window_manager.invoke_props_dialog(self)
750
+
751
+ def draw(self, context):
752
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
753
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
754
+ row = self.layout.row(align=True)
755
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
756
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
757
+ self.layout.label(text="Metal set", icon='MATCAP_19')
758
+ self.layout.prop(self, 'mate_color', icon='COLOR')
759
+ row = self.layout.row(align=True)
760
+ row.prop(self, 'environment_strength', icon='MATCAP_19', slider=True)
761
+ row.prop(self, 'highlight_strength', icon='MATCAP_09', slider=True)
762
+
763
+ def execute(self, context):
764
+ ob = context.active_object
765
+ me = ob.data
766
+ ob.hide_render = False
767
+
768
+ override = context.copy()
769
+ override['object'] = ob
770
+
771
+ image_width, image_height = int(self.image_width), int(self.image_height)
772
+
773
+ if self.image_name in context.blend_data.images:
774
+ img = context.blend_data.images[self.image_name]
775
+ else:
776
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
777
+
778
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
779
+ common.set_area_space_attr(area, 'image', img)
780
+ for elem in me.uv_textures.active.data:
781
+ elem.image = img
782
+
783
+ hide_render_restore = common.hide_render_restore()
784
+ material_restore = common.material_restore(ob)
785
+
786
+ blend_path = os.path.join(os.path.dirname(__file__), "append_data.blend")
787
+ with context.blend_data.libraries.load(blend_path) as (data_from, data_to):
788
+ data_to.materials = ["Metal"]
789
+
790
+ bpy.ops.object.material_slot_add(override)
791
+ temp_mate = data_to.materials[0]
792
+ ob.material_slots[0].material = temp_mate
793
+ temp_mate.diffuse_color = self.mate_color[:]
794
+ temp_mate.texture_slots[0].diffuse_color_factor = self.environment_strength
795
+ temp_mate.node_tree.nodes["Mix.001"].inputs[0].default_value = 1.0 - self.highlight_strength
796
+
797
+ temp_lamp = context.blend_data.lamps.new("quick_metal_bake_image_lamp_temp", 'HEMI')
798
+ temp_lamp_ob = context.blend_data.objects.new("quick_metal_bake_image_lamp_temp", temp_lamp)
799
+ context.scene.objects.link(temp_lamp_ob)
800
+ #temp_lamp.energy = self.lamp_energy
801
+
802
+ pre_scene_camera = context.scene.camera
803
+ temp_camera = context.blend_data.cameras.new("quick_metal_bake_image_camera_temp")
804
+ temp_camera_ob = context.blend_data.objects.new("quick_metal_bake_image_camera_temp", temp_camera)
805
+ context.scene.objects.link(temp_camera_ob)
806
+ temp_camera_ob.rotation_euler[0] = 1.5708
807
+ context.scene.camera = temp_camera_ob
808
+
809
+ context.scene.world.light_settings.use_ambient_occlusion = False
810
+
811
+ context.scene.render.bake_type = 'FULL'
812
+ context.scene.render.use_bake_selected_to_active = False
813
+ bpy.ops.object.bake_image()
814
+
815
+ common.remove_data([temp_mate, temp_lamp_ob, temp_lamp, temp_camera_ob, temp_camera])
816
+ context.scene.camera = pre_scene_camera
817
+
818
+ material_restore.restore()
819
+ hide_render_restore.restore()
820
+
821
+ return {'FINISHED'}
822
+
823
+ class quick_hair_bake_image(bpy.types.Operator):
824
+ bl_idname = 'object.quick_hair_bake_image'
825
+ bl_label = "Hair"
826
+ bl_description = "Bake the hairstyle quickly"
827
+ bl_options = {'REGISTER', 'UNDO'}
828
+
829
+ image_name = bpy.props.StringProperty(name="Image Name")
830
+ items = [
831
+ ('128', "128 px", "", 'LAYER_USED', 1),
832
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
833
+ ('512', "512 px", "", 'HAND', 3),
834
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
835
+ ('2048', "2048 px", "", 'ERROR', 5),
836
+ ('4096', "4096 px", "", 'CANCEL', 6),
837
+ ]
838
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
839
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
840
+
841
+ mate_diffuse_color = bpy.props.FloatVectorProperty(name="Hair color", default=(1, 1, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=3)
842
+ mate_angel_ring_factor = bpy.props.FloatProperty(name="Ring factor", default=0.5, min=0, max=1, soft_min=0, soft_max=1, step=50, precision=2)
843
+
844
+ lamp_energy = bpy.props.FloatProperty(name="Light Intensity", default=1, min=0, max=2, soft_min=0, soft_max=2, step=50, precision=2)
845
+
846
+ use_ao = bpy.props.BoolProperty(name="Use the AO", default=False)
847
+ ao_samples = bpy.props.IntProperty(name="Accuracy", default=20, min=1, max=50, soft_min=1, soft_max=50)
848
+ ao_hide_other = bpy.props.BoolProperty(name="Hide other Objects", default=True)
849
+
850
+ @classmethod
851
+ def poll(cls, context):
852
+ if len(context.selected_objects) != 1:
853
+ return False
854
+ ob = context.active_object
855
+ if ob:
856
+ if ob.type == 'MESH':
857
+ me = ob.data
858
+ if len(me.uv_layers):
859
+ return True
860
+ return False
861
+
862
+ def invoke(self, context, event):
863
+ ob = context.active_object
864
+ self.image_name = ob.name + " Hair Bake"
865
+ return context.window_manager.invoke_props_dialog(self)
866
+
867
+ def draw(self, context):
868
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
869
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
870
+ row = self.layout.row(align=True)
871
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
872
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
873
+ self.layout.label(text="Hair set", icon='PARTICLEMODE')
874
+ self.layout.prop(self, 'mate_diffuse_color', icon='COLOR')
875
+ self.layout.prop(self, 'mate_angel_ring_factor', icon='MATCAP_09', slider=True)
876
+ self.layout.label(text="Hemi Lamp Settings", icon='LAMP_HEMI')
877
+ self.layout.prop(self, 'lamp_energy', icon='LAMP_POINT', slider=True)
878
+ self.layout.label(text="AO Setting", icon='BRUSH_TEXFILL')
879
+ row = self.layout.row(align=True)
880
+ row.prop(self, 'use_ao', icon='FILE_TICK')
881
+ row.prop(self, 'ao_samples', icon='ANIM_DATA')
882
+ self.layout.prop(self, 'ao_hide_other', icon='VISIBLE_IPO_OFF')
883
+
884
+ def execute(self, context):
885
+ import os.path
886
+
887
+ ob = context.active_object
888
+ me = ob.data
889
+ ob.hide_render = False
890
+
891
+ override = context.copy()
892
+ override['object'] = ob
893
+
894
+ image_width, image_height = int(self.image_width), int(self.image_height)
895
+
896
+ if self.image_name in context.blend_data.images:
897
+ img = context.blend_data.images[self.image_name]
898
+ else:
899
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
900
+
901
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
902
+ common.set_area_space_attr(area, 'image', img)
903
+
904
+ for elem in me.uv_textures.active.data:
905
+ elem.image = img
906
+
907
+ if self.ao_hide_other: hide_render_restore = common.hide_render_restore()
908
+ material_restore = common.material_restore(ob)
909
+
910
+ temp_lamp = context.blend_data.lamps.new("quick_hemi_bake_image_lamp_temp", 'HEMI')
911
+ temp_lamp_ob = context.blend_data.objects.new("quick_hemi_bake_image_lamp_temp", temp_lamp)
912
+ context.scene.objects.link(temp_lamp_ob)
913
+ temp_lamp.energy = self.lamp_energy
914
+
915
+ pre_scene_camera = context.scene.camera
916
+ temp_camera = context.blend_data.cameras.new("quick_hemi_bake_image_camera_temp")
917
+ temp_camera_ob = context.blend_data.objects.new("quick_hemi_bake_image_camera_temp", temp_camera)
918
+ context.scene.objects.link(temp_camera_ob)
919
+ temp_camera_ob.rotation_euler[0] = 1.5708
920
+ context.scene.camera = temp_camera_ob
921
+
922
+
923
+ blend_path = os.path.join(os.path.dirname(__file__), "append_data.blend")
924
+ with context.blend_data.libraries.load(blend_path) as (data_from, data_to):
925
+ data_to.materials = ["CM3D2 Hair"]
926
+
927
+ bpy.ops.object.material_slot_add(override)
928
+ temp_mate = data_to.materials[0]
929
+ ob.material_slots[0].material = temp_mate
930
+
931
+ temp_mate.diffuse_color = self.mate_diffuse_color
932
+ temp_mate.node_tree.nodes["mate_angel_ring_factor"].inputs[0].default_value = self.mate_angel_ring_factor
933
+
934
+ context.scene.world.light_settings.use_ambient_occlusion = self.use_ao
935
+ if self.use_ao:
936
+ context.scene.world.light_settings.samples = self.ao_samples
937
+ context.scene.world.light_settings.ao_blend_type = 'MULTIPLY'
938
+
939
+ context.scene.render.bake_type = 'FULL'
940
+ context.scene.render.use_bake_selected_to_active = False
941
+ bpy.ops.object.bake_image()
942
+
943
+ temp_tex = temp_mate.texture_slots[0].texture
944
+
945
+ common.remove_data([temp_mate, temp_tex, temp_camera_ob, temp_camera, temp_lamp_ob, temp_lamp])
946
+ context.scene.camera = pre_scene_camera
947
+
948
+ material_restore.restore()
949
+ if self.ao_hide_other: hide_render_restore.restore()
950
+
951
+ return {'FINISHED'}
952
+
953
+ class quick_uv_border_bake_image(bpy.types.Operator):
954
+ bl_idname = 'object.quick_uv_border_bake_image'
955
+ bl_label = "UV Edge Bake"
956
+ bl_description = "Quickly bake the edge of the UV"
957
+ bl_options = {'REGISTER', 'UNDO'}
958
+
959
+ image_name = bpy.props.StringProperty(name="Image Name")
960
+ items = [
961
+ ('128', "128 px", "", 'LAYER_USED', 1),
962
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
963
+ ('512', "512 px", "", 'HAND', 3),
964
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
965
+ ('2048', "2048 px", "", 'ERROR', 5),
966
+ ('4096', "4096 px", "", 'CANCEL', 6),
967
+ ]
968
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
969
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
970
+
971
+ items = [
972
+ ('FLAT', "Flat", "", 'IPO_CONSTANT', 1),
973
+ ('TENT', "Tent", "", 'IPO_LINEAR', 2),
974
+ ('QUAD', "Quad", "", 'IPO_QUAD', 3),
975
+ ('CUBIC', "Cubic", "", 'IPO_CUBIC', 4),
976
+ ('GAUSS', "Gauss", "", 'HAND', 5),
977
+ ('FAST_GAUSS', "Fast gauss", "", 'ALIASED', 6),
978
+ ('CATROM', "Catrom", "", 'FILE_TICK', 7),
979
+ ('MITCH', "Mitch", "", 'FILE_TICK', 8),
980
+ ]
981
+ blur_type = bpy.props.EnumProperty(items=items, name="Blur type", default='GAUSS')
982
+ blur_strength = bpy.props.IntProperty(name="Blur strength", default=100, min=0, max=1000, soft_min=0, soft_max=1000)
983
+ normalize = bpy.props.BoolProperty(name="Normalize", default=True)
984
+ keep_alpha = bpy.props.BoolProperty(name="Keep alpha", default=True)
985
+
986
+ @classmethod
987
+ def poll(cls, context):
988
+ if len(context.selected_objects) != 1:
989
+ return False
990
+ ob = context.active_object
991
+ if ob:
992
+ if ob.type == 'MESH':
993
+ me = ob.data
994
+ if len(me.uv_layers):
995
+ return True
996
+ return False
997
+
998
+ def invoke(self, context, event):
999
+ ob = context.active_object
1000
+ self.image_name = ob.name + " UV Border Bake"
1001
+ return context.window_manager.invoke_props_dialog(self)
1002
+
1003
+ def draw(self, context):
1004
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
1005
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
1006
+ row = self.layout.row(align=True)
1007
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
1008
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
1009
+ self.layout.label(text="Edge Setting", icon='MATCAP_24')
1010
+ self.layout.prop(self, 'blur_type', icon='BRUSH_BLUR')
1011
+ self.layout.prop(self, 'blur_strength', icon='ARROW_LEFTRIGHT')
1012
+ row = self.layout.row(align=True)
1013
+ row.prop(self, 'normalize', icon='IMAGE_ALPHA')
1014
+ row.prop(self, 'keep_alpha', icon='IMAGE_RGB_ALPHA')
1015
+
1016
+ def execute(self, context):
1017
+ ob = context.active_object
1018
+ me = ob.data
1019
+ ob.hide_render = False
1020
+
1021
+ override = context.copy()
1022
+ override['object'] = ob
1023
+
1024
+ image_width, image_height = int(self.image_width), int(self.image_height)
1025
+
1026
+ if self.image_name in context.blend_data.images:
1027
+ img = context.blend_data.images[self.image_name]
1028
+ else:
1029
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
1030
+
1031
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
1032
+
1033
+ img.generated_color = (0, 0, 0, 1)
1034
+
1035
+ for elem in me.uv_textures.active.data:
1036
+ elem.image = img
1037
+
1038
+ material_restore = common.material_restore(ob)
1039
+
1040
+ bpy.ops.object.material_slot_add(override)
1041
+ temp_mate = context.blend_data.materials.new("quick_gradation_bake_image_temp")
1042
+ ob.material_slots[0].material = temp_mate
1043
+ temp_mate.diffuse_color = (1, 1, 1)
1044
+
1045
+ pre_use_bake_clear = context.scene.render.use_bake_clear
1046
+ pre_bake_margin = context.scene.render.bake_margin
1047
+ context.scene.render.use_bake_clear = False
1048
+ context.scene.render.bake_type = 'TEXTURE'
1049
+ context.scene.render.use_bake_selected_to_active = False
1050
+
1051
+ bpy.ops.object.bake_image()
1052
+ img_w, img_h, img_c = img.size[0], img.size[1], img.channels
1053
+ pixels = numpy.array(img.pixels).reshape(img_h, img_w, img_c)
1054
+ img_alphas = pixels[:,:,0]
1055
+
1056
+ img.reload()
1057
+ context.scene.render.bake_margin = 0
1058
+ bpy.ops.object.bake_image()
1059
+
1060
+ context.scene.render.use_bake_clear = pre_use_bake_clear
1061
+ context.scene.render.bake_margin = pre_bake_margin
1062
+
1063
+ # 無駄に壮大なぼかし処理
1064
+ pre_resolution_x = context.scene.render.resolution_x
1065
+ pre_resolution_y = context.scene.render.resolution_y
1066
+ pre_resolution_percentage = context.scene.render.resolution_percentage
1067
+ context.scene.render.resolution_x = img.size[0]
1068
+ context.scene.render.resolution_y = img.size[1]
1069
+ context.scene.render.resolution_percentage = 100
1070
+
1071
+ context.scene.use_nodes = True
1072
+ node_tree = context.scene.node_tree
1073
+ for node in node_tree.nodes:
1074
+ node_tree.nodes.remove(node)
1075
+
1076
+ img_node = node_tree.nodes.new('CompositorNodeImage')
1077
+ img_node.location = (0, 0)
1078
+ img_node.image = img
1079
+
1080
+ blur_node = node_tree.nodes.new('CompositorNodeBlur')
1081
+ blur_node.location = (250, 0)
1082
+ blur_node.size_x, blur_node.size_y = 1, 1
1083
+ blur_node.filter_type = self.blur_type
1084
+ blur_node.inputs[1].default_value = self.blur_strength
1085
+
1086
+ out_node = node_tree.nodes.new('CompositorNodeComposite')
1087
+ out_node.location = (500, 0)
1088
+
1089
+ node_tree.links.new(blur_node.inputs[0], img_node.outputs[0])
1090
+ node_tree.links.new(out_node.inputs[0], blur_node.outputs[0])
1091
+
1092
+ bpy.ops.render.render()
1093
+
1094
+ render_img = context.blend_data.images["Render Result"]
1095
+
1096
+ temp_png_path = os.path.join(bpy.app.tempdir, "temp.png")
1097
+ img_override = context.copy()
1098
+ img_override['object'] = render_img
1099
+ img_override['edit_image'] = render_img
1100
+ img_override['area'] = area
1101
+ common.set_area_space_attr(area, 'image', render_img)
1102
+ bpy.ops.image.save_as(img_override, save_as_render=True, copy=True, filepath=temp_png_path, relative_path=False, show_multiview=False, use_multiview=False)
1103
+ img.source = 'FILE'
1104
+ img.filepath = temp_png_path
1105
+ img.reload()
1106
+ pixels = numpy.array(img.pixels).reshape(img_h, img_w, img_c)
1107
+ if self.keep_alpha:
1108
+ pixels[:,:,3] = img_alphas
1109
+ if self.normalize:
1110
+ pixels[:,:,:3] -= 0.5
1111
+ pixels[:,:,:3] *= 2.0
1112
+ img.pixels = pixels.flatten()
1113
+ img.pack(as_png=True)
1114
+ os.remove(temp_png_path)
1115
+
1116
+ for node in node_tree.nodes:
1117
+ node_tree.nodes.remove(node)
1118
+ context.scene.use_nodes = False
1119
+ context.scene.render.resolution_x = pre_resolution_x
1120
+ context.scene.render.resolution_y = pre_resolution_y
1121
+ context.scene.render.resolution_percentage = pre_resolution_percentage
1122
+ # 無駄に壮大なぼかし処理 完
1123
+
1124
+ common.set_area_space_attr(area, 'image', img)
1125
+ common.remove_data([temp_mate])
1126
+ material_restore.restore()
1127
+
1128
+ return {'FINISHED'}
1129
+
1130
+ class quick_mesh_border_bake_image(bpy.types.Operator):
1131
+ bl_idname = 'object.quick_mesh_border_bake_image'
1132
+ bl_label = "Mesh edge bake"
1133
+ bl_description = "bake the edge of the mesh to the object"
1134
+ bl_options = {'REGISTER', 'UNDO'}
1135
+
1136
+ image_name = bpy.props.StringProperty(name="Image Name")
1137
+ items = [
1138
+ ('128', "128 px", "", 'LAYER_USED', 1),
1139
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
1140
+ ('512', "512 px", "", 'HAND', 3),
1141
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
1142
+ ('2048', "2048 px", "", 'ERROR', 5),
1143
+ ('4096', "4096 px", "", 'CANCEL', 6),
1144
+ ]
1145
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
1146
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
1147
+
1148
+ range = bpy.props.IntProperty(name="Range", default=5, min=1, max=50, soft_min=1, soft_max=50)
1149
+
1150
+ @classmethod
1151
+ def poll(cls, context):
1152
+ if len(context.selected_objects) != 1:
1153
+ return False
1154
+ ob = context.active_object
1155
+ if ob:
1156
+ if ob.type == 'MESH':
1157
+ me = ob.data
1158
+ if len(me.uv_layers):
1159
+ return True
1160
+ return False
1161
+
1162
+ def invoke(self, context, event):
1163
+ ob = context.active_object
1164
+ self.image_name = ob.name + " Mesh Border Bake"
1165
+ return context.window_manager.invoke_props_dialog(self)
1166
+
1167
+ def draw(self, context):
1168
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
1169
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
1170
+ row = self.layout.row(align=True)
1171
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
1172
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
1173
+
1174
+ self.layout.prop(self, 'range', icon='PROP_ON')
1175
+
1176
+ def execute(self, context):
1177
+ ob = context.active_object
1178
+ me = ob.data
1179
+ ob.select = False
1180
+ ob.hide_render = False
1181
+
1182
+ image_width, image_height = int(self.image_width), int(self.image_height)
1183
+
1184
+ if self.image_name in context.blend_data.images:
1185
+ img = context.blend_data.images[self.image_name]
1186
+ else:
1187
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
1188
+
1189
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
1190
+ common.set_area_space_attr(area, 'image', img)
1191
+ for elem in me.uv_textures.active.data:
1192
+ elem.image = img
1193
+
1194
+ temp_me = ob.to_mesh(scene=context.scene, apply_modifiers=True, settings='PREVIEW')
1195
+ temp_ob = context.blend_data.objects.new("quick_density_bake_image", temp_me)
1196
+ context.scene.objects.link(temp_ob)
1197
+ for vc in temp_me.vertex_colors:
1198
+ temp_me.vertex_colors.remove(vc)
1199
+ temp_vertex_color = temp_me.vertex_colors.new(name="quick_density_bake_image")
1200
+ context.scene.objects.active = temp_ob
1201
+ temp_ob.select = True
1202
+
1203
+ def paint_selected_vertices(me, color, except_indices=[]):
1204
+ paint_vertices = []
1205
+ for vert in me.vertices:
1206
+ if vert.select and vert.index not in except_indices:
1207
+ paint_vertices.append(vert.index)
1208
+ for loop in me.loops:
1209
+ if loop.vertex_index in paint_vertices:
1210
+ me.vertex_colors.active.data[loop.index].color = color
1211
+ return paint_vertices
1212
+
1213
+ context.tool_settings.mesh_select_mode = (True, False, False)
1214
+ already_vert_indices = []
1215
+ for index in range(self.range):
1216
+ bpy.ops.object.mode_set(mode='EDIT')
1217
+ if index == 0:
1218
+ bpy.ops.mesh.reveal()
1219
+ bpy.ops.mesh.select_all(action='DESELECT')
1220
+ bpy.ops.mesh.select_non_manifold()
1221
+ else:
1222
+ bpy.ops.mesh.select_more()
1223
+ bpy.ops.object.mode_set(mode='OBJECT')
1224
+
1225
+ value = (1.0 / self.range) * index
1226
+ already_vert_indices += paint_selected_vertices(temp_me, [value, value, value], already_vert_indices)
1227
+
1228
+ bpy.ops.object.mode_set(mode='EDIT')
1229
+ bpy.ops.mesh.select_all(action='DESELECT')
1230
+ bpy.ops.object.mode_set(mode='OBJECT')
1231
+
1232
+ context.scene.render.bake_type = 'VERTEX_COLORS'
1233
+ context.scene.render.use_bake_selected_to_active = False
1234
+ bpy.ops.object.bake_image()
1235
+
1236
+ common.remove_data([temp_me, temp_ob])
1237
+ context.scene.objects.active = ob
1238
+ ob.select = True
1239
+
1240
+ return {'FINISHED'}
1241
+
1242
+ class quick_density_bake_image(bpy.types.Operator):
1243
+ bl_idname = 'object.quick_density_bake_image'
1244
+ bl_label = "Density bake"
1245
+ bl_description = "Bakes density in to the active object"
1246
+ bl_options = {'REGISTER', 'UNDO'}
1247
+
1248
+ image_name = bpy.props.StringProperty(name="Image Name")
1249
+ items = [
1250
+ ('128', "128 px", "", 'LAYER_USED', 1),
1251
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
1252
+ ('512', "512 px", "", 'HAND', 3),
1253
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
1254
+ ('2048', "2048 px", "", 'ERROR', 5),
1255
+ ('4096', "4096 px", "", 'CANCEL', 6),
1256
+ ]
1257
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
1258
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
1259
+
1260
+ items = [
1261
+ ('ALL', "All", "", 'MOD_SUBSURF', 1),
1262
+ ('PARTS', "Each Part", "", 'GROUP_VCOL', 2),
1263
+ ]
1264
+ mode = bpy.props.EnumProperty(items=items, name="Comparison", default='PARTS')
1265
+
1266
+ @classmethod
1267
+ def poll(cls, context):
1268
+ if len(context.selected_objects) != 1:
1269
+ return False
1270
+ ob = context.active_object
1271
+ if ob:
1272
+ if ob.type == 'MESH':
1273
+ me = ob.data
1274
+ if len(me.uv_layers):
1275
+ return True
1276
+ return False
1277
+
1278
+ def invoke(self, context, event):
1279
+ ob = context.active_object
1280
+ self.image_name = ob.name + " Density Bake"
1281
+ return context.window_manager.invoke_props_dialog(self)
1282
+
1283
+ def draw(self, context):
1284
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
1285
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
1286
+ row = self.layout.row(align=True)
1287
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
1288
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
1289
+ self.layout.label(text="Comparision", icon='ZOOM_PREVIOUS')
1290
+ self.layout.prop(self, 'mode', icon='ZOOM_PREVIOUS', expand=True)
1291
+
1292
+ def execute(self, context):
1293
+ ob = context.active_object
1294
+ me = ob.data
1295
+ ob.select = False
1296
+ ob.hide_render = False
1297
+
1298
+ image_width, image_height = int(self.image_width), int(self.image_height)
1299
+
1300
+ if self.image_name in context.blend_data.images:
1301
+ img = context.blend_data.images[self.image_name]
1302
+ else:
1303
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
1304
+
1305
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
1306
+ common.set_area_space_attr(area, 'image', img)
1307
+ for elem in me.uv_textures.active.data:
1308
+ elem.image = img
1309
+
1310
+ temp_me = ob.to_mesh(scene=context.scene, apply_modifiers=True, settings='PREVIEW')
1311
+ temp_ob = context.blend_data.objects.new("quick_density_bake_image", temp_me)
1312
+ context.scene.objects.link(temp_ob)
1313
+ for vc in temp_me.vertex_colors:
1314
+ temp_me.vertex_colors.remove(vc)
1315
+ temp_vertex_color = temp_me.vertex_colors.new(name="quick_density_bake_image")
1316
+ context.scene.objects.active = temp_ob
1317
+ temp_ob.select = True
1318
+
1319
+ bm = bmesh.new()
1320
+ bm.from_mesh(temp_me)
1321
+ bm.verts.ensure_lookup_table()
1322
+
1323
+ vert_islands = []
1324
+ if self.mode == 'ALL':
1325
+ vert_islands.append([v.index for v in bm.verts])
1326
+ elif self.mode == 'PARTS':
1327
+ alread_vert_indices = []
1328
+ for i in range(9**9):
1329
+
1330
+ vert_islands.append([])
1331
+
1332
+ for vert in bm.verts:
1333
+ if vert.index not in alread_vert_indices:
1334
+ new_verts = [vert]
1335
+ alread_vert_indices.append(vert.index)
1336
+ vert_islands[-1].append(vert.index)
1337
+ break
1338
+
1339
+ for j in range(9**9):
1340
+
1341
+ vs = []
1342
+ for vert in new_verts:
1343
+ for edge in vert.link_edges:
1344
+ for v in edge.verts:
1345
+ if vert.index != v.index and v.index not in alread_vert_indices:
1346
+ vs.append(v)
1347
+ alread_vert_indices.append(v.index)
1348
+ vert_islands[-1].append(v.index)
1349
+ break
1350
+
1351
+ if not len(vs):
1352
+ break
1353
+
1354
+ new_verts = vs[:]
1355
+
1356
+ if len(bm.verts) <= len(alread_vert_indices):
1357
+ break
1358
+
1359
+ for island in vert_islands:
1360
+ edge_lens = []
1361
+ for index in island:
1362
+ lens = [e.calc_length() for e in bm.verts[index].link_edges]
1363
+ edge_lens.append( sum(lens) / len(lens) )
1364
+ edge_min, edge_max = min(edge_lens), max(edge_lens)
1365
+ try:
1366
+ multi = 1.0 / (edge_max - edge_min)
1367
+ except:
1368
+ multi = 1.0
1369
+
1370
+ for index in island:
1371
+ vert = bm.verts[index]
1372
+
1373
+ lens = [e.calc_length() for e in vert.link_edges]
1374
+ l = sum(lens) / len(lens)
1375
+ value = (l - edge_min) * multi
1376
+ for loop in vert.link_loops:
1377
+ temp_vertex_color.data[loop.index].color = (value, value, value)
1378
+
1379
+ context.scene.render.bake_type = 'VERTEX_COLORS'
1380
+ context.scene.render.use_bake_selected_to_active = False
1381
+ bpy.ops.object.bake_image()
1382
+
1383
+ common.remove_data([temp_me, temp_ob])
1384
+ context.scene.objects.active = ob
1385
+ ob.select = True
1386
+
1387
+ return {'FINISHED'}
1388
+
1389
+ class quick_mesh_distance_bake_image(bpy.types.Operator):
1390
+ bl_idname = 'object.quick_mesh_distance_bake_image'
1391
+ bl_label = "Mesh distance bake"
1392
+ bl_description = "Bake the distance between the other objects in the active object"
1393
+ bl_options = {'REGISTER', 'UNDO'}
1394
+
1395
+ image_name = bpy.props.StringProperty(name="Image Name")
1396
+ items = [
1397
+ ('128', "128 px", "", 'LAYER_USED', 1),
1398
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
1399
+ ('512', "512 px", "", 'HAND', 3),
1400
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
1401
+ ('2048', "2048 px", "", 'ERROR', 5),
1402
+ ('4096', "4096 px", "", 'CANCEL', 6),
1403
+ ]
1404
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
1405
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
1406
+
1407
+ @classmethod
1408
+ def poll(cls, context):
1409
+ obs = context.selected_objects
1410
+ if len(obs) != 2: return False
1411
+ for ob in obs:
1412
+ if ob.type != 'MESH':
1413
+ return False
1414
+ me = context.active_object.data
1415
+ if len(me.uv_layers):
1416
+ return True
1417
+ return False
1418
+
1419
+ def invoke(self, context, event):
1420
+ ob = context.active_object
1421
+ self.image_name = ob.name + " Mesh Distance Bake"
1422
+ return context.window_manager.invoke_props_dialog(self)
1423
+
1424
+ def draw(self, context):
1425
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
1426
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
1427
+ row = self.layout.row(align=True)
1428
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
1429
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
1430
+
1431
+ def execute(self, context):
1432
+ target_ob = context.active_object
1433
+ target_ob.hide_render = False
1434
+ for ob in context.selected_objects:
1435
+ if ob.name != target_ob.name:
1436
+ source_ob = ob
1437
+ ob.select = False
1438
+ target_me = target_ob.data
1439
+ source_me = source_ob.data
1440
+
1441
+ image_width, image_height = int(self.image_width), int(self.image_height)
1442
+
1443
+ if self.image_name in context.blend_data.images:
1444
+ img = context.blend_data.images[self.image_name]
1445
+ else:
1446
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
1447
+
1448
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
1449
+ common.set_area_space_attr(area, 'image', img)
1450
+ for elem in target_me.uv_textures.active.data:
1451
+ elem.image = img
1452
+
1453
+ temp_me = target_ob.to_mesh(scene=context.scene, apply_modifiers=True, settings='PREVIEW')
1454
+ temp_ob = context.blend_data.objects.new("quick_density_bake_image", temp_me)
1455
+ context.scene.objects.link(temp_ob)
1456
+ for vc in temp_me.vertex_colors:
1457
+ temp_me.vertex_colors.remove(vc)
1458
+ temp_vertex_color = temp_me.vertex_colors.new(name="quick_density_bake_image")
1459
+ context.scene.objects.active = temp_ob
1460
+ temp_ob.select = True
1461
+
1462
+ bvh = mathutils.bvhtree.BVHTree.FromObject(source_ob, context.scene)
1463
+
1464
+ vert_dists = []
1465
+ for vert in temp_me.vertices:
1466
+ co = target_ob.matrix_world * vert.co
1467
+ location, normal, index, dist = bvh.find(co)
1468
+ vert_dists.append(dist)
1469
+
1470
+ dist_min, dist_max = min(vert_dists), max(vert_dists)
1471
+ try:
1472
+ multi = 1.0 / (dist_max - dist_min)
1473
+ except:
1474
+ multi = 1.0
1475
+
1476
+ for loop in temp_me.loops:
1477
+ value = ( vert_dists[loop.vertex_index] - dist_min ) * multi
1478
+ temp_vertex_color.data[loop.index].color = (value, value, value)
1479
+
1480
+ context.scene.render.bake_type = 'VERTEX_COLORS'
1481
+ context.scene.render.use_bake_selected_to_active = False
1482
+ bpy.ops.object.bake_image()
1483
+
1484
+ common.remove_data([temp_me, temp_ob])
1485
+ context.scene.objects.active = target_ob
1486
+ target_ob.select = True
1487
+ source_ob.select = True
1488
+
1489
+ return {'FINISHED'}
1490
+
1491
+ class quick_bulge_bake_image(bpy.types.Operator):
1492
+ bl_idname = 'object.quick_bulge_bake_image'
1493
+ bl_label = "Bulge Bake"
1494
+ bl_description = "Quick bakes the parts that bulge"
1495
+ bl_options = {'REGISTER', 'UNDO'}
1496
+
1497
+ image_name = bpy.props.StringProperty(name="Image Name")
1498
+ items = [
1499
+ ('128', "128 px", "", 'LAYER_USED', 1),
1500
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
1501
+ ('512', "512 px", "", 'HAND', 3),
1502
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
1503
+ ('2048', "2048 px", "", 'ERROR', 5),
1504
+ ('4096', "4096 px", "", 'CANCEL', 6),
1505
+ ]
1506
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
1507
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
1508
+
1509
+ @classmethod
1510
+ def poll(cls, context):
1511
+ if len(context.selected_objects) != 1:
1512
+ return False
1513
+ ob = context.active_object
1514
+ if ob:
1515
+ if ob.type == 'MESH':
1516
+ me = ob.data
1517
+ if len(me.uv_layers):
1518
+ return True
1519
+ return False
1520
+
1521
+ def invoke(self, context, event):
1522
+ ob = context.active_object
1523
+ self.image_name = ob.name + " Bulge Bake"
1524
+ return context.window_manager.invoke_props_dialog(self)
1525
+
1526
+ def draw(self, context):
1527
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
1528
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
1529
+ row = self.layout.row(align=True)
1530
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
1531
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
1532
+
1533
+ def execute(self, context):
1534
+ ob = context.active_object
1535
+ me = ob.data
1536
+ ob.select = False
1537
+ ob.hide_render = False
1538
+
1539
+ image_width, image_height = int(self.image_width), int(self.image_height)
1540
+
1541
+ if self.image_name in context.blend_data.images:
1542
+ img = context.blend_data.images[self.image_name]
1543
+ else:
1544
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
1545
+
1546
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
1547
+ common.set_area_space_attr(area, 'image', img)
1548
+ for elem in me.uv_textures.active.data:
1549
+ elem.image = img
1550
+
1551
+ temp_me = ob.to_mesh(scene=context.scene, apply_modifiers=True, settings='PREVIEW')
1552
+ temp_ob = context.blend_data.objects.new("quick_bulge_bake_image", temp_me)
1553
+ context.scene.objects.link(temp_ob)
1554
+ for vc in temp_me.vertex_colors:
1555
+ temp_me.vertex_colors.remove(vc)
1556
+ temp_vertex_color = temp_me.vertex_colors.new(name="quick_bulge_bake_image")
1557
+ context.scene.objects.active = temp_ob
1558
+ temp_ob.select = True
1559
+
1560
+ bm = bmesh.new()
1561
+ bm.from_mesh(temp_me)
1562
+
1563
+ angles = []
1564
+ for vert in bm.verts:
1565
+ normal = vert.normal
1566
+ edge_angle_total = 0.0
1567
+ for edge in vert.link_edges:
1568
+ diff_co = edge.other_vert(vert).co - vert.co
1569
+ if 0 < diff_co.length:
1570
+ edge_angle_total += normal.angle(diff_co)
1571
+ if len(vert.link_edges):
1572
+ edge_angle = edge_angle_total / len(vert.link_edges)
1573
+ else:
1574
+ edge_angle = 0.0
1575
+ angles.append(edge_angle)
1576
+
1577
+ angle_min, angle_max = 1.5708, max(angles)
1578
+ multi = 1.0 / (angle_max - angle_min)
1579
+
1580
+ for vert in bm.verts:
1581
+ value = (angles[vert.index] - angle_min) * multi
1582
+ for loop in vert.link_loops:
1583
+ temp_vertex_color.data[loop.index].color = (value, value, value)
1584
+
1585
+ context.scene.render.bake_type = 'VERTEX_COLORS'
1586
+ context.scene.render.use_bake_selected_to_active = False
1587
+ bpy.ops.object.bake_image()
1588
+
1589
+ common.remove_data([temp_me, temp_ob])
1590
+ context.scene.objects.active = ob
1591
+ ob.select = True
1592
+
1593
+ return {'FINISHED'}
1594
+
1595
+ class quick_semen_bake_image(bpy.types.Operator):
1596
+ bl_idname = 'object.quick_semen_bake_image'
1597
+ bl_label = "White liquid bake AKA Semen"
1598
+ bl_description = "Bake the white liquid to the object..."
1599
+ bl_options = {'REGISTER', 'UNDO'}
1600
+
1601
+ image_name = bpy.props.StringProperty(name="Image Name")
1602
+ items = [
1603
+ ('128', "128 px", "", 'LAYER_USED', 1),
1604
+ ('256', "256 px", "", 'LAYER_ACTIVE', 2),
1605
+ ('512', "512 px", "", 'HAND', 3),
1606
+ ('1024', "1024 px", "", 'FILE_TICK', 4),
1607
+ ('2048', "2048 px", "", 'ERROR', 5),
1608
+ ('4096', "4096 px", "", 'CANCEL', 6),
1609
+ ]
1610
+ image_width = bpy.props.EnumProperty(items=items, name="Width", default='1024')
1611
+ image_height = bpy.props.EnumProperty(items=items, name="Height", default='1024')
1612
+
1613
+ texture_scale = bpy.props.FloatProperty(name="Texture size", default=1, min=0, max=100, soft_min=0, soft_max=100, step=50, precision=1)
1614
+
1615
+ @classmethod
1616
+ def poll(cls, context):
1617
+ if len(context.selected_objects) != 1:
1618
+ return False
1619
+ ob = context.active_object
1620
+ if ob:
1621
+ if ob.type == 'MESH':
1622
+ me = ob.data
1623
+ if len(me.uv_layers):
1624
+ return True
1625
+ return False
1626
+
1627
+ def invoke(self, context, event):
1628
+ ob = context.active_object
1629
+ self.image_name = ob.name + " Semen Bake"
1630
+ return context.window_manager.invoke_props_dialog(self)
1631
+
1632
+ def draw(self, context):
1633
+ self.layout.label(text="New image settings", icon='IMAGE_COL')
1634
+ self.layout.prop(self, 'image_name', icon='SORTALPHA')
1635
+ row = self.layout.row(align=True)
1636
+ row.prop(self, 'image_width', icon='ARROW_LEFTRIGHT')
1637
+ row.prop(self, 'image_height', icon='NLA_PUSHDOWN')
1638
+
1639
+ self.layout.prop(self, 'texture_scale', icon='TEXTURE')
1640
+
1641
+ def execute(self, context):
1642
+ ob = context.active_object
1643
+ me = ob.data
1644
+ ob.hide_render = False
1645
+
1646
+ override = context.copy()
1647
+ override['object'] = ob
1648
+
1649
+ image_width, image_height = int(self.image_width), int(self.image_height)
1650
+
1651
+ if self.image_name in context.blend_data.images:
1652
+ img = context.blend_data.images[self.image_name]
1653
+ else:
1654
+ img = context.blend_data.images.new(self.image_name, image_width, image_height, alpha=True)
1655
+
1656
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
1657
+ common.set_area_space_attr(area, 'image', img)
1658
+ for elem in me.uv_textures.active.data:
1659
+ elem.image = img
1660
+
1661
+ material_restore = common.material_restore(ob)
1662
+
1663
+ blend_path = os.path.join(os.path.dirname(__file__), "append_data.blend")
1664
+ with context.blend_data.libraries.load(blend_path) as (data_from, data_to):
1665
+ data_to.materials = ["Semen"]
1666
+
1667
+ bpy.ops.object.material_slot_add(override)
1668
+ temp_mate = data_to.materials[0]
1669
+ ob.material_slots[0].material = temp_mate
1670
+ temp_mate.texture_slots[0].scale = (self.texture_scale, self.texture_scale, self.texture_scale)
1671
+
1672
+ context.scene.render.bake_type = 'TEXTURE'
1673
+ context.scene.render.use_bake_selected_to_active = False
1674
+ bpy.ops.object.bake_image()
1675
+
1676
+ common.remove_data([temp_mate, temp_mate.texture_slots[0].texture, temp_mate.texture_slots[0].texture.image])
1677
+
1678
+ material_restore.restore()
1679
+
1680
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_RENDER_PT_render.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「レンダー」タブ → 「レンダー」パネル
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ self.layout.operator('render.render_cm3d2_icon', icon_value=common.preview_collections['main']['KISS'].icon_id)
8
+
9
+ class render_cm3d2_icon(bpy.types.Operator):
10
+ bl_idname = 'render.render_cm3d2_icon'
11
+ bl_label = "Render a CM3D2 Style Icon"
12
+ bl_description = "Renders a small icon that looks very similar to the icons found in official content."
13
+ bl_options = {'REGISTER', 'UNDO'}
14
+
15
+ items = [
16
+ ('FACE_TEXTURE', "With Textures", "", 'FACESEL_HLT', 1),
17
+ ('NOW_MATERIAL', "With Material", "", 'MATERIAL', 2),
18
+ ]
19
+ mode = bpy.props.EnumProperty(items=items, name="Mode", default='FACE_TEXTURE')
20
+
21
+ use_freestyle = bpy.props.BoolProperty(name="Outline", default=True)
22
+ line_thickness = bpy.props.FloatProperty(name="Outline Thickness", default=0.2, min=0, max=0.5, soft_min=0, soft_max=0.5, step=10, precision=2, subtype='PIXEL')
23
+ line_color = bpy.props.FloatVectorProperty(name="Outline Color", default=(0, 0, 0), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=3)
24
+
25
+ resolution = bpy.props.IntProperty(name="Resolution", default=80, min=10, max=800, soft_min=10, soft_max=800, subtype='PIXEL')
26
+ camera_angle = bpy.props.FloatVectorProperty(name="Camera Angle", default=(0.576667, 0.576667, 0.578715), min=-10, max=10, soft_min=-10, soft_max=10, step=1, precision=2, subtype='DIRECTION', size=3)
27
+ camera_move = bpy.props.FloatVectorProperty(name="Camera Movement", default=(0, 0), min=-10, max=10, soft_min=-10, soft_max=10, step=10, precision=2, subtype='XYZ', size=2)
28
+ zoom_multi = bpy.props.IntProperty(name="Distance", default=100, min=10, max=190, soft_min=10, soft_max=190, step=10, subtype='PERCENTAGE')
29
+
30
+ use_background_color = bpy.props.BoolProperty(name="Use Background", default=True)
31
+ background_color = bpy.props.FloatVectorProperty(name="Background Color", default=(1, 1, 1), min=0, max=1, soft_min=0, soft_max=1, step=10, precision=2, subtype='COLOR', size=3)
32
+ is_round_background = bpy.props.BoolProperty(name="Round Corners", default=True)
33
+
34
+ layer_image = bpy.props.StringProperty(name="Overlay", default="")
35
+
36
+ @classmethod
37
+ def poll(cls, context):
38
+ obs = context.selected_objects
39
+ if not len(obs):
40
+ return False
41
+ for ob in obs:
42
+ if ob.type == 'MESH':
43
+ return True
44
+ return False
45
+
46
+ def invoke(self, context, event):
47
+ obs = context.selected_objects
48
+ for ob in obs:
49
+ if ob.type != 'MESH': continue
50
+ me = ob.data
51
+ if not len(me.uv_textures): continue
52
+ if me.uv_textures.active.data[0].image:
53
+ self.mode = 'FACE_TEXTURE'
54
+ break
55
+ else:
56
+ self.mode = 'NOW_MATERIAL'
57
+
58
+ if 'render_cm3d2_icon_background_color' in context.scene:
59
+ try:
60
+ color = str( context.scene['render_cm3d2_icon_background_color'] ).split(",")
61
+ if len(color) == 3:
62
+ self.background_color[0] = float(color[0])
63
+ self.background_color[1] = float(color[1])
64
+ self.background_color[2] = float(color[2])
65
+ except: pass
66
+ if 'render_cm3d2_icon_background_color_layer_image' in context.scene: self.layer_image = context.scene['render_cm3d2_icon_background_color_layer_image']
67
+
68
+ return context.window_manager.invoke_props_dialog(self)
69
+
70
+ def draw(self, context):
71
+ self.layout.prop(self, 'resolution', icon='IMAGE_COL', slider=True)
72
+ col = self.layout.column(align=True)
73
+ col.label(text="Texture reference method", icon='TEXTURE_SHADED')
74
+ row = col.row()
75
+ row.prop(self, 'mode', icon='TEXTURE_SHADED', expand=True)
76
+ self.layout.separator()
77
+
78
+ row = self.layout.split(percentage=1/3, align=True)
79
+ row.prop(self, 'use_freestyle', icon='LINE_DATA', text="Outline")
80
+ row.prop(self, 'line_thickness', icon='ARROW_LEFTRIGHT', slider=True, text="")
81
+ row.prop(self, 'line_color', icon='COLOR', text="")
82
+ self.layout.separator()
83
+
84
+ col = self.layout.column(align=True)
85
+ col.label(text="Camera Angle", icon='FILE_REFRESH')
86
+ col.prop(self, 'camera_angle', text="")
87
+ self.layout.prop(self, 'camera_move', icon='ARROW_LEFTRIGHT')
88
+ self.layout.prop(self, 'zoom_multi', icon='VIEWZOOM', slider=True)
89
+ self.layout.separator()
90
+
91
+ row = self.layout.split(percentage=0.333333333, align=True)
92
+ row.prop(self, 'use_background_color', icon='WORLD')
93
+ row.prop(self, 'background_color', icon='COLOR', text="")
94
+ row.prop(self, 'is_round_background', icon='MATCAP_24')
95
+
96
+ self.layout.separator()
97
+ self.layout.prop_search(self, 'layer_image', context.blend_data, "images", icon='MOD_UVPROJECT')
98
+
99
+ def execute(self, context):
100
+ import math, mathutils
101
+
102
+ c = self.background_color[:]
103
+ context.scene['render_cm3d2_icon_background_color'] = ",".join([ str(c[0]), str(c[1]), str(c[2]) ])
104
+ context.scene['render_cm3d2_icon_background_color_layer_image'] = self.layer_image
105
+
106
+ override = context.copy()
107
+
108
+ obs = context.selected_objects
109
+
110
+ if self.mode == 'FACE_TEXTURE':
111
+ material_restores = []
112
+ temp_mates = []
113
+ for ob in obs:
114
+ material_restores.append( common.material_restore(ob) )
115
+ override['object'] = ob
116
+ bpy.ops.object.material_slot_add(override)
117
+ temp_mate = context.blend_data.materials.new("temp")
118
+ ob.material_slots[0].material = temp_mate
119
+ temp_mate.use_shadeless = True
120
+ temp_mate.use_face_texture = True
121
+ temp_mate.use_transparency = True
122
+ temp_mate.alpha = 0.0
123
+ temp_mate.use_face_texture_alpha = True
124
+ temp_mates.append(temp_mate)
125
+ elif self.mode == 'NOW_MATERIAL':
126
+ pre_mate_settings = []
127
+ for ob in obs:
128
+ pre_mate_settings.append([])
129
+ for slot in ob.material_slots:
130
+ if not slot.material: continue
131
+ mate = slot.material
132
+ pre_mate_settings[-1].append([mate, mate.use_shadeless])
133
+ mate.use_shadeless = True
134
+
135
+ xs, ys, zs = [], [], []
136
+ for ob in obs:
137
+ if ob.type == 'MESH':
138
+ temp_me = ob.to_mesh(context.scene, apply_modifiers=True, settings='PREVIEW')
139
+ for vert in temp_me.vertices:
140
+ co = ob.matrix_world * vert.co
141
+ xs.append(co.x)
142
+ ys.append(co.y)
143
+ zs.append(co.z)
144
+ common.remove_data(temp_me)
145
+ center_co = mathutils.Vector((0, 0, 0))
146
+ center_co.x = (min(xs) + max(xs)) / 2.0
147
+ center_co.y = (min(ys) + max(ys)) / 2.0
148
+ center_co.z = (min(zs) + max(zs)) / 2.0
149
+
150
+ hide_render_restore = common.hide_render_restore()
151
+
152
+ maxs = [-999, -999, -999]
153
+ mins = [999, 999, 999]
154
+ for ob in obs:
155
+ for i in range(8):
156
+ for j in range(3):
157
+ v = ob.bound_box[i][j]
158
+ if maxs[j] < v:
159
+ maxs[j] = v
160
+ if v < mins[j]:
161
+ mins[j] = v
162
+
163
+ lens = [maxs[0] - mins[0]]
164
+ lens.append(maxs[1] - mins[1])
165
+ lens.append(maxs[2] - mins[2])
166
+ lens.sort()
167
+ zoom = lens[-1] * 1.2
168
+
169
+ pre_scene_camera = context.scene.camera
170
+ temp_camera = context.blend_data.cameras.new("render_cm3d2_icon_temp")
171
+ temp_camera_ob = context.blend_data.objects.new("render_cm3d2_icon_temp", temp_camera)
172
+ context.scene.objects.link(temp_camera_ob)
173
+ context.scene.camera = temp_camera_ob
174
+ temp_camera.type = 'ORTHO'
175
+ temp_camera.ortho_scale = zoom * (self.zoom_multi * 0.01)
176
+
177
+ direct = self.camera_angle.copy()
178
+ direct.rotate( mathutils.Euler((math.radians(90), 0, 0), 'XYZ') )
179
+ temp_camera_ob.rotation_mode = 'QUATERNION'
180
+ temp_camera_ob.rotation_quaternion = direct.to_track_quat('Z', 'Y')
181
+ temp_camera_ob.location = direct * 10
182
+ temp_camera_ob.location += center_co
183
+ vec = mathutils.Vector()
184
+ vec.x, vec.y = -self.camera_move.x, -self.camera_move.y
185
+ temp_camera_ob.location += direct.to_track_quat('Z', 'Y') * vec
186
+
187
+ context.scene.render.resolution_x = self.resolution
188
+ context.scene.render.resolution_y = self.resolution
189
+ context.scene.render.resolution_percentage = 100
190
+
191
+ context.scene.world.light_settings.use_ambient_occlusion = False
192
+ context.scene.world.light_settings.ao_blend_type = 'ADD'
193
+ context.scene.world.light_settings.gather_method = 'RAYTRACE'
194
+ context.scene.world.light_settings.samples = 10
195
+
196
+ context.scene.render.alpha_mode = 'SKY' if self.use_background_color else 'TRANSPARENT'
197
+ context.scene.world.horizon_color = self.background_color
198
+
199
+ if self.use_freestyle:
200
+ pre_use_freestyle = context.scene.render.use_freestyle
201
+ pre_line_thickness = context.scene.render.line_thickness
202
+ context.scene.render.use_freestyle = True
203
+ context.scene.render.line_thickness = self.line_thickness
204
+ temp_lineset = context.scene.render.layers.active.freestyle_settings.linesets.new("temp")
205
+ temp_lineset.linestyle.color = self.line_color
206
+
207
+ # コンポジットノード #
208
+ pre_use_nodes = context.scene.use_nodes
209
+ context.scene.use_nodes = True
210
+ node_tree = context.scene.node_tree
211
+ for node in node_tree.nodes:
212
+ node_tree.nodes.remove(node)
213
+
214
+ in_node = node_tree.nodes.new('CompositorNodeRLayers')
215
+ in_node.location = (0, 0)
216
+
217
+ img_node = node_tree.nodes.new('CompositorNodeImage')
218
+ img_node.location = (0, -300)
219
+ blend_path = os.path.join(os.path.dirname(__file__), "append_data.blend")
220
+ if "Icon Alpha" in context.blend_data.images:
221
+ icon_alpha_img = context.blend_data.images["Icon Alpha"]
222
+ else:
223
+ with context.blend_data.libraries.load(blend_path) as (data_from, data_to):
224
+ data_to.images = ["Icon Alpha"]
225
+ icon_alpha_img = data_to.images[0]
226
+ img_node.image = icon_alpha_img
227
+
228
+ scale_node = node_tree.nodes.new('CompositorNodeScale')
229
+ scale_node.location = (250, -300)
230
+ scale_node.space = 'RENDER_SIZE'
231
+
232
+ mix_node = node_tree.nodes.new('CompositorNodeMixRGB')
233
+ mix_node.location = (500, -100)
234
+ mix_node.blend_type = 'MULTIPLY'
235
+
236
+ alpha_node = node_tree.nodes.new('CompositorNodeSetAlpha')
237
+ alpha_node.location = (750, 0)
238
+
239
+ out_node = node_tree.nodes.new('CompositorNodeComposite')
240
+ out_node.location = (1500, 0)
241
+
242
+ layer_img = None
243
+ if self.layer_image in context.blend_data.images:
244
+ layer_img = context.blend_data.images[self.layer_image]
245
+ if layer_img:
246
+ layer_img_node = node_tree.nodes.new('CompositorNodeImage')
247
+ layer_img_node.location = (750, -200)
248
+ layer_img_node.image = layer_img
249
+
250
+ layer_scale_node = node_tree.nodes.new('CompositorNodeScale')
251
+ layer_scale_node.location = (1000, -200)
252
+ layer_scale_node.space = 'RENDER_SIZE'
253
+
254
+ layer_add_node = node_tree.nodes.new('CompositorNodeAlphaOver')
255
+ layer_add_node.location = (1250, 0)
256
+
257
+ node_tree.links.new(layer_add_node.inputs[1], alpha_node.outputs[0])
258
+ node_tree.links.new(layer_scale_node.inputs[0], layer_img_node.outputs[0])
259
+ node_tree.links.new(layer_add_node.inputs[2], layer_scale_node.outputs[0])
260
+ node_tree.links.new(out_node.inputs[0], layer_add_node.outputs[0])
261
+ else:
262
+ node_tree.links.new(out_node.inputs[0], alpha_node.outputs[0])
263
+
264
+ node_tree.links.new(alpha_node.inputs[0], in_node.outputs[0])
265
+ node_tree.links.new(mix_node.inputs[1], in_node.outputs[1])
266
+ node_tree.links.new(scale_node.inputs[0], img_node.outputs[0])
267
+ node_tree.links.new(mix_node.inputs[2], scale_node.outputs[0])
268
+ if self.is_round_background:
269
+ node_tree.links.new(alpha_node.inputs[1], mix_node.outputs[0])
270
+ # コンポジットノード #
271
+
272
+ bpy.ops.render.render()
273
+
274
+ if self.is_round_background:
275
+ for node in node_tree.nodes:
276
+ node_tree.nodes.remove(node)
277
+ context.scene.use_nodes = False
278
+ common.remove_data([icon_alpha_img])
279
+
280
+ if self.use_freestyle:
281
+ context.scene.render.use_freestyle = pre_use_freestyle
282
+ context.scene.render.line_thickness = pre_line_thickness
283
+ common.remove_data([temp_lineset.linestyle])
284
+ context.scene.render.layers.active.freestyle_settings.linesets.remove(temp_lineset)
285
+
286
+ img = context.blend_data.images["Render Result"]
287
+ img['tex Name'] = common.remove_serial_number( context.active_object.name.split('.')[0] ) + "_i_.tex"
288
+ img['cm3d2_path'] = "assets/texture/texture/" + context.active_object.name.split('.')[0] + "_i_.png"
289
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
290
+ common.set_area_space_attr(area, 'image', img)
291
+
292
+ common.remove_data([temp_camera_ob, temp_camera])
293
+ context.scene.camera = pre_scene_camera
294
+
295
+ if self.mode == 'FACE_TEXTURE':
296
+ for material_restore in material_restores:
297
+ material_restore.restore()
298
+ common.remove_data(temp_mates)
299
+ elif self.mode == 'NOW_MATERIAL':
300
+ for ob_mate in pre_mate_settings:
301
+ for mate, is_shadeless in ob_mate:
302
+ mate.use_shadeless = is_shadeless
303
+
304
+ hide_render_restore.restore()
305
+
306
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_TEXTURE_PT_context_texture.py ADDED
@@ -0,0 +1,568 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「プロパティ」エリア → 「テクスチャ」タブ
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ import os
8
+
9
+ try:
10
+ tex_slot = context.texture_slot
11
+ tex = context.texture
12
+ mate = context.active_object.active_material
13
+ mate['shader1']
14
+ mate['shader2']
15
+ except: return
16
+ if not tex_slot: return
17
+
18
+ if tex_slot.use:
19
+ type = 'tex'
20
+ else:
21
+ type = 'col' if tex_slot.use_rgb_to_intensity else 'f'
22
+ base_name = common.remove_serial_number(tex.name)
23
+
24
+ box = self.layout.box()
25
+ box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
26
+ split = box.split(percentage=0.333333333333333333)
27
+ split.label(text="Setting type:")
28
+ row = split.row()
29
+
30
+ if type == 'tex': row.label(text='Texture', icon='TEXTURE')
31
+ elif type == 'col': row.label(text='Color', icon='COLOR')
32
+ elif type == 'f': row.label(text='Value', icon='ARROW_LEFTRIGHT')
33
+
34
+ check_row = row.row(align=True)
35
+ check_row.prop(tex_slot, 'use', text="")
36
+ sub_row = check_row.row()
37
+ sub_row.prop(tex_slot, 'use_rgb_to_intensity', text="")
38
+ if tex_slot.use:
39
+ sub_row.enabled = False
40
+ box.prop(tex, 'name', icon='SORTALPHA', text="Setting value name")
41
+
42
+ if type == "tex":
43
+ if tex.type == 'IMAGE':
44
+ img = tex.image
45
+ if img:
46
+ if img.source == 'FILE':
47
+
48
+ if re.search(r"\.[Pp][Nn][Gg]$", img.name):
49
+ img.name = re.sub(r"\.[Pp][Nn][Gg]$", "", img.name)
50
+ if re.search(r"\.[Pp][Nn][Gg]\.\d{3}$", img.name):
51
+ img.name = re.sub(r"\.[Pp][Nn][Gg](\.\d{3})$", r"\1", img.name)
52
+
53
+ sub_box = box.box()
54
+ row = sub_box.split(percentage=0.333333333333, align=True)
55
+ row.label(text="Texture name:")
56
+ row.template_ID(tex, 'image', open='image.open')
57
+ if 'cm3d2_path' not in img:
58
+ img['cm3d2_path'] = "Assets\\texture\\texture\\" + os.path.basename(img.filepath)
59
+ sub_box.prop(img, '["cm3d2_path"]', text="Texture path")
60
+
61
+ if base_name == "_ToonRamp":
62
+ sub_box.menu('TEXTURE_PT_context_texture_ToonRamp', icon='NLA')
63
+ elif base_name == "_ShadowRateToon":
64
+ sub_box.menu('TEXTURE_PT_context_texture_ShadowRateToon', icon='NLA')
65
+ split = sub_box.split(percentage=0.333333333333, align=True)
66
+ split.label(text="Offset:")
67
+ row = split.row(align=True)
68
+ row.prop(tex_slot, 'color', index=0, text="")
69
+ row.prop(tex_slot, 'color', index=1, text="")
70
+
71
+ split = sub_box.split(percentage=0.333333333333, align=True)
72
+ split.label(text="Enlargement/Reduction:")
73
+ row = split.row(align=True)
74
+ row.prop(tex_slot, 'color', index=2, text="")
75
+ row.prop(tex_slot, 'diffuse_color_factor', text="")
76
+
77
+ row = sub_box.row()
78
+ row.operator('image.show_image', text="Image to UV/Image Editor", icon='ZOOM_IN').image_name = img.name
79
+ if len(img.pixels):
80
+ row.operator('image.quick_export_cm3d2_tex', text="Save as .Tex", icon='FILESEL')
81
+ else:
82
+ row.operator('image.replace_cm3d2_tex', icon='BORDERMOVE')
83
+
84
+ elif type == "col":
85
+ sub_box = box.box()
86
+
87
+ #row = sub_box.split(percentage=0.7, align=True)
88
+ row = sub_box.row(align=True)
89
+ row.prop(tex_slot, 'color', text="")
90
+ row.operator('texture.auto_set_color_value', icon='RECOVER_AUTO', text="Auto")
91
+ row.operator('texture.set_color_value', text="", icon='MATCAP_10').color = [0, 0, 0] + [tex_slot.diffuse_color_factor]
92
+ row.operator('texture.set_color_value', text="", icon='MATCAP_24').color = [1, 1, 1] + [tex_slot.diffuse_color_factor]
93
+
94
+ row = sub_box.row(align=True)
95
+ row.operator('texture.set_color_value', text="", icon='TRIA_LEFT').color = list(tex_slot.color) + [0]
96
+ row.prop(tex_slot, 'diffuse_color_factor', icon='IMAGE_RGB_ALPHA', text="Alpha", slider=True)
97
+ row.operator('texture.set_color_value', text="", icon='TRIA_RIGHT').color = list(tex_slot.color) + [1]
98
+
99
+ elif type == "f":
100
+ sub_box = box.box()
101
+ row = sub_box.row(align=True)
102
+ row.prop(tex_slot, 'diffuse_color_factor', icon='ARROW_LEFTRIGHT', text="Value")
103
+
104
+ data_path = 'texture_slot.diffuse_color_factor'
105
+ if base_name == '_Shininess':
106
+ row.menu('TEXTURE_PT_context_texture_values_normal', icon='DOWNARROW_HLT', text="")
107
+
108
+ row = sub_box.row(align=True)
109
+ row.operator('texture.set_color_value', text="0.0", icon='MATCAP_10').color = list(tex_slot.color) + [0.0]
110
+ row.operator('texture.set_color_value', text="0.25").color = list(tex_slot.color) + [0.25]
111
+ row.operator('texture.set_color_value', text="0.5").color = list(tex_slot.color) + [0.5]
112
+ row.operator('texture.set_color_value', text="0.75").color = list(tex_slot.color) + [0.75]
113
+ row.operator('texture.set_color_value', text="1.0", icon='MATCAP_09').color = list(tex_slot.color) + [1.0]
114
+
115
+ elif base_name == '_OutlineWidth':
116
+ row.menu('TEXTURE_PT_context_texture_values_OutlineWidth', icon='DOWNARROW_HLT', text="")
117
+
118
+ row = sub_box.row(align=True)
119
+ row.operator('texture.set_color_value', text="0.001", icon='MATSPHERE').color = list(tex_slot.color) + [0.001]
120
+ row.operator('texture.set_color_value', text="0.0015").color = list(tex_slot.color) + [0.0015]
121
+ row.operator('texture.set_color_value', text="0.002", icon='ANTIALIASED').color = list(tex_slot.color) + [0.002]
122
+
123
+ split = sub_box.split(percentage=0.3)
124
+ split.label(text=" Exact Value: ")
125
+ split.label(text=str(tex_slot.diffuse_color_factor))
126
+
127
+ elif base_name == '_RimPower':
128
+ row.menu('TEXTURE_PT_context_texture_values_RimPower', icon='DOWNARROW_HLT', text="")
129
+
130
+ row = sub_box.row(align=True)
131
+ row.operator('texture.set_color_value', text="1", icon='BRUSH_TEXFILL').color = list(tex_slot.color) + [1]
132
+ row.operator('texture.set_color_value', text="10").color = list(tex_slot.color) + [10]
133
+ row.operator('texture.set_color_value', text="20").color = list(tex_slot.color) + [20]
134
+ row.operator('texture.set_color_value', text="30", icon='MATCAP_07').color = list(tex_slot.color) + [30]
135
+
136
+ elif base_name == '_RimShift':
137
+ row.menu('TEXTURE_PT_context_texture_values_normal', icon='DOWNARROW_HLT', text="")
138
+
139
+ row = sub_box.row(align=True)
140
+ row.operator('texture.set_color_value', text="0.0", icon='FULLSCREEN_EXIT').color = list(tex_slot.color) + [0.0]
141
+ row.operator('texture.set_color_value', text="0.25").color = list(tex_slot.color) + [0.25]
142
+ row.operator('texture.set_color_value', text="0.5").color = list(tex_slot.color) + [0.5]
143
+ row.operator('texture.set_color_value', text="0.75").color = list(tex_slot.color) + [0.75]
144
+ row.operator('texture.set_color_value', text="1.0", icon='FULLSCREEN_ENTER').color = list(tex_slot.color) + [1.0]
145
+
146
+ box.operator('texture.sync_tex_color_ramps', icon='LINKED')
147
+
148
+ description = ""
149
+ if base_name == '_MainTex':
150
+ description = ["The Main Texture is the primary texture as it will be most visible on the surface of the mesh.", "The Texture path should move automatically at the time of export.", "Please insert an appropriate texture name and withold any file type extensions."]
151
+ if base_name == '_ToonRamp':
152
+ description = ["This specifies a toon ramp that will be used in the transition from lit areas to shadow areas."]
153
+ elif base_name == '_ShadowTex':
154
+ description = ["The texture will determine the Color of the surface of the shaded portion.", "Specify the range in the _ShadowRateToon。"]
155
+ if base_name == '_ShadowRateToon':
156
+ description = ["Will affect the intensity of the Shadowtex.", "This Makes black colors valid and white colors invalid"]
157
+ elif base_name == '_Color':
158
+ description = ["Specifies the color of the surface", "This setting has no effect when the color is white."]
159
+ elif base_name == '_ShadowColor':
160
+ description = ["Specifies the color of the shadow. Turn it white to disable it", "This will determine the color of the shadow any object casts on it."]
161
+ elif base_name == '_RimColor':
162
+ description = ["Specify the color of the Rim light", "The Rim light is the reflection of light that is on the edge", "It is recommended that you turn this off by setting the color to black and setting transparency to 0.", "Alternatively, you can use it though you should use near black color values."]
163
+ elif base_name == '_OutlineColor':
164
+ description = ["Specifies the Outline's color", "It is advised that the color you choose be darker or lighter then your texture."]
165
+ elif base_name == '_Shininess':
166
+ description = ["Strength of the Shininess", "This is good for simulating reflective surfaces like Metals, Leathers, and Glass."]
167
+ elif base_name == '_OutlineWidth':
168
+ description = ["Specifies the Outline's width", "0.002 is thick、0.001 is narrow。"]
169
+ elif base_name == '_RimPower':
170
+ description = ["Specifies Rim Lighting Power", "This value is often found to be around 10.", "If the value is close to 0. then the Rim lighting will not appear properly.", "Rim Power determines how the Rim light fades at it's ends. Higher values make the fade less subtle."]
171
+ elif base_name == '_RimShift':
172
+ description = ["Specifies the Size of the Rim Light", "At a value of 1. your mesh is completely engulfed by the Rim light.", "At a value of -0.1 the Rim light disappears."]
173
+ elif base_name == '_RenderTex':
174
+ description = ["Sets the Mosiac shader value", "This should be left alone."]
175
+ elif base_name == '_FloatValue1':
176
+ description = ["The amount of pixels in the Mosiac.", "Larger values give you a clearer picture."]
177
+
178
+ if description != "":
179
+ sub_box = box.box()
180
+ col = sub_box.column(align=True)
181
+ col.label(text="Comments", icon='TEXT')
182
+ for line in description:
183
+ col.label(text=line)
184
+
185
+ # _ToonRamp設定メニュー
186
+ class TEXTURE_PT_context_texture_ToonRamp(bpy.types.Menu):
187
+ bl_idname = 'TEXTURE_PT_context_texture_ToonRamp'
188
+ bl_label = "_ToonRamp Configuration"
189
+
190
+ def draw(self, context):
191
+ l = self.layout
192
+ cmd = 'texture.set_default_toon_textures'
193
+ l.operator(cmd, text="NoTex", icon='SPACE2').name = "NoTex"
194
+ l.operator(cmd, text="ToonBlackA1", icon='SPACE2').name = "ToonBlackA1"
195
+ l.operator(cmd, text="ToonBlueA1", icon='SPACE2').name = "ToonBlueA1"
196
+ l.operator(cmd, text="ToonBlueA2", icon='SPACE2').name = "ToonBlueA2"
197
+ l.operator(cmd, text="ToonBrownA1", icon='SPACE2').name = "ToonBrownA1"
198
+ l.operator(cmd, text="ToonDress_Shadow", icon='LAYER_USED').name = "ToonDress_Shadow"
199
+ l.operator(cmd, text="ToonFace", icon='SPACE2').name = "ToonFace"
200
+ l.operator(cmd, text="ToonFace_Shadow", icon='LAYER_USED').name = "ToonFace_Shadow"
201
+ l.operator(cmd, text="ToonFace002", icon='SPACE2').name = "ToonFace002"
202
+ l.operator(cmd, text="ToonGrayA1", icon='SPACE2').name = "ToonGrayA1"
203
+ l.operator(cmd, text="ToonGreenA1", icon='SPACE2').name = "ToonGreenA1"
204
+ l.operator(cmd, text="ToonGreenA2", icon='SPACE2').name = "ToonGreenA2"
205
+ l.operator(cmd, text="ToonOrangeA1", icon='SPACE2').name = "ToonOrangeA1"
206
+ l.operator(cmd, text="ToonPinkA1", icon='SPACE2').name = "ToonPinkA1"
207
+ l.operator(cmd, text="ToonPinkA2", icon='SPACE2').name = "ToonPinkA2"
208
+ l.operator(cmd, text="ToonPurpleA1", icon='SPACE2').name = "ToonPurpleA1"
209
+ l.operator(cmd, text="ToonRedA1", icon='SPACE2').name = "ToonRedA1"
210
+ l.operator(cmd, text="ToonRedA2", icon='SPACE2').name = "ToonRedA2"
211
+ l.operator(cmd, text="ToonSkin", icon='SPACE2').name = "ToonSkin"
212
+ l.operator(cmd, text="ToonSkin_Shadow", icon='LAYER_USED').name = "ToonSkin_Shadow"
213
+ l.operator(cmd, text="ToonSkin002", icon='SPACE2').name = "ToonSkin002"
214
+ l.operator(cmd, text="ToonYellowA1", icon='SPACE2').name = "ToonYellowA1"
215
+ l.operator(cmd, text="ToonYellowA2", icon='SPACE2').name = "ToonYellowA2"
216
+ l.operator(cmd, text="ToonYellowA3", icon='SPACE2').name = "ToonYellowA3"
217
+
218
+ # _ShadowRateToon設定メニュー
219
+ class TEXTURE_PT_context_texture_ShadowRateToon(bpy.types.Menu):
220
+ bl_idname = 'TEXTURE_PT_context_texture_ShadowRateToon'
221
+ bl_label = "_ShadowRateToon Configuration"
222
+
223
+ def draw(self, context):
224
+ l = self.layout
225
+ cmd = 'texture.set_default_toon_textures'
226
+ l.operator(cmd, text="NoTex", icon='LAYER_USED').name = "NoTex"
227
+ l.operator(cmd, text="ToonBlackA1", icon='LAYER_USED').name = "ToonBlackA1"
228
+ l.operator(cmd, text="ToonBlueA1", icon='LAYER_USED').name = "ToonBlueA1"
229
+ l.operator(cmd, text="ToonBlueA2", icon='LAYER_USED').name = "ToonBlueA2"
230
+ l.operator(cmd, text="ToonBrownA1", icon='LAYER_USED').name = "ToonBrownA1"
231
+ l.operator(cmd, text="ToonDress_Shadow", icon='SPACE2').name = "ToonDress_Shadow"
232
+ l.operator(cmd, text="ToonFace", icon='LAYER_USED').name = "ToonFace"
233
+ l.operator(cmd, text="ToonFace_Shadow", icon='SPACE2').name = "ToonFace_Shadow"
234
+ l.operator(cmd, text="ToonFace002", icon='LAYER_USED').name = "ToonFace002"
235
+ l.operator(cmd, text="ToonGrayA1", icon='LAYER_USED').name = "ToonGrayA1"
236
+ l.operator(cmd, text="ToonGreenA1", icon='LAYER_USED').name = "ToonGreenA1"
237
+ l.operator(cmd, text="ToonGreenA2", icon='LAYER_USED').name = "ToonGreenA2"
238
+ l.operator(cmd, text="ToonOrangeA1", icon='LAYER_USED').name = "ToonOrangeA1"
239
+ l.operator(cmd, text="ToonPinkA1", icon='LAYER_USED').name = "ToonPinkA1"
240
+ l.operator(cmd, text="ToonPinkA2", icon='LAYER_USED').name = "ToonPinkA2"
241
+ l.operator(cmd, text="ToonPurpleA1", icon='LAYER_USED').name = "ToonPurpleA1"
242
+ l.operator(cmd, text="ToonRedA1", icon='LAYER_USED').name = "ToonRedA1"
243
+ l.operator(cmd, text="ToonRedA2", icon='LAYER_USED').name = "ToonRedA2"
244
+ l.operator(cmd, text="ToonSkin", icon='LAYER_USED').name = "ToonSkin"
245
+ l.operator(cmd, text="ToonSkin_Shadow", icon='SPACE2').name = "ToonSkin_Shadow"
246
+ l.operator(cmd, text="ToonSkin002", icon='LAYER_USED').name = "ToonSkin002"
247
+ l.operator(cmd, text="ToonYellowA1", icon='LAYER_USED').name = "ToonYellowA1"
248
+ l.operator(cmd, text="ToonYellowA2", icon='LAYER_USED').name = "ToonYellowA2"
249
+ l.operator(cmd, text="ToonYellowA3", icon='LAYER_USED').name = "ToonYellowA3"
250
+
251
+ # 0.0~1.0までの値設定メニュー
252
+ class TEXTURE_PT_context_texture_values_normal(bpy.types.Menu):
253
+ bl_idname = 'TEXTURE_PT_context_texture_values_normal'
254
+ bl_label = "Value list"
255
+
256
+ def draw(self, context):
257
+ tex_slot = context.texture_slot
258
+ for i in range(11):
259
+ value = round(i * 0.1, 1)
260
+ icon = 'LAYER_USED' if i % 2 else 'LAYER_ACTIVE'
261
+ self.layout.operator('texture.set_color_value', text=str(value), icon=icon).color = list(tex_slot.color) + [value]
262
+
263
+ # _OutlineWidth用の値設定メニュー
264
+ class TEXTURE_PT_context_texture_values_OutlineWidth(bpy.types.Menu):
265
+ bl_idname = 'TEXTURE_PT_context_texture_values_OutlineWidth'
266
+ bl_label = "Value list"
267
+
268
+ def draw(self, context):
269
+ tex_slot = context.texture_slot
270
+ for i in range(16):
271
+ value = round(i * 0.0002, 4)
272
+ icon = 'LAYER_USED' if i % 2 else 'LAYER_ACTIVE'
273
+ self.layout.operator('texture.set_color_value', text=str(value), icon=icon).color = list(tex_slot.color) + [value]
274
+
275
+ # _RimPower用のValue設定メニュー
276
+ class TEXTURE_PT_context_texture_values_RimPower(bpy.types.Menu):
277
+ bl_idname = 'TEXTURE_PT_context_texture_values_RimPower'
278
+ bl_label = "Value list"
279
+
280
+ def draw(self, context):
281
+ tex_slot = context.texture_slot
282
+ for i in range(16):
283
+ value = round(i * 2, 0)
284
+ icon = 'LAYER_USED' if i % 2 else 'LAYER_ACTIVE'
285
+ if value == 0:
286
+ icon = 'ERROR'
287
+ self.layout.operator('texture.set_color_value', text=str(value), icon=icon).color = list(tex_slot.color) + [value]
288
+
289
+ class show_image(bpy.types.Operator):
290
+ bl_idname = 'image.show_image'
291
+ bl_label = "Open Image in UV/Image Editor"
292
+ bl_description = "Displays the specified image in the UV/ Image Editor"
293
+ bl_options = {'REGISTER', 'UNDO'}
294
+
295
+ image_name = bpy.props.StringProperty(name="Image name")
296
+
297
+ def execute(self, context):
298
+ if self.image_name in context.blend_data.images:
299
+ img = context.blend_data.images[self.image_name]
300
+ else:
301
+ self.report(type={'ERROR'}, message="Cannot find the file specified")
302
+ return {'CANCELLED'}
303
+
304
+ area = common.get_request_area(context, 'IMAGE_EDITOR')
305
+ if area:
306
+ common.set_area_space_attr(area, 'image', img)
307
+ else:
308
+ self.report(type={'ERROR'}, message="Area to view the image as not found")
309
+ return {'CANCELLED'}
310
+ return {'FINISHED'}
311
+
312
+ class replace_cm3d2_tex(bpy.types.Operator):
313
+ bl_idname = 'image.replace_cm3d2_tex'
314
+ bl_label = "Find texture"
315
+ bl_description = "looks for textures in the search paths specified in the Converter Settings."
316
+ bl_options = {'REGISTER', 'UNDO'}
317
+
318
+ @classmethod
319
+ def poll(cls, context):
320
+ if 'texture' in dir(context):
321
+ tex = context.texture
322
+ return 'image' in dir(tex)
323
+ return False
324
+
325
+ def execute(self, context):
326
+ tex = context.texture
327
+ img = tex.image
328
+ if not common.replace_cm3d2_tex(img):
329
+ self.report(type={'ERROR'}, message="Could not be located")
330
+ return {'CANCELLED'}
331
+ tex.image_user.use_auto_refresh = True
332
+ return {'FINISHED'}
333
+
334
+ class sync_tex_color_ramps(bpy.types.Operator):
335
+ bl_idname = 'texture.sync_tex_color_ramps'
336
+ bl_label = "Sync Textures to Colors and Values."
337
+ bl_description = "Applies Textures according to Color changes. (Example: Changing the RimColor)"
338
+ bl_options = {'REGISTER', 'UNDO'}
339
+
340
+ @classmethod
341
+ def poll(cls, context):
342
+ if 'material' in dir(context):
343
+ if context.material:
344
+ return True
345
+ if 'texture_slot' in dir(context) and 'texture' in dir(context):
346
+ return context.texture_slot and context.texture
347
+ return False
348
+
349
+ def execute(self, context):
350
+ for mate in context.blend_data.materials:
351
+ if 'shader1' in mate and 'shader2' in mate:
352
+ for slot in mate.texture_slots:
353
+ if not slot:
354
+ continue
355
+ common.set_texture_color(slot)
356
+ return {'FINISHED'}
357
+
358
+ class set_default_toon_textures(bpy.types.Operator):
359
+ bl_idname = 'texture.set_default_toon_textures'
360
+ bl_label = "Select the toon"
361
+ bl_description = "Select the default toon texture."
362
+ bl_options = {'REGISTER', 'UNDO'}
363
+
364
+ name = bpy.props.StringProperty(name="Texture name")
365
+ #dir = bpy.props.StringProperty(name="パス", default="Assets\\texture\\texture\\toon\\")
366
+
367
+ @classmethod
368
+ def poll(cls, context):
369
+ if 'texture_slot' in dir(context) and 'texture' in dir(context):
370
+ if context.texture_slot and context.texture:
371
+ name = common.remove_serial_number(context.texture.name)
372
+ return name == "_ToonRamp" or name == "_ShadowRateToon"
373
+ return False
374
+
375
+ def execute(self, context):
376
+ import os.path, struct
377
+ img = context.texture.image
378
+ img.name = self.name
379
+
380
+ png_path = os.path.join( os.path.dirname(bpy.path.abspath(img.filepath)), self.name + ".png" )
381
+ tex_path = os.path.splitext(png_path)[0] + ".tex"
382
+ if not os.path.exists(png_path):
383
+ if os.path.exists(tex_path):
384
+ tex_file = open(tex_path, 'rb')
385
+ header_ext = common.read_str(tex_file)
386
+ if header_ext == 'CM3D2_TEX':
387
+ tex_file.seek(4, 1)
388
+ common.read_str(tex_file)
389
+ png_size = struct.unpack('<i', tex_file.read(4))[0]
390
+ png_file = open(png_path, 'wb')
391
+ png_file.write(tex_file.read(png_size))
392
+ png_file.close()
393
+ tex_file.close()
394
+ img.filepath = png_path
395
+ img.reload()
396
+
397
+ img['cm3d2_path'] = bpy.path.abspath(img.filepath)
398
+ return {'FINISHED'}
399
+
400
+ class auto_set_color_value(bpy.types.Operator):
401
+ bl_idname = 'texture.auto_set_color_value'
402
+ bl_label = "Automatically set the Color setting Value"
403
+ bl_description = "Color settings are set automatically with the Colors in the Texture"
404
+ bl_options = {'REGISTER', 'UNDO'}
405
+
406
+ is_all = bpy.props.BoolProperty(name="All", default=True)
407
+ saturation_multi = bpy.props.FloatProperty(name="Saturation Multiplication", default=2.2, min=0, max=5, soft_min=0, soft_max=5, step=10, precision=2)
408
+ value_multi = bpy.props.FloatProperty(name="Mulitplication of Lightness value", default=0.3, min=0, max=5, soft_min=0, soft_max=5, step=10, precision=2)
409
+
410
+ @classmethod
411
+ def poll(cls, context):
412
+ ob = context.active_object
413
+ if not ob: return False
414
+ if ob.type != 'MESH': return False
415
+ me = ob.data
416
+ mate = ob.active_material
417
+ if not mate: return False
418
+ for slot in mate.texture_slots:
419
+ if not slot: continue
420
+ tex = slot.texture
421
+ name = common.remove_serial_number(tex.name)
422
+ if name == '_MainTex':
423
+ img = tex.image
424
+ if img:
425
+ if len(img.pixels):
426
+ break
427
+ if me.uv_textures.active:
428
+ if me.uv_textures.active.data[0].image:
429
+ if len(me.uv_textures.active.data[0].image.pixels):
430
+ break
431
+ else: return False
432
+ if 'texture_slot' in dir(context) and 'texture' in dir(context):
433
+ slot = context.texture_slot
434
+ tex = context.texture
435
+ name = common.remove_serial_number(tex.name)
436
+ if name in ['_ShadowColor', '_RimColor', '_OutlineColor']:
437
+ return True
438
+ return False
439
+
440
+ def invoke(self, context, event):
441
+ return context.window_manager.invoke_props_dialog(self)
442
+
443
+ def draw(self, context):
444
+ self.layout.prop(self, 'is_all', icon='ACTION')
445
+ row = self.layout.row()
446
+ row.label(text="", icon='SMOOTH')
447
+ row.prop(self, 'saturation_multi')
448
+ row = self.layout.row()
449
+ row.label(text="", icon='SOLID')
450
+ row.prop(self, 'value_multi')
451
+
452
+ def execute(self, context):
453
+ ob = context.active_object
454
+ me = ob.data
455
+ mate = ob.active_material
456
+ active_slot = context.texture_slot
457
+ active_tex = context.texture
458
+ tex_name = common.remove_serial_number(active_tex.name)
459
+
460
+ target_slots = []
461
+ if self.is_all:
462
+ for slot in mate.texture_slots:
463
+ if not slot: continue
464
+ name = common.remove_serial_number(slot.texture.name)
465
+ if name in ['_ShadowColor', '_RimColor', '_OutlineColor']:
466
+ target_slots.append(slot)
467
+ else:
468
+ target_slots.append(active_slot)
469
+
470
+ for slot in mate.texture_slots:
471
+ if not slot: continue
472
+ name = common.remove_serial_number(slot.texture.name)
473
+ if name == '_MainTex':
474
+ img = slot.texture.image
475
+ if img:
476
+ if len(img.pixels):
477
+ break
478
+ else:
479
+ img = me.uv_textures.active.data[0].image
480
+
481
+ sample_count = 10
482
+ img_width, img_height, img_channel = img.size[0], img.size[1], img.channels
483
+
484
+ bm = bmesh.new()
485
+ bm.from_mesh(me)
486
+ uv_lay = bm.loops.layers.uv.active
487
+ uvs = [l[uv_lay].uv[:] for f in bm.faces if f.material_index == ob.active_material_index for l in f.loops]
488
+ bm.free()
489
+
490
+ average_color = mathutils.Color([0, 0, 0])
491
+ seek_interval = len(uvs) / sample_count
492
+ for sample_index in range(sample_count):
493
+
494
+ uv_index = int(seek_interval * sample_index)
495
+ x, y = uvs[uv_index]
496
+ x, y = int(x * img_width), int(y * img_height)
497
+
498
+ pixel_index = ((y * img_width) + x) * img_channel
499
+ color = mathutils.Color(img.pixels[pixel_index:pixel_index+3])
500
+
501
+ average_color += color
502
+ average_color /= sample_count
503
+ average_color.s *= self.saturation_multi
504
+ average_color.v *= self.value_multi
505
+
506
+ for slot in target_slots:
507
+ slot.color = average_color[:3]
508
+ common.set_texture_color(slot)
509
+
510
+ return {'FINISHED'}
511
+
512
+ class quick_export_cm3d2_tex(bpy.types.Operator):
513
+ bl_idname = 'image.quick_export_cm3d2_tex'
514
+ bl_label = "Export As .tex"
515
+ bl_description = "Save image as a .tex for CM3D2."
516
+ bl_options = {'REGISTER'}
517
+
518
+ def execute(self, context):
519
+ import os.path
520
+
521
+ try:
522
+ slot = context.texture_slot
523
+ tex = context.texture
524
+ img = tex.image
525
+ img.pixels[0]
526
+ except:
527
+ self.report(type={'ERROR'}, message="Mission failed.")
528
+ return {'CANCELLED'}
529
+
530
+ override = context.copy()
531
+ override['edit_image'] = img
532
+ filepath = os.path.splitext( bpy.path.abspath(img.filepath) )[0] + ".tex"
533
+ path = "assets/texture/texture/" + os.path.basename( bpy.path.abspath(img.filepath) )
534
+ if 'cm3d2_path' in img:
535
+ path = img['cm3d2_path']
536
+ if os.path.exists(filepath):
537
+ file = open(filepath, 'rb')
538
+ header_ext = common.read_str(file)
539
+ if header_ext == 'CM3D2_TEX':
540
+ file.seek(4, 1)
541
+ path = common.read_str(file)
542
+ file.close()
543
+ bpy.ops.image.export_cm3d2_tex(override, filepath=filepath, path=path)
544
+
545
+ self.report(type={'INFO'}, message="Texture has been saved as data in the same folder. Mission Accomplished")
546
+ return {'FINISHED'}
547
+
548
+ class set_color_value(bpy.types.Operator):
549
+ bl_idname = 'texture.set_color_value'
550
+ bl_label = "Set the Color setting Value"
551
+ bl_description = "Set the Color type of setting Value"
552
+ bl_options = {'REGISTER', 'UNDO'}
553
+
554
+ color = bpy.props.FloatVectorProperty(name="Color", default=(0, 0, 0, 0), subtype='COLOR', size=4)
555
+
556
+ @classmethod
557
+ def poll(cls, context):
558
+ if 'texture_slot' in dir(context) and 'texture' in dir(context):
559
+ if context.texture_slot and context.texture:
560
+ return True
561
+ return False
562
+
563
+ def execute(self, context):
564
+ slot = context.texture_slot
565
+ slot.color = self.color[:3]
566
+ slot.diffuse_color_factor = self.color[3]
567
+ common.set_texture_color(slot)
568
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_TEXT_HT_header.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「テキストエディター」エリア → ヘッダー
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ texts = bpy.data.texts
8
+ text_keys = texts.keys()
9
+ self.layout.label(text="For CM3D2:", icon_value=common.preview_collections['main']['KISS'].icon_id)
10
+ row = self.layout.row(align=True)
11
+ if 'BoneData' in text_keys:
12
+ txt = bpy.data.texts['BoneData']
13
+ line_count = 0
14
+ for line in txt.as_string().split('\n'):
15
+ if line:
16
+ line_count += 1
17
+ row.operator('text.show_text', icon='ARMATURE_DATA', text="BoneData (%d)" % line_count).name = 'BoneData'
18
+ if 'LocalBoneData' in text_keys:
19
+ txt = bpy.data.texts['LocalBoneData']
20
+ line_count = 0
21
+ for line in txt.as_string().split('\n'):
22
+ if line:
23
+ line_count += 1
24
+ row.operator('text.show_text', icon='BONE_DATA', text="LocalBoneData (%d)" % line_count).name = 'LocalBoneData'
25
+ if 'BoneData' in text_keys and 'LocalBoneData' in text_keys:
26
+ if 'BoneData' in texts:
27
+ if 'BaseBone' not in texts['BoneData']:
28
+ texts['BoneData']['BaseBone'] = ""
29
+ row.prop(texts['BoneData'], '["BaseBone"]', text="")
30
+ row.operator('text.copy_text_bone_data', icon='COPYDOWN', text="")
31
+ row.operator('text.paste_text_bone_data', icon='PASTEDOWN', text="")
32
+ if 'Material:0' in text_keys:
33
+ self.layout.label(text="", icon='MATERIAL_DATA')
34
+ row = self.layout.row(align=True)
35
+ pass_count = 0
36
+ for i in range(99):
37
+ name = "Material:" + str(i)
38
+ if name in text_keys:
39
+ sub_row = row.row(align=True)
40
+ sub_row.scale_x = 0.5
41
+ sub_row.operator('text.show_text', text=str(i)).name = name
42
+ else:
43
+ pass_count += 1
44
+ if 9 < pass_count:
45
+ break
46
+ if "Material:0" in text_keys:
47
+ row.operator('text.remove_all_material_texts', icon='X', text="")
48
+
49
+ class show_text(bpy.types.Operator):
50
+ bl_idname = 'text.show_text'
51
+ bl_label = "Display Text"
52
+ bl_description = "Displays the specified text in this area"
53
+ bl_options = {'REGISTER', 'UNDO'}
54
+
55
+ name = bpy.props.StringProperty(name="Text name")
56
+
57
+ @classmethod
58
+ def poll(cls, context):
59
+ if 'text' in dir(context.space_data):
60
+ return True
61
+ return False
62
+
63
+ def execute(self, context):
64
+ context.space_data.text = bpy.data.texts[self.name]
65
+ return {'FINISHED'}
66
+
67
+ class copy_text_bone_data(bpy.types.Operator):
68
+ bl_idname = 'text.copy_text_bone_data'
69
+ bl_label = "Copy the Bone Data in the text"
70
+ bl_description = "Bone data is copied to clipboard so it can be pasted in the custom properties."
71
+ bl_options = {'REGISTER', 'UNDO'}
72
+
73
+ @classmethod
74
+ def poll(cls, context):
75
+ texts = context.blend_data.texts
76
+ return 'BoneData' in texts and 'LocalBoneData' in texts
77
+
78
+ def execute(self, context):
79
+ output_text = ""
80
+ if 'BaseBone' in context.blend_data.texts['BoneData']:
81
+ output_text += "BaseBone:" + context.blend_data.texts['BoneData']['BaseBone'] + "\n"
82
+ for line in context.blend_data.texts['BoneData'].as_string().split('\n'):
83
+ if not line:
84
+ continue
85
+ output_text += "BoneData:" + line + "\n"
86
+ for line in context.blend_data.texts['LocalBoneData'].as_string().split('\n'):
87
+ if not line:
88
+ continue
89
+ output_text += "LocalBoneData:" + line + "\n"
90
+ context.window_manager.clipboard = output_text
91
+ self.report(type={'INFO'}, message="Bonedata was copied, mission accomplished")
92
+ return {'FINISHED'}
93
+
94
+ class paste_text_bone_data(bpy.types.Operator):
95
+ bl_idname = 'text.paste_text_bone_data'
96
+ bl_label = "Paste Bone Data"
97
+ bl_description = "Paste Bone Data from clipboard into text editor."
98
+ bl_options = {'REGISTER', 'UNDO'}
99
+
100
+ @classmethod
101
+ def poll(cls, context):
102
+ clipboard = context.window_manager.clipboard
103
+ return 'BoneData:' in clipboard and 'LocalBoneData:' in clipboard
104
+
105
+ def execute(self, context):
106
+ import re
107
+ clipboard = context.window_manager.clipboard
108
+ if "BoneData" in context.blend_data.texts:
109
+ bone_data_text = context.blend_data.texts["BoneData"]
110
+ bone_data_text.clear()
111
+ else:
112
+ bone_data_text = context.blend_data.texts.new("BoneData")
113
+ if "LocalBoneData" in context.blend_data.texts:
114
+ local_bone_data_text = context.blend_data.texts["LocalBoneData"]
115
+ local_bone_data_text.clear()
116
+ else:
117
+ local_bone_data_text = context.blend_data.texts.new("LocalBoneData")
118
+
119
+ for line in context.window_manager.clipboard.split("\n"):
120
+ r = re.search('^BaseBone:(.+)$', line)
121
+ if r:
122
+ bone_data_text['BaseBone'] = r.groups()[0]
123
+ local_bone_data_text['BaseBone'] = r.groups()[0]
124
+ r = re.search('^BoneData:(.+)$', line)
125
+ if r:
126
+ if line.count(',') == 4:
127
+ info = r.groups()[0]
128
+ bone_data_text.write(info + "\n")
129
+ r = re.search('^LocalBoneData:(.+)$', line)
130
+ if r:
131
+ if line.count(',') == 1:
132
+ info = r.groups()[0]
133
+ local_bone_data_text.write(info + "\n")
134
+ bone_data_text.current_line_index = 0
135
+ local_bone_data_text.current_line_index = 0
136
+ self.report(type={'INFO'}, message="Bone Data was pasted, mission accomplished.")
137
+ return {'FINISHED'}
138
+
139
+ class remove_all_material_texts(bpy.types.Operator):
140
+ bl_idname = 'text.remove_all_material_texts'
141
+ bl_label = "Delete all .mate data"
142
+ bl_description = "Removes .mate data in the text editor"
143
+ bl_options = {'REGISTER', 'UNDO'}
144
+
145
+ is_keep_used_material = bpy.props.BoolProperty(name="Keep Used Materials", default=True)
146
+
147
+ @classmethod
148
+ def poll(cls, context):
149
+ return 'Material:0' in context.blend_data.texts
150
+
151
+ def invoke(self, context, event):
152
+ return context.window_manager.invoke_props_dialog(self)
153
+
154
+ def draw(self, context):
155
+ self.layout.prop(self, 'is_keep_used_material')
156
+
157
+ def execute(self, context):
158
+ remove_texts = []
159
+ pass_count = 0
160
+ for i in range(9999):
161
+ name = 'Material:' + str(i)
162
+ if name in context.blend_data.texts:
163
+ remove_texts.append(context.blend_data.texts[name])
164
+ else:
165
+ pass_count += 1
166
+ if 10 < pass_count:
167
+ break
168
+ if self.is_keep_used_material:
169
+ ob = context.active_object
170
+ if ob:
171
+ remove_texts = remove_texts[len(ob.material_slots):]
172
+ for txt in remove_texts:
173
+ context.blend_data.texts.remove(txt)
174
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_MT_edit_mesh_specials.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「3Dビュー」エリア → メッシュ編集モード → 「W」キー
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ icon_id = common.preview_collections['main']['KISS'].icon_id
8
+ self.layout.separator()
9
+ self.layout.operator('mesh.selected_mesh_vertex_group_blur', icon_value=icon_id)
10
+ self.layout.separator()
11
+ self.layout.operator('mesh.selected_face_sort_front', text="The drawing order of the selected surface is set to the forefront(?)", icon_value=icon_id).is_back = False
12
+ self.layout.operator('mesh.selected_face_sort_front', text="The drawing order of the selected surface is set to the backmost(?)", icon_value=icon_id).is_back = True
13
+
14
+ class selected_mesh_sort_front(bpy.types.Operator):
15
+ bl_idname = 'mesh.selected_face_sort_front'
16
+ bl_label = "The drawing order of the selected surface is set to the forefront(?)"
17
+ bl_description = "Rearranges the drawing order of the currently selected face to the front / back"
18
+ bl_options = {'REGISTER', 'UNDO'}
19
+
20
+ is_back = bpy.props.BoolProperty(name="Back")
21
+
22
+ @classmethod
23
+ def poll(cls, context):
24
+ ob = context.active_object
25
+ return ob.type == 'MESH'
26
+
27
+ def execute(self, context):
28
+ ob = context.active_object
29
+ if ob.mode != 'EDIT':
30
+ self.report(type={'ERROR'}, message="Please Run in Edit mode. Aborting.")
31
+ return {'CANCELLED'}
32
+ me = ob.data
33
+ bm = bmesh.from_edit_mesh(me)
34
+
35
+ bm.faces.ensure_lookup_table()
36
+
37
+ selected_face_indexs = []
38
+ other_face_indexs = []
39
+ for face in bm.faces:
40
+ if face.select:
41
+ selected_face_indexs.append(face.index)
42
+ else:
43
+ other_face_indexs.append(face.index)
44
+
45
+ output_face_indexs = []
46
+ if not self.is_back:
47
+ output_face_indexs = other_face_indexs + selected_face_indexs
48
+ else:
49
+ output_face_indexs = selected_face_indexs + other_face_indexs
50
+
51
+ for for_index, sorted_index in enumerate(output_face_indexs):
52
+ bm.faces[sorted_index].index = for_index
53
+
54
+ bm.faces.sort()
55
+ bmesh.update_edit_mesh(me)
56
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_MT_pose_apply.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「3Dビュー」エリア → ポーズモード → Ctrl+A (ポーズ → 適用)
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ self.layout.separator()
8
+ self.layout.operator('pose.apply_prime_field', icon_value=common.preview_collections['main']['KISS'].icon_id)
9
+
10
+ class apply_prime_field(bpy.types.Operator):
11
+ bl_idname = 'pose.apply_prime_field'
12
+ bl_label = "Apply Prime Field"
13
+ bl_description = "A body will be created that makes custom modeling easy with the current pose."
14
+ bl_options = {'REGISTER', 'UNDO'}
15
+
16
+ is_apply_armature_modifier = bpy.props.BoolProperty(name="Apply Armature Modifier", default=True)
17
+ is_deform_preserve_volume = bpy.props.BoolProperty(name="Conserve Volume", default=True)
18
+
19
+ @classmethod
20
+ def poll(cls, context):
21
+ ob = context.active_object
22
+ if ob:
23
+ if ob.type == 'ARMATURE':
24
+ return True
25
+ return False
26
+
27
+ def invoke(self, context, event):
28
+ return context.window_manager.invoke_props_dialog(self)
29
+
30
+ def draw(self, context):
31
+ self.layout.prop(self, 'is_apply_armature_modifier')
32
+ self.layout.prop(self, 'is_deform_preserve_volume')
33
+
34
+ def execute(self, context):
35
+ ob = context.active_object
36
+ arm = ob.data
37
+ pose = ob.pose
38
+
39
+ pre_selected_objects = context.selected_objects
40
+ pre_selected_pose_bones = context.selected_pose_bones
41
+ pre_mode = ob.mode
42
+ bpy.ops.object.mode_set(mode='OBJECT')
43
+ bpy.ops.object.select_all(action='DESELECT')
44
+ ob.select = True
45
+
46
+ if self.is_apply_armature_modifier:
47
+ for o in context.blend_data.objects:
48
+ if o.type == 'MESH' and len(o.modifiers):
49
+ is_applies = [False] * 32
50
+ for i, mod in enumerate(o.modifiers):
51
+ if mod.type == 'ARMATURE':
52
+ if mod.object and mod.object.name == ob.name:
53
+ is_applies[i] = True
54
+ if self.is_deform_preserve_volume:
55
+ mod.use_deform_preserve_volume = True
56
+ if any(is_applies):
57
+ override = context.copy()
58
+ override['object'], override['active_object'] = o, o
59
+ bpy.ops.object.forced_modifier_apply(override, is_applies=is_applies)
60
+
61
+ temp_ob = ob.copy()
62
+ temp_arm = arm.copy()
63
+ temp_ob.data = temp_arm
64
+ context.scene.objects.link(temp_ob)
65
+
66
+ context.scene.objects.active = temp_ob
67
+ bpy.ops.object.mode_set(mode='POSE')
68
+ bpy.ops.pose.select_all(action='SELECT')
69
+ bpy.ops.pose.transforms_clear()
70
+
71
+ context.scene.objects.active = ob
72
+ bpy.ops.object.mode_set(mode='POSE')
73
+ bpy.ops.pose.select_all(action='SELECT')
74
+ bpy.ops.pose.armature_apply()
75
+ bpy.ops.pose.constraints_clear()
76
+
77
+ consts = []
78
+ for bone in pose.bones:
79
+ const = bone.constraints.new('COPY_TRANSFORMS')
80
+ const.target = temp_ob
81
+ const.subtarget = bone.name
82
+ consts.append(const)
83
+
84
+ for i in range(10):
85
+ for const in consts:
86
+ const.mute = bool(i % 2)
87
+
88
+ if i % 2:
89
+ bpy.ops.pose.visual_transform_apply()
90
+ else:
91
+ bpy.ops.pose.transforms_clear()
92
+
93
+ for bone in pose.bones:
94
+ bone.keyframe_insert(data_path='location', frame=i)
95
+ bone.keyframe_insert(data_path='rotation_quaternion', frame=i)
96
+ bone.keyframe_insert(data_path='rotation_euler', frame=i)
97
+ bone.keyframe_insert(data_path='scale', frame=i)
98
+ bpy.ops.pose.constraints_clear()
99
+
100
+ common.remove_data(temp_arm)
101
+ common.remove_data(temp_ob)
102
+
103
+ bpy.ops.pose.select_all(action='DESELECT')
104
+ for bone in pre_selected_pose_bones:
105
+ arm.bones[bone.name].select = True
106
+
107
+ arm['is T Stance'] = 1
108
+
109
+ for o in pre_selected_objects:
110
+ o.select = True
111
+ context.scene.objects.active = ob
112
+ bpy.ops.object.mode_set(mode=pre_mode)
113
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_PT_tools_mesh_shapekey.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「3Dビュー」エリア → 「メッシュエディット」モード → ツールシェルフ → 「シェイプキーツール」パネル
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ """
6
+ class VIEW3D_PT_tools_mesh_shapekey(bpy.types.Panel):
7
+ bl_label = "Shape key tool"
8
+ bl_idname = 'VIEW3D_PT_tools_mesh_shapekey'
9
+ bl_region_type = 'TOOLS'
10
+ bl_space_type = 'VIEW_3D'
11
+ bl_category = 'Tools'
12
+ bl_context = 'mesh_edit'
13
+
14
+ def draw(self, context):
15
+ pass
16
+ """
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/misc_VIEW3D_PT_tools_weightpaint.py ADDED
@@ -0,0 +1,394 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 「3Dビュー」エリア → 「ウェイトペイント」モード → ツールシェルフ → 「ウェイトツール」パネル
2
+ import os, re, sys, bpy, time, bmesh, mathutils
3
+ from . import common
4
+
5
+ # メニュー等に項目追加
6
+ def menu_func(self, context):
7
+ icon_id = common.preview_collections['main']['KISS'].icon_id
8
+ box = self.layout.box()
9
+ column = box.column(align=False)
10
+ column.prop(context.active_object.data, 'use_paint_mask_vertex', icon='VERTEXSEL', text="Vertex selection mode")
11
+ column.operator('mesh.selected_mesh_vertex_group_blur', text="Blur the selected part", icon_value=icon_id)
12
+ column.operator('mesh.selected_mesh_vertex_group_calculation', text="Four arithmetic operation", icon_value=icon_id)
13
+
14
+ class selected_mesh_vertex_group_blur(bpy.types.Operator):
15
+ bl_idname = 'mesh.selected_mesh_vertex_group_blur'
16
+ bl_label = "Blur the vertex group of the selected part"
17
+ bl_description = "Blurs the vertex groups of the selected parts."
18
+ bl_options = {'REGISTER', 'UNDO'}
19
+
20
+ items = [
21
+ ('LINER', "Linear", "", 'LINCURVE', 1),
22
+ ('TRIGONOMETRIC', "Trigonometric", "", 'SMOOTHCURVE', 2),
23
+ ]
24
+ smooth_method = bpy.props.EnumProperty(items=items, name="Damping type", default='TRIGONOMETRIC')
25
+
26
+ selection_blur_range_multi = bpy.props.FloatProperty(name="Blur Range", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
27
+ selection_blur_accuracy = bpy.props.IntProperty(name="Blur Accuracy", default=3, min=0, max=10, soft_min=1, soft_max=10)
28
+
29
+ items = [
30
+ ('ALL', "All", "", 'COLLAPSEMENU', 1),
31
+ ('ACTIVE', "Active", "", 'LAYER_ACTIVE', 2),
32
+ ]
33
+ target_vertex_group = bpy.props.EnumProperty(items=items, name="Target vertex groups", default='ALL')
34
+ items = [
35
+ ('NORMAL', "Normal", "", 'BRUSH_BLUR', 1),
36
+ ('ADD', "Add", "", 'BRUSH_DARKEN', 2),
37
+ ('SUB', "Sub", "", 'BRUSH_LIGHTEN', 3),
38
+ ]
39
+ blur_mode = bpy.props.EnumProperty(items=items, name="Blur Mode", default='NORMAL')
40
+ blur_range_multi = bpy.props.FloatProperty(name="Blur Range", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
41
+ blur_count = bpy.props.IntProperty(name="Blur Amount", default=1, min=1, max=100, soft_min=1, soft_max=100)
42
+ is_vertex_group_limit_total = bpy.props.BoolProperty(name="Limit total weights.", default=True)
43
+
44
+ @classmethod
45
+ def poll(cls, context):
46
+ ob = context.active_object
47
+ if ob.type == 'MESH':
48
+ if len(ob.vertex_groups):
49
+ return len(ob.data.vertices) and len(ob.data.edges)
50
+ return False
51
+
52
+ def invoke(self, context, event):
53
+ return context.window_manager.invoke_props_dialog(self)
54
+
55
+ def draw(self, context):
56
+ self.layout.prop(self, 'smooth_method')
57
+
58
+ self.layout.label(text="Blur Selected", icon='UV_SYNC_SELECT')
59
+ self.layout.prop(self, 'selection_blur_range_multi', text="Range | Average of side lengths ×")
60
+ self.layout.prop(self, 'selection_blur_accuracy', text="Accuracy (number of steps)")
61
+
62
+ self.layout.label(text="Blur Vertex Group", icon='GROUP_VERTEX')
63
+ self.layout.prop(self, 'target_vertex_group', text="Target Group")
64
+ self.layout.prop(self, 'blur_mode', text="Mode")
65
+ self.layout.prop(self, 'blur_range_multi', text="Range | Average of side lengths ×")
66
+ self.layout.prop(self, 'blur_count', text="Blur Count")
67
+ self.layout.prop(self, 'is_vertex_group_limit_total', icon='IMGDISPLAY')
68
+
69
+ def execute(self, context):
70
+ class EmptyClass: pass
71
+
72
+ ob = context.active_object
73
+ me = ob.data
74
+
75
+ pre_mode = ob.mode
76
+ bpy.ops.object.mode_set(mode='OBJECT')
77
+
78
+ pre_selected_objects = context.selected_objects[:]
79
+ for selected_object in pre_selected_objects:
80
+ selected_object.select = False
81
+ ob.select = True
82
+
83
+ bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
84
+
85
+ selection_ob = context.active_object
86
+ selection_me = selection_ob.data
87
+
88
+ for v in selection_me.vertices:
89
+ if v.hide: v.hide, v.select = False, False
90
+ for e in selection_me.edges:
91
+ if e.hide: e.hide, e.select = False, False
92
+ for p in selection_me.polygons:
93
+ if p.hide: p.hide, p.select = False, False
94
+
95
+ bpy.ops.object.mode_set(mode='EDIT')
96
+ bpy.ops.mesh.select_all(action='INVERT')
97
+ if context.tool_settings.mesh_select_mode[0]:
98
+ bpy.ops.mesh.delete(type='VERT')
99
+ elif context.tool_settings.mesh_select_mode[1]:
100
+ bpy.ops.mesh.delete(type='EDGE')
101
+ elif context.tool_settings.mesh_select_mode[2]:
102
+ bpy.ops.mesh.delete(type='FACE')
103
+ bpy.ops.mesh.select_all(action='SELECT')
104
+ if 1 <= self.selection_blur_accuracy:
105
+ bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadtri=False, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0)
106
+ bpy.ops.object.mode_set(mode='OBJECT')
107
+
108
+ selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
109
+ [selection_kd.insert(v.co, v.index) for v in selection_me.vertices]
110
+ selection_kd.balance()
111
+ common.remove_data([selection_ob, selection_me])
112
+
113
+ ob.select = True
114
+ context.scene.objects.active = ob
115
+
116
+ bm = bmesh.new()
117
+ bm.from_mesh(me)
118
+ edge_lengths = [e.calc_length() for e in bm.edges]
119
+ bm.free()
120
+ edge_lengths.sort()
121
+ edge_lengths_center_index = int( (len(edge_lengths) - 1) * 0.5 )
122
+ average_edge_length = edge_lengths[edge_lengths_center_index]
123
+ selection_blur_range = average_edge_length * self.selection_blur_range_multi
124
+
125
+ vert_selection_values = [None for v in me.vertices]
126
+ for vert in me.vertices:
127
+ co, index, dist = selection_kd.find(vert.co)
128
+ if dist <= selection_blur_range + 0.00001:
129
+ if 0 < selection_blur_range:
130
+ if self.smooth_method == 'TRIGONOMETRIC':
131
+ value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
132
+ else:
133
+ value = 1.0 - (dist / selection_blur_range)
134
+ vert_selection_values[vert.index] = value
135
+ else:
136
+ vert_selection_values[vert.index] = 1.0
137
+
138
+ """
139
+ # 頂点カラーで選択状態を確認
140
+ preview_vertex_color = me.vertex_colors.new()
141
+ for loop in me.loops:
142
+ v = vert_selection_values[loop.vertex_index]
143
+ if v != None:
144
+ preview_vertex_color.data[loop.index].color = (v, v, v)
145
+ else:
146
+ preview_vertex_color.data[loop.index].color = (0, 0, 0)
147
+ """
148
+
149
+ kd = mathutils.kdtree.KDTree(len(me.vertices))
150
+ [kd.insert(v.co, v.index) for v in me.vertices]
151
+ kd.balance()
152
+
153
+ blur_range = average_edge_length * self.blur_range_multi
154
+
155
+ for i in range(self.blur_count):
156
+
157
+ pre_vert_weights = [[0.0 for vg in ob.vertex_groups] for v in me.vertices]
158
+ for vert in me.vertices:
159
+ for vge in vert.groups:
160
+ pre_vert_weights[vert.index][vge.group] = vge.weight
161
+
162
+ for vert in me.vertices:
163
+ selection_value = vert_selection_values[vert.index]
164
+ if selection_value == None: continue
165
+
166
+ near_infos = []
167
+ total_effect = 0.0
168
+ for co, index, dist in kd.find_range(vert.co, blur_range):
169
+ ec = EmptyClass()
170
+ ec.index = index
171
+ if 0 < blur_range:
172
+ raw_effect = 1.0 - (dist / blur_range)
173
+ if self.smooth_method == 'TRIGONOMETRIC': ec.effect = common.trigonometric_smooth(raw_effect)
174
+ else: ec.effect = raw_effect
175
+ else:
176
+ ec.effect = 1.0
177
+ total_effect += ec.effect
178
+ near_infos.append(ec)
179
+
180
+ new_vert_weight = [0.0 for vg in ob.vertex_groups]
181
+ for ec in near_infos:
182
+ pre_vert_weight = pre_vert_weights[ec.index]
183
+ weight_multi = ec.effect / total_effect
184
+ for vg_index, near_vert_pre_weight_value in enumerate(pre_vert_weight):
185
+ current_vert_pre_weight_value = pre_vert_weights[vert.index][vg_index]
186
+
187
+ if self.blur_mode == 'NORMAL':
188
+ send_weight_value = near_vert_pre_weight_value
189
+ elif self.blur_mode == 'ADD':
190
+ if current_vert_pre_weight_value < near_vert_pre_weight_value:
191
+ send_weight_value = near_vert_pre_weight_value
192
+ else:
193
+ send_weight_value = current_vert_pre_weight_value
194
+ elif self.blur_mode == 'SUB':
195
+ if near_vert_pre_weight_value < current_vert_pre_weight_value:
196
+ send_weight_value = near_vert_pre_weight_value
197
+ else:
198
+ send_weight_value = current_vert_pre_weight_value
199
+
200
+ new_vert_weight[vg_index] += send_weight_value * weight_multi
201
+
202
+ for vg in ob.vertex_groups:
203
+ if self.target_vertex_group == 'ACTIVE' and ob.vertex_groups.active.name != vg.name: continue
204
+ if vg.lock_weight: continue
205
+
206
+ pre_weight = pre_vert_weights[vert.index][vg.index]
207
+ new_weight = new_vert_weight[vg.index]
208
+ result_weight = (pre_weight * (1.0 - selection_value)) + (new_weight * selection_value)
209
+
210
+ if 0.0 < result_weight:
211
+ vg.add([vert.index], result_weight, 'REPLACE')
212
+ else:
213
+ vg.remove([vert.index])
214
+
215
+ if self.is_vertex_group_limit_total:
216
+ bpy.ops.object.vertex_group_limit_total(group_select_mode='ALL', limit=4)
217
+
218
+ bpy.ops.object.mode_set(mode=pre_mode)
219
+ for selected_object in pre_selected_objects:
220
+ selected_object.select = True
221
+ return {'FINISHED'}
222
+
223
+ class selected_mesh_vertex_group_calculation(bpy.types.Operator):
224
+ bl_idname = 'mesh.selected_mesh_vertex_group_calculation'
225
+ bl_label = "Four arithmetic operations on the vertex groups of the selection"
226
+ bl_description = "Applies four arithmetic operations to the vertex groups of selection."
227
+ bl_options = {'REGISTER', 'UNDO'}
228
+
229
+ items = [
230
+ ('LINER', "Iinear", "", 'LINCURVE', 1),
231
+ ('TRIGONOMETRIC', "Trigonometric", "", 'SMOOTHCURVE', 2),
232
+ ]
233
+ smooth_method = bpy.props.EnumProperty(items=items, name="Smooth Methid", default='TRIGONOMETRIC')
234
+
235
+ selection_blur_range_multi = bpy.props.FloatProperty(name="Blur Range", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
236
+ selection_blur_accuracy = bpy.props.IntProperty(name="Blur Accuracy", default=3, min=0, max=10, soft_min=1, soft_max=10)
237
+
238
+ items = [
239
+ ('ACTIVE', "Active", "", 'LAYER_ACTIVE', 1),
240
+ ]
241
+ target_vertex_group = bpy.props.EnumProperty(items=items, name="Target Vertex Group", default='ACTIVE')
242
+ items = [
243
+ ('ADD', "Add", "", 'ZOOMIN', 1),
244
+ ('SUB', "Sub", "", 'ZOOMOUT', 2),
245
+ ('MULTI', "Multi", "", 'X', 3),
246
+ ('DIV', "Div", "", 'FULLSCREEN_EXIT', 4),
247
+ ]
248
+ calculation_mode = bpy.props.EnumProperty(items=items, name="Arithmetic operation mode", default='ADD')
249
+ calculation_value = bpy.props.FloatProperty(name="Value", default=1.0, min=-100.0, max=100.0, soft_min=-100.0, soft_max=100.0, step=10, precision=1)
250
+
251
+ @classmethod
252
+ def poll(cls, context):
253
+ ob = context.active_object
254
+ if ob.type == 'MESH':
255
+ return bool(len(ob.vertex_groups))
256
+ return False
257
+
258
+ def draw(self, context):
259
+ self.layout.label(text="Blur the selection of the vertex groups.", icon='UV_SYNC_SELECT')
260
+ self.layout.prop(self, 'smooth_method')
261
+ self.layout.prop(self, 'selection_blur_range_multi', text="Range | Average of side length ×")
262
+ self.layout.prop(self, 'selection_blur_accuracy', text="Accuracy (Steps)")
263
+
264
+ self.layout.label(text="Four arithmetic operations", icon='BRUSH_ADD')
265
+ self.layout.prop(self, 'target_vertex_group', text="Target Group")
266
+ self.layout.prop(self, 'calculation_mode', text="Mode")
267
+ self.layout.prop(self, 'calculation_value', text="Value")
268
+
269
+ calculation_text = "Expression: Original weight "
270
+ if self.calculation_mode == 'ADD': calculation_text += "+"
271
+ elif self.calculation_mode == 'SUB': calculation_text += "-"
272
+ elif self.calculation_mode == 'MULTI': calculation_text += "×"
273
+ elif self.calculation_mode == 'DIV': calculation_text += "÷"
274
+ calculation_text += " " + str(round(self.calculation_value, 1))
275
+ self.layout.label(text=calculation_text)
276
+
277
+ def execute(self, context):
278
+ class EmptyClass: pass
279
+
280
+ if self.calculation_mode == 'DIV' and self.calculation_value == 0.0:
281
+ self.report(type={'ERROR'}, message="Cannot divide by zero, Aborting.")
282
+ return {'CANCELLED'}
283
+
284
+ ob = context.active_object
285
+ me = ob.data
286
+
287
+ pre_mode = ob.mode
288
+ bpy.ops.object.mode_set(mode='OBJECT')
289
+
290
+ pre_selected_objects = context.selected_objects[:]
291
+ for selected_object in pre_selected_objects:
292
+ selected_object.select = False
293
+ ob.select = True
294
+
295
+ bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
296
+
297
+ selection_ob = context.active_object
298
+ selection_me = selection_ob.data
299
+
300
+ for v in selection_me.vertices:
301
+ if v.hide: v.hide, v.select = False, False
302
+ for e in selection_me.edges:
303
+ if e.hide: e.hide, e.select = False, False
304
+ for p in selection_me.polygons:
305
+ if p.hide: p.hide, p.select = False, False
306
+
307
+ bpy.ops.object.mode_set(mode='EDIT')
308
+ bpy.ops.mesh.select_all(action='INVERT')
309
+ if context.tool_settings.mesh_select_mode[0]:
310
+ bpy.ops.mesh.delete(type='VERT')
311
+ elif context.tool_settings.mesh_select_mode[1]:
312
+ bpy.ops.mesh.delete(type='EDGE')
313
+ elif context.tool_settings.mesh_select_mode[2]:
314
+ bpy.ops.mesh.delete(type='FACE')
315
+ bpy.ops.mesh.select_all(action='SELECT')
316
+ if 1 <= self.selection_blur_accuracy:
317
+ bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadtri=False, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0)
318
+ bpy.ops.object.mode_set(mode='OBJECT')
319
+
320
+ selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
321
+ [selection_kd.insert(v.co, v.index) for v in selection_me.vertices]
322
+ selection_kd.balance()
323
+ common.remove_data([selection_ob, selection_me])
324
+
325
+ ob.select = True
326
+ context.scene.objects.active = ob
327
+
328
+ bm = bmesh.new()
329
+ bm.from_mesh(me)
330
+ edge_lengths = [e.calc_length() for e in bm.edges]
331
+ bm.free()
332
+ edge_lengths.sort()
333
+ edge_lengths_center_index = int( (len(edge_lengths) - 1) * 0.5 )
334
+ average_edge_length = edge_lengths[edge_lengths_center_index]
335
+ selection_blur_range = average_edge_length * self.selection_blur_range_multi
336
+
337
+ vert_selection_values = [None for v in me.vertices]
338
+ for vert in me.vertices:
339
+ co, index, dist = selection_kd.find(vert.co)
340
+ if dist <= selection_blur_range + 0.00001:
341
+ if 0 < selection_blur_range:
342
+ if self.smooth_method == 'TRIGONOMETRIC':
343
+ value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
344
+ else:
345
+ value = 1.0 - (dist / selection_blur_range)
346
+ vert_selection_values[vert.index] = value
347
+ else:
348
+ vert_selection_values[vert.index] = 1.0
349
+
350
+ """
351
+ # 頂点カラーで選択状態を確認
352
+ preview_vertex_color = me.vertex_colors.new()
353
+ for loop in me.loops:
354
+ v = vert_selection_values[loop.vertex_index]
355
+ if v != None:
356
+ preview_vertex_color.data[loop.index].color = (v, v, v)
357
+ else:
358
+ preview_vertex_color.data[loop.index].color = (0, 0, 0)
359
+ """
360
+
361
+ for vert in me.vertices:
362
+ effect = vert_selection_values[vert.index]
363
+ if effect == None: continue
364
+
365
+ pre_vert_weight = 0.0
366
+ for vge in vert.groups:
367
+ if ob.vertex_groups.active.index == vge.group:
368
+ pre_vert_weight = vge.weight
369
+
370
+ if self.calculation_mode == 'ADD':
371
+ new_vert_weight = pre_vert_weight + self.calculation_value
372
+ elif self.calculation_mode == 'SUB':
373
+ new_vert_weight = pre_vert_weight - self.calculation_value
374
+ elif self.calculation_mode == 'MULTI':
375
+ new_vert_weight = pre_vert_weight * self.calculation_value
376
+ elif self.calculation_mode == 'DIV':
377
+ new_vert_weight = pre_vert_weight / self.calculation_value
378
+
379
+ if new_vert_weight < 0.0:
380
+ new_vert_weight = 0.0
381
+ elif 1.0 < new_vert_weight:
382
+ new_vert_weight = 1.0
383
+
384
+ new_vert_weight = (pre_vert_weight * (1.0 - effect)) + (new_vert_weight * effect)
385
+
386
+ if 0.0 < new_vert_weight:
387
+ ob.vertex_groups.active.add([vert.index], new_vert_weight, 'REPLACE')
388
+ else:
389
+ ob.vertex_groups.active.remove([vert.index])
390
+
391
+ bpy.ops.object.mode_set(mode=pre_mode)
392
+ for selected_object in pre_selected_objects:
393
+ selected_object.select = True
394
+ return {'FINISHED'}
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/model_export.py ADDED
@@ -0,0 +1,849 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bpy, bmesh, mathutils
2
+ import os, re, struct, time, math
3
+ from operator import itemgetter
4
+ from . import common
5
+
6
+
7
+
8
+ # メインオペレーター
9
+ class export_cm3d2_model(bpy.types.Operator):
10
+ bl_idname = 'export_mesh.export_cm3d2_model'
11
+ bl_label = "CM3D2 Model (.model)"
12
+ bl_description = "Will export a mesh in CM3D2 .Model Format."
13
+ bl_options = {'REGISTER'}
14
+
15
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
16
+ filename_ext = ".model"
17
+ filter_glob = bpy.props.StringProperty(default="*.model", options={'HIDDEN'})
18
+
19
+ scale = bpy.props.FloatProperty(name="Scale", default=0.2, min=0.01, max=100, soft_min=0.01, soft_max=100, step=10, precision=2, description="How the mesh will be scaled at the time of export.")
20
+
21
+ is_backup = bpy.props.BoolProperty(name="Backup", default=True, description="Will backup any previous files with the same name.")
22
+
23
+ version = bpy.props.IntProperty(name="Version", default=1000, min=1000, max=1111, soft_min=1000, soft_max=1111, step=1)
24
+ model_name = bpy.props.StringProperty(name="Model Name", default="*")
25
+ base_bone_name = bpy.props.StringProperty(name="Base Bone Name", default="*")
26
+
27
+ items = [
28
+ ('ARMATURE', "Armature", "", 'OUTLINER_OB_ARMATURE', 1),
29
+ ('TEXT', "Text", "", 'FILE_TEXT', 2),
30
+ ('OBJECT_PROPERTY', "Object Data", "", 'OBJECT_DATAMODE', 3),
31
+ ('ARMATURE_PROPERTY', "Armature Data", "", 'ARMATURE_DATA', 4),
32
+ ]
33
+ bone_info_mode = bpy.props.EnumProperty(items=items, name="Bone Data Source", default='OBJECT_PROPERTY', description="This will decide from where the Bone Data is gathered from.")
34
+
35
+ items = [
36
+ ('TEXT', "Text", "", 'FILE_TEXT', 1),
37
+ ('MATERIAL', "Material", "", 'MATERIAL', 2),
38
+ ]
39
+ mate_info_mode = bpy.props.EnumProperty(items=items, name="Material Source", default='MATERIAL', description="This will decide from where the Material Data is gathered from.")
40
+
41
+ is_arrange_name = bpy.props.BoolProperty(name="Delete Duplicate Name Numbers", default=True, description="This will delete the numbers that are added to duplicate names such as [.001]")
42
+
43
+ is_convert_tris = bpy.props.BoolProperty(name="Triangulate", default=True, description="Will triangulate any none triangular faces.")
44
+ is_normalize_weight = bpy.props.BoolProperty(name="Normalize Weights", default=True, description="Will normalize all Vertex Weights so that the sum of the weights on a single vertex is equal to 1.")
45
+ is_convert_bone_weight_names = bpy.props.BoolProperty(name="Convert Vertex Groups for CM3D2", default=True, description="This will change the vertex group names to CM3D2's format if it is in Blenders format.")
46
+ is_apply_modifiers = bpy.props.BoolProperty(name="Apply Modifiers", default=False)
47
+ custom_normal_blend = bpy.props.FloatProperty(name="CM3D2 Blending Ratio", default=0.5, min=0, max=1, soft_min=0, soft_max=1, step=3, precision=0)
48
+
49
+ is_batch = bpy.props.BoolProperty(name="Batch Mode", default=False, description="We do not switch modes or select error locations.[?]")
50
+
51
+ @classmethod
52
+ def poll(cls, context):
53
+ ob = context.active_object
54
+ if ob:
55
+ if ob.type == 'MESH':
56
+ return True
57
+ return False
58
+
59
+ def report_cancel(self, report_message, report_type={'ERROR'}, resobj={'CANCELLED'}):
60
+ """エラーメッセージを出力してキャンセルオブジェクトを返す"""
61
+ self.report(type=report_type, message=report_message)
62
+ return resobj
63
+
64
+
65
+ def precheck(self, context):
66
+ """データの成否チェック"""
67
+ ob = context.active_object
68
+ if not ob:
69
+ return self.report_cancel("There is no Active Object.")
70
+ if ob.type != 'MESH':
71
+ return self.report_cancel("Please select the mesh first.")
72
+ if not len(ob.material_slots):
73
+ return self.report_cancel("There is no material.")
74
+ for slot in ob.material_slots:
75
+ if not slot.material:
76
+ return self.report_cancel("Please Delete the empty Material Slot")
77
+ try:
78
+ slot.material['shader1']
79
+ slot.material['shader2']
80
+ except:
81
+ return self.report_cancel("Please add [shader 1] and [shader 2] to the material")
82
+ me = ob.data
83
+ if not me.uv_layers.active:
84
+ return self.report_cancel("There is no UV")
85
+ if 65535 < len(me.vertices):
86
+ return self.report_cancel("Too many Vertices. Please reduce to at least 65535")
87
+ return None
88
+
89
+
90
+ def invoke(self, context, event):
91
+ res = self.precheck(context)
92
+ if res: return res
93
+ ob = context.active_object
94
+
95
+ # model名とか
96
+ ob_names = common.remove_serial_number(ob.name, self.is_arrange_name).split('.')
97
+ self.model_name = ob_names[0]
98
+ self.base_bone_name = ob_names[1] if 2 <= len(ob_names) else 'Auto'
99
+
100
+ # ボーン情報元のデフォルトオプションを取得
101
+ if "BoneData" in context.blend_data.texts:
102
+ if "LocalBoneData" in context.blend_data.texts:
103
+ self.bone_info_mode = 'TEXT'
104
+ if "BoneData:0" in ob:
105
+ if "LocalBoneData:0" in ob:
106
+ self.bone_info_mode = 'OBJECT_PROPERTY'
107
+ arm_ob = ob.parent
108
+ if arm_ob:
109
+ if arm_ob.type == 'ARMATURE':
110
+ self.bone_info_mode = 'ARMATURE_PROPERTY'
111
+ else:
112
+ for mod in ob.modifiers:
113
+ if mod.type == 'ARMATURE':
114
+ if mod.object:
115
+ self.bone_info_mode = 'ARMATURE_PROPERTY'
116
+ break
117
+
118
+ # エクスポート時のデフォルトパスを取得
119
+ if common.preferences().model_default_path:
120
+ self.filepath = common.default_cm3d2_dir(common.preferences().model_default_path, self.model_name, "model")
121
+ else:
122
+ self.filepath = common.default_cm3d2_dir(common.preferences().model_export_path, self.model_name, "model")
123
+
124
+ # バックアップ関係
125
+ self.is_backup = bool(common.preferences().backup_ext)
126
+
127
+ self.scale = 1.0 / common.preferences().scale
128
+ context.window_manager.fileselect_add(self)
129
+ return {'RUNNING_MODAL'}
130
+
131
+
132
+ # 'is_batch' がオンなら非表示
133
+ def draw(self, context):
134
+ self.layout.prop(self, 'scale')
135
+ row = self.layout.row()
136
+ row.prop(self, 'is_backup', icon='FILE_BACKUP')
137
+ if not common.preferences().backup_ext:
138
+ row.enabled = False
139
+ self.layout.prop(self, 'is_arrange_name', icon='SAVE_AS')
140
+ box = self.layout.box()
141
+ box.prop(self, 'version', icon='LINENUMBERS_ON')
142
+ box.prop(self, 'model_name', icon='SORTALPHA')
143
+
144
+ row = box.row()
145
+ row.prop(self, 'base_bone_name', icon='CONSTRAINT_BONE')
146
+ if self.base_bone_name == 'Auto':
147
+ row.enabled = False
148
+
149
+ box = self.layout.box()
150
+ col = box.column(align=True)
151
+ col.label(text="Bone Data Source", icon='BONE_DATA')
152
+ col.prop(self, 'bone_info_mode', icon='BONE_DATA', expand=True)
153
+ col = box.column(align=True)
154
+ col.label(text="Material Source", icon='MATERIAL')
155
+ col.prop(self, 'mate_info_mode', icon='MATERIAL', expand=True)
156
+ box = self.layout.box()
157
+ box.label("Triangulate")
158
+ box.prop(self, 'is_convert_tris', icon='MESH_DATA')
159
+ sub_box = box.box()
160
+ sub_box.prop(self, 'is_normalize_weight', icon='MOD_VERTEX_WEIGHT')
161
+ sub_box.prop(self, 'is_convert_bone_weight_names', icon_value=common.preview_collections['main']['KISS'].icon_id)
162
+ sub_box = box.box()
163
+ sub_box.prop(self, 'is_apply_modifiers', icon='MODIFIER')
164
+ row = sub_box.row()
165
+ row.prop(self, 'custom_normal_blend', icon='SNAP_NORMAL', slider=True)
166
+ row.enabled = self.is_apply_modifiers
167
+
168
+
169
+ def execute(self, context):
170
+ """モデルファイルを出力"""
171
+ start_time = time.time()
172
+
173
+ if not self.is_batch:
174
+ common.preferences().model_export_path = self.filepath
175
+ common.preferences().scale = 1.0 / self.scale
176
+ bpy.ops.object.mode_set(mode='OBJECT')
177
+
178
+
179
+ context.window_manager.progress_begin(0, 10)
180
+ context.window_manager.progress_update(0)
181
+
182
+ res = self.precheck(context)
183
+ if res: return res
184
+
185
+ ob = context.active_object
186
+ me = ob.data
187
+
188
+ if ob.active_shape_key_index != 0:
189
+ ob.active_shape_key_index = 0
190
+ me.update()
191
+
192
+ # モディファイアを適用する場合
193
+ if self.is_apply_modifiers:
194
+ new_ob = ob.copy()
195
+ new_me = ob.data.copy()
196
+ new_ob.data = new_me
197
+ context.scene.objects.link(new_ob)
198
+ context.scene.objects.active = new_ob
199
+ new_ob.select = True
200
+
201
+ source_ob = ob
202
+ source_me = me
203
+ ob = new_ob
204
+ me = new_me
205
+
206
+ bpy.ops.object.forced_modifier_apply(is_applies=[True for i in range(32)], custom_normal_blend=self.custom_normal_blend)
207
+
208
+ # データの成否チェック
209
+ if self.bone_info_mode == 'ARMATURE':
210
+ arm_ob = ob.parent
211
+ if arm_ob and arm_ob.type != 'ARMATURE':
212
+ return self.report_cancel("The parent of the mesh object is not an armature")
213
+ if not arm_ob:
214
+ try:
215
+ arm_ob = next(mod for mod in ob.modifiers if mod.type == 'ARMATURE' and mod.object)
216
+ except StopIteration:
217
+ return self.report_cancel("Armature not found, please make it parent or modifier")
218
+ arm_ob = arm_ob.object
219
+ elif self.bone_info_mode == 'TEXT':
220
+ if "BoneData" not in context.blend_data.texts:
221
+ return self.report_cancel("BoneData in Text cannot be found. Aborting.")
222
+ if "LocalBoneData" not in context.blend_data.texts:
223
+ return self.report_cancel("Text 'LocalBoneData' can not be found, aborted")
224
+ elif self.bone_info_mode == 'OBJECT_PROPERTY':
225
+ if "BoneData:0" not in ob:
226
+ return self.report_cancel("There is no BoneData in the custom properties of the object")
227
+ if "LocalBoneData:0" not in ob:
228
+ return self.report_cancel("There is no LocalBoneData in the custom properties of the object")
229
+ elif self.bone_info_mode == 'ARMATURE_PROPERTY':
230
+ arm_ob = ob.parent
231
+ if arm_ob and arm_ob.type != 'ARMATURE':
232
+ return self.report_cancel("The Parent of the Mesh object is not an Armature")
233
+ if not arm_ob:
234
+ try:
235
+ arm_ob = next(mod for mod in ob.modifiers if mod.type == 'ARMATURE' and mod.object)
236
+ except StopIteration:
237
+ return self.report_cancel("Armature not found. Please parent the Armature to the mesh or add an Armature modifier with the corresponding Armature.")
238
+ arm_ob = arm_ob.object
239
+ if "BoneData:0" not in arm_ob.data:
240
+ return self.report_cancel("There is no BoneData in the custom properties of the Armature.")
241
+ if "LocalBoneData:0" not in arm_ob.data:
242
+ return self.report_cancel("There is no Local BoneData in the custom properties of the Armature.")
243
+ else:
244
+ return self.report_cancel("The bone Information source is not working? Please choose another.")
245
+
246
+ if self.mate_info_mode == 'TEXT':
247
+ for index, slot in enumerate(ob.material_slots):
248
+ if "Material:" + str(index) not in context.blend_data.texts:
249
+ return self.report_cancel("Material Data from Text is incomplete.")
250
+ context.window_manager.progress_update(1)
251
+
252
+ # model名とか
253
+ ob_names = common.remove_serial_number(ob.name, self.is_arrange_name).split('.')
254
+ if self.model_name == '*':
255
+ self.model_name = ob_names[0]
256
+ if self.base_bone_name == '*':
257
+ self.base_bone_name = ob_names[1] if 2 <= len(ob_names) else 'Auto'
258
+
259
+ # BoneData情報読み込み
260
+ base_bone_candidate = None
261
+ bone_data = []
262
+ if self.bone_info_mode == 'ARMATURE':
263
+ bone_data = self.armature_bone_data_parser(arm_ob)
264
+ base_bone_candidate = arm_ob.data['BaseBone']
265
+ elif self.bone_info_mode == 'TEXT':
266
+ bone_data_text = context.blend_data.texts["BoneData"]
267
+ if 'BaseBone' in bone_data_text:
268
+ base_bone_candidate = bone_data_text['BaseBone']
269
+ bone_data = self.bone_data_parser(l.body for l in bone_data_text.lines)
270
+ elif self.bone_info_mode in ['OBJECT_PROPERTY', 'ARMATURE_PROPERTY']:
271
+ target = ob if self.bone_info_mode == 'OBJECT_PROPERTY' else arm_ob.data
272
+ if 'BaseBone' in target:
273
+ base_bone_candidate = target['BaseBone']
274
+ bone_data = self.bone_data_parser(self.indexed_data_generator(target, prefix='BoneData:'))
275
+ if len(bone_data) <= 0:
276
+ return self.report_cancel("There is no such Base Bone in the Bone Data")
277
+
278
+ if self.base_bone_name not in (b['name'] for b in bone_data):
279
+ if base_bone_candidate and self.base_bone_name == 'Auto':
280
+ self.base_bone_name = base_bone_candidate
281
+ else:
282
+ return self.report_cancel("The second half of the Object name should be the bone names(?)")
283
+ context.window_manager.progress_update(2)
284
+
285
+ # LocalBoneData情報読み込み
286
+ local_bone_data = []
287
+ if self.bone_info_mode == 'ARMATURE':
288
+ local_bone_data = self.armature_local_bone_data_parser(arm_ob)
289
+ elif self.bone_info_mode == 'TEXT':
290
+ local_bone_data_text = context.blend_data.texts["LocalBoneData"]
291
+ local_bone_data = self.local_bone_data_parser(l.body for l in local_bone_data_text.lines)
292
+ elif self.bone_info_mode in ['OBJECT_PROPERTY', 'ARMATURE_PROPERTY']:
293
+ target = ob if self.bone_info_mode == 'OBJECT_PROPERTY' else arm_ob.data
294
+ local_bone_data = self.local_bone_data_parser(self.indexed_data_generator(target, prefix='LocalBoneData:'))
295
+ if len(local_bone_data) <= 0:
296
+ return self.report_cancel("LocalBoneData in text does not contain valid data")
297
+ local_bone_name_indices = {bone['name']:index for index, bone in enumerate(local_bone_data)}
298
+ context.window_manager.progress_update(3)
299
+
300
+ # ウェイト情報読み込み
301
+ vertices = []
302
+ is_over_one = 0
303
+ is_under_one = 0
304
+ for i, vert in enumerate(me.vertices):
305
+ vgs = []
306
+ for vg in vert.groups:
307
+ name = common.encode_bone_name(ob.vertex_groups[vg.group].name, self.is_convert_bone_weight_names)
308
+ index = local_bone_name_indices.get(name, -1)
309
+ if 0 <= index and 0.0 < vg.weight:
310
+ vgs.append([index, vg.weight])
311
+ if len(vgs) == 0:
312
+ if not self.is_batch:
313
+ self.select_no_weight_vertices(context, local_bone_name_indices)
314
+ return self.report_cancel("A Vertex with no Weight assigned has been found. Aborting.")
315
+ vgs = sorted(vgs, key=itemgetter(1), reverse=True)[0:4]
316
+ total = sum(vg[1] for vg in vgs)
317
+ if self.is_normalize_weight:
318
+ for vg in vgs:
319
+ vg[1] /= total
320
+ else:
321
+ if 1.01 < total:
322
+ is_over_one += 1
323
+ elif total < 0.99:
324
+ is_under_one += 1
325
+ if len(vgs) < 4:
326
+ vgs += [(0, 0.0)] * (4 - len(vgs))
327
+ vertices.append({
328
+ 'index': vert.index,
329
+ 'face_indexs': list(map(itemgetter(0), vgs)),
330
+ 'weights': list(map(itemgetter(1), vgs)),
331
+ })
332
+ if 1 <= is_over_one:
333
+ self.report(type={'INFO'}, message="A vertex whose total weight is more then 1 has been found. Please Normalize Weights." % is_over_one)
334
+ if 1 <= is_under_one:
335
+ self.report(type={'INFO'}, message="A vertex whose total weight is less then 1 has been found. Please Normalize Weights." % is_under_one)
336
+ context.window_manager.progress_update(4)
337
+
338
+ try:
339
+ file = common.open_temporary(self.filepath, 'wb', is_backup=self.is_backup)
340
+ except:
341
+ self.report(type={'ERROR'}, message="Failed to Backup previous file. Possibly inaccessible or non-existent.")
342
+ return {'CANCELLED'}
343
+
344
+ model_datas = {
345
+ 'bone_data': bone_data,
346
+ 'local_bone_data': local_bone_data,
347
+ 'vertices': vertices,
348
+ }
349
+ try:
350
+ with file:
351
+ self.write_model(context, file, **model_datas)
352
+ except common.CM3D2ExportException as e:
353
+ self.report(type={'ERROR'}, message=str(e))
354
+ return {'CANCELLED'}
355
+
356
+ # モディファイアを適用する場合
357
+ if self.is_apply_modifiers:
358
+ context.blend_data.objects.remove(new_ob, do_unlink=True)
359
+ context.blend_data.meshes.remove(new_me, do_unlink=True)
360
+ context.scene.objects.active = source_ob
361
+
362
+ context.window_manager.progress_update(10)
363
+ diff_time = time.time() - start_time
364
+ self.report(type={'INFO'}, message=str(round(diff_time, 1)) + " Seconds")
365
+ self.report(type={'INFO'}, message="Model Exported Successfully. Mission Accomplished.")
366
+ return {'FINISHED'}
367
+
368
+
369
+ def write_model(self, context, file, bone_data=[], local_bone_data=[], vertices=[]):
370
+ """モデルデータをファイルオブジェクトに書き込む"""
371
+ ob = context.active_object
372
+ me = ob.data
373
+
374
+ # ファイル先頭
375
+ common.write_str(file, 'CM3D2_MESH')
376
+ file.write(struct.pack('<i', self.version))
377
+
378
+ common.write_str(file, self.model_name)
379
+ common.write_str(file, self.base_bone_name)
380
+
381
+ # ボーン情報書き出し
382
+ file.write(struct.pack('<i', len(bone_data)))
383
+ for bone in bone_data:
384
+ common.write_str(file, bone['name'])
385
+ file.write(struct.pack('<b', bone['unknown']))
386
+ context.window_manager.progress_update(3.3)
387
+ for bone in bone_data:
388
+ file.write(struct.pack('<i', bone['parent_index']))
389
+ context.window_manager.progress_update(3.7)
390
+ for bone in bone_data:
391
+ file.write(struct.pack('<3f', bone['co'][0], bone['co'][1], bone['co'][2]))
392
+ file.write(struct.pack('<4f', bone['rot'][1], bone['rot'][2], bone['rot'][3], bone['rot'][0]))
393
+ context.window_manager.progress_update(4)
394
+
395
+ # 正しい頂点数などを取得
396
+ bm = bmesh.new()
397
+ bm.from_mesh(me)
398
+ uv_lay = bm.loops.layers.uv.active
399
+ vert_uvs = []
400
+ vert_uvs_append = vert_uvs.append
401
+ vert_iuv = {}
402
+ vert_indices = {}
403
+ vert_count = 0
404
+ for vert in bm.verts:
405
+ vert_uvs_append([])
406
+ for loop in vert.link_loops:
407
+ uv = loop[uv_lay].uv
408
+ if uv not in vert_uvs[-1]:
409
+ vert_uvs[-1].append(uv)
410
+ iuv_hash = hash(repr([vert.index, uv.x, uv.y]))
411
+ vert_iuv[iuv_hash] = vert_count
412
+ vert_indices[vert.index] = vert_count
413
+ vert_count += 1
414
+ if 65535 < vert_count:
415
+ raise common.CM3D2ExportException("There are still too many vertices (% d Vertices). Please remove% d more vertices. Aborting." % (vert_count, vert_count - 65535))
416
+ context.window_manager.progress_update(5)
417
+
418
+ file.write(struct.pack('<2i', vert_count, len(ob.material_slots)))
419
+
420
+ # ローカルボーン情報を書き出し
421
+ file.write(struct.pack('<i', len(local_bone_data)))
422
+ for bone in local_bone_data:
423
+ common.write_str(file, bone['name'])
424
+ context.window_manager.progress_update(5.3)
425
+ for bone in local_bone_data:
426
+ for f in bone['matrix']:
427
+ file.write(struct.pack('<f', f))
428
+ context.window_manager.progress_update(5.7)
429
+
430
+ # カスタム法線情報を取得
431
+ if me.has_custom_normals:
432
+ custom_normals = [mathutils.Vector() for i in range(len(me.vertices))]
433
+ me.calc_normals_split()
434
+ for loop in me.loops:
435
+ custom_normals[loop.vertex_index] = loop.normal.copy()
436
+ # 頂点情報を書き出し
437
+ for i, vert in enumerate(bm.verts):
438
+ co = vert.co * self.scale
439
+ if me.has_custom_normals:
440
+ no = custom_normals[vert.index]
441
+ else:
442
+ no = vert.normal.copy()
443
+ for uv in vert_uvs[i]:
444
+ file.write(struct.pack('<3f', -co.x, co.y, co.z))
445
+ file.write(struct.pack('<3f', -no.x, no.y, no.z))
446
+ file.write(struct.pack('<2f', uv.x, uv.y))
447
+ context.window_manager.progress_update(6)
448
+
449
+ # 不明な情報を書き出し
450
+ unknown_count = 0
451
+ file.write(struct.pack('<i', unknown_count))
452
+
453
+ # ウェイト情報を書き出し
454
+ for vert in vertices:
455
+ for uv in vert_uvs[vert['index']]:
456
+ file.write(struct.pack('<4H', *vert['face_indexs']))
457
+ file.write(struct.pack('<4f', *vert['weights']))
458
+ context.window_manager.progress_update(7)
459
+
460
+ # 面情報を書き出し
461
+ progress_plus_value = 1.0 / (len(ob.material_slots) * len(bm.faces))
462
+ progress_count = 7.0
463
+ progress_reduce = (len(ob.material_slots) * len(bm.faces)) // 200 + 1
464
+
465
+ def vert_index_from_loops(loops):
466
+ """vert_index generator"""
467
+ for loop in loops:
468
+ uv = loop[uv_lay].uv
469
+ index = loop.vert.index
470
+ iuv_hash = hash(repr([index, uv.x, uv.y]))
471
+ vert_index = vert_iuv.get(iuv_hash)
472
+ if vert_index is None:
473
+ vert_index = vert_indices.get(index, 0)
474
+ yield vert_index
475
+
476
+ for mate_index, slot in enumerate(ob.material_slots):
477
+ tris_faces = []
478
+ for face in bm.faces:
479
+ progress_count += progress_plus_value
480
+ if face.index % progress_reduce == 0:
481
+ context.window_manager.progress_update(progress_count)
482
+ if face.material_index != mate_index:
483
+ continue
484
+ if len(face.verts) == 3:
485
+ tris_faces.extend(vert_index_from_loops(reversed(face.loops)))
486
+ elif len(face.verts) == 4 and self.is_convert_tris:
487
+ v1 = face.loops[0].vert.co - face.loops[2].vert.co
488
+ v2 = face.loops[1].vert.co - face.loops[3].vert.co
489
+ if v1.length < v2.length:
490
+ f1 = [0, 1, 2]
491
+ f2 = [0, 2, 3]
492
+ else:
493
+ f1 = [0, 1, 3]
494
+ f2 = [1, 2, 3]
495
+ faces, faces2 = [], []
496
+ for i, vert_index in enumerate(vert_index_from_loops(reversed(face.loops))):
497
+ if i in f1:
498
+ faces.append(vert_index)
499
+ if i in f2:
500
+ faces2.append(vert_index)
501
+ tris_faces.extend(faces)
502
+ tris_faces.extend(faces2)
503
+ elif 5 <= len(face.verts) and self.is_convert_tris:
504
+ face_count = len(face.verts) - 2
505
+
506
+ tris = []
507
+ seek_min, seek_max = 0, len(face.verts) - 1
508
+ for i in range(face_count):
509
+ if not i % 2:
510
+ tris.append([seek_min, seek_min+1, seek_max])
511
+ seek_min += 1
512
+ else:
513
+ tris.append([seek_min, seek_max-1, seek_max])
514
+ seek_max -= 1
515
+
516
+ tris_indexs = [[] for _ in range(len(tris))]
517
+ for i, vert_index in enumerate(vert_index_from_loops(reversed(face.loops))):
518
+ for tris_index, points in enumerate(tris):
519
+ if i in points:
520
+ tris_indexs[tris_index].append(vert_index)
521
+
522
+ tris_faces.extend(p for ps in tris_indexs for p in ps)
523
+
524
+ file.write(struct.pack('<i', len(tris_faces)))
525
+ for face_index in tris_faces:
526
+ file.write(struct.pack('<H', face_index))
527
+ context.window_manager.progress_update(8)
528
+
529
+ # マテリアルを書き出し
530
+ file.write(struct.pack('<i', len(ob.material_slots)))
531
+ for slot_index, slot in enumerate(ob.material_slots):
532
+ if self.mate_info_mode == 'MATERIAL':
533
+ mate = slot.material
534
+ common.write_str(file, common.remove_serial_number(mate.name, self.is_arrange_name))
535
+ common.write_str(file, mate['shader1'])
536
+ common.write_str(file, mate['shader2'])
537
+ for tindex, tslot in enumerate(mate.texture_slots):
538
+ if not tslot:
539
+ continue
540
+ tex = tslot.texture
541
+ if mate.use_textures[tindex]:
542
+ common.write_str(file, 'tex')
543
+ common.write_str(file, common.remove_serial_number(tex.name, self.is_arrange_name))
544
+ if tex.image:
545
+ img = tex.image
546
+ common.write_str(file, 'tex2d')
547
+
548
+ tex_name = common.remove_serial_number(img.name, self.is_arrange_name)
549
+ tex_name = re.sub(r"\.[Pp][Nn][Gg]$", "", tex_name)
550
+ common.write_str(file, tex_name)
551
+
552
+ if 'cm3d2_path' in img:
553
+ path = img['cm3d2_path']
554
+ else:
555
+ path = bpy.path.abspath(img.filepath)
556
+ path = path.replace('\\', '/')
557
+ path = re.sub(r'^[\/\.]*', "", path)
558
+ if not re.search(r'^assets/texture/', path, re.I):
559
+ path = "Assets/texture/texture/" + os.path.basename(path)
560
+ common.write_str(file, path)
561
+ col = tslot.color
562
+ file.write(struct.pack('<3f', col[0], col[1], col[2]))
563
+ file.write(struct.pack('<f', tslot.diffuse_color_factor))
564
+ else:
565
+ common.write_str(file, 'null')
566
+ else:
567
+ if tslot.use_rgb_to_intensity:
568
+ common.write_str(file, 'col')
569
+ common.write_str(file, common.remove_serial_number(tex.name, self.is_arrange_name))
570
+ col = tslot.color
571
+ file.write(struct.pack('<3f', col[0], col[1], col[2]))
572
+ file.write(struct.pack('<f', tslot.diffuse_color_factor))
573
+ else:
574
+ common.write_str(file, 'f')
575
+ common.write_str(file, common.remove_serial_number(tex.name, self.is_arrange_name))
576
+ file.write(struct.pack('<f', tslot.diffuse_color_factor))
577
+ elif self.mate_info_mode == 'TEXT':
578
+ data = context.blend_data.texts["Material:" + str(slot_index)].as_string()
579
+ data = data.split('\n')
580
+ common.write_str(file, data[2])
581
+ common.write_str(file, data[3])
582
+ common.write_str(file, data[4])
583
+ seek = 5
584
+ for i in range(9**9):
585
+ if len(data) <= seek:
586
+ break
587
+ type = data[seek]
588
+ if type == 'tex':
589
+ common.write_str(file, type)
590
+ common.write_str(file, common.line_trim(data[seek + 1]))
591
+ common.write_str(file, common.line_trim(data[seek + 2]))
592
+ if common.line_trim(data[seek + 2]) == 'tex2d':
593
+ common.write_str(file, common.line_trim(data[seek + 3]))
594
+ common.write_str(file, common.line_trim(data[seek + 4]))
595
+ col = common.line_trim(data[seek + 5])
596
+ col = col.split(' ')
597
+ file.write(struct.pack('<4f', float(col[0]), float(col[1]), float(col[2]), float(col[3])))
598
+ seek += 3
599
+ seek += 2
600
+ elif type == 'col':
601
+ common.write_str(file, type)
602
+ common.write_str(file, common.line_trim(data[seek + 1]))
603
+ col = common.line_trim(data[seek + 2])
604
+ col = col.split(' ')
605
+ file.write(struct.pack('<4f', float(col[0]), float(col[1]), float(col[2]), float(col[3])))
606
+ seek += 2
607
+ elif type == 'f':
608
+ common.write_str(file, type)
609
+ common.write_str(file, common.line_trim(data[seek + 1]))
610
+ file.write(struct.pack('<f', float(common.line_trim(data[seek + 2]))))
611
+ seek += 2
612
+ seek += 1
613
+ common.write_str(file, 'end')
614
+ context.window_manager.progress_update(9)
615
+
616
+ # モーフを書き出し
617
+ if me.shape_keys:
618
+ temp_me = context.blend_data.meshes.new(me.name + ".temp")
619
+ vs = [vert.co for vert in me.vertices]
620
+ es = []
621
+ fs = [face.vertices for face in me.polygons]
622
+ temp_me.from_pydata(vs, es, fs)
623
+ if 2 <= len(me.shape_keys.key_blocks):
624
+ for shape_key in me.shape_keys.key_blocks[1:]:
625
+ morph = []
626
+ vert_index = 0
627
+ for i in range(len(me.vertices)):
628
+ temp_me.vertices[i].co = shape_key.data[i].co.copy()
629
+ temp_me.update()
630
+ for i, vert in enumerate(me.vertices):
631
+ co_diff = shape_key.data[i].co - vert.co
632
+ if me.has_custom_normals:
633
+ no_diff = custom_normals[i] - vert.normal
634
+ else:
635
+ no_diff = temp_me.vertices[i].normal - vert.normal
636
+ if 0.001 < co_diff.length or 0.001 < no_diff.length:
637
+ co = co_diff * self.scale
638
+ for d in vert_uvs[i]:
639
+ morph.append((vert_index, co, no_diff))
640
+ vert_index += 1
641
+ else:
642
+ vert_index += len(vert_uvs[i])
643
+ if not len(morph):
644
+ continue
645
+ common.write_str(file, 'morph')
646
+ common.write_str(file, shape_key.name)
647
+ file.write(struct.pack('<i', len(morph)))
648
+ for index, vec, normal in morph:
649
+ file.write(struct.pack('<H', index))
650
+ file.write(struct.pack('<3f', -vec.x, vec.y, vec.z))
651
+ file.write(struct.pack('<3f', -normal.x, normal.y, normal.z))
652
+ context.blend_data.meshes.remove(temp_me)
653
+ common.write_str(file, 'end')
654
+
655
+
656
+ def select_no_weight_vertices(self, context, local_bone_name_indices):
657
+ """ウェイトが割り当てられていない頂点を選択する"""
658
+ ob = context.active_object
659
+ me = ob.data
660
+ bpy.ops.object.mode_set(mode='EDIT')
661
+ bpy.ops.mesh.select_all(action='DESELECT')
662
+ bpy.ops.object.mode_set(mode='OBJECT')
663
+ context.tool_settings.mesh_select_mode = (True, False, False)
664
+ for vert in me.vertices:
665
+ for vg in vert.groups:
666
+ name = common.encode_bone_name(ob.vertex_groups[vg.group].name, self.is_convert_bone_weight_names)
667
+ if name in local_bone_name_indices and 0.0 < vg.weight:
668
+ break
669
+ else:
670
+ vert.select = True
671
+ bpy.ops.object.mode_set(mode='EDIT')
672
+
673
+ def armature_bone_data_parser(self, ob):
674
+ """アーマチュアを解析してBoneDataを返す"""
675
+ arm = ob.data
676
+
677
+ bones = []
678
+ bone_name_indices = {}
679
+ already_bone_names = []
680
+ bones_queue = arm.bones[:]
681
+ while len(bones_queue):
682
+ bone = bones_queue.pop(0)
683
+
684
+ if not bone.parent:
685
+ already_bone_names.append(bone.name)
686
+ bones.append(bone)
687
+ bone_name_indices[bone.name] = len(bone_name_indices)
688
+ continue
689
+ elif bone.parent.name in already_bone_names:
690
+ already_bone_names.append(bone.name)
691
+ bones.append(bone)
692
+ bone_name_indices[bone.name] = len(bone_name_indices)
693
+ continue
694
+
695
+ bones_queue.append(bone)
696
+
697
+ bone_data = []
698
+ for bone in bones:
699
+
700
+ if 'UnknownFlag' in bone: unknown_frag = bone['UnknownFlag']
701
+ else: unknown_frag = 0
702
+
703
+ if bone.parent: parent_index = bone_name_indices[bone.parent.name]
704
+ else: parent_index = -1
705
+
706
+ mat = bone.matrix_local.copy()
707
+ if bone.parent:
708
+ mat = bone.parent.matrix_local.inverted() * mat
709
+
710
+ co = mat.to_translation() * self.scale
711
+ rot = mat.to_quaternion()
712
+
713
+ if bone.parent:
714
+ co.x, co.y, co.z = -co.y, -co.x, co.z
715
+ rot.w, rot.x, rot.y, rot.z = rot.w, rot.y, rot.x, -rot.z
716
+ else:
717
+ co.x, co.y, co.z = -co.x, co.z, -co.y
718
+
719
+ fix_quat = mathutils.Euler((0, 0, math.radians(-90)), 'XYZ').to_quaternion()
720
+ fix_quat2 = mathutils.Euler((math.radians(-90), 0, 0), 'XYZ').to_quaternion()
721
+ rot = rot * fix_quat * fix_quat2
722
+
723
+ rot.w, rot.x, rot.y, rot.z = -rot.y, -rot.z, -rot.x, rot.w
724
+
725
+ bone_data.append({
726
+ 'name': bone.name,
727
+ 'unknown': unknown_frag,
728
+ 'parent_index': parent_index,
729
+ 'co': co.copy(),
730
+ 'rot': rot.copy(),
731
+ })
732
+ return bone_data
733
+
734
+ @staticmethod
735
+ def bone_data_parser(container):
736
+ """BoneData テキストをパースして辞書を要素とするリストを返す"""
737
+ bone_data = []
738
+ bone_name_indices = {}
739
+ for line in container:
740
+ data = line.split(',')
741
+ if len(data) != 5:
742
+ continue
743
+ parent_name = data[2]
744
+ if parent_name.isdigit():
745
+ parent_index = int(parent_name)
746
+ else:
747
+ parent_index = bone_name_indices.get(parent_name, -1)
748
+ bone_data.append({
749
+ 'name': data[0],
750
+ 'unknown': int(data[1]),
751
+ 'parent_index': parent_index,
752
+ 'co': list(map(float, data[3].split())),
753
+ 'rot': list(map(float, data[4].split())),
754
+ })
755
+ bone_name_indices[data[0]] = len(bone_name_indices)
756
+ return bone_data
757
+
758
+ def armature_local_bone_data_parser(self, ob):
759
+ """アーマチュアを解析してBoneDataを返す"""
760
+ arm = ob.data
761
+
762
+ bones = []
763
+ bone_name_indices = {}
764
+ already_bone_names = []
765
+ bones_queue = arm.bones[:]
766
+ while len(bones_queue):
767
+ bone = bones_queue.pop(0)
768
+
769
+ if not bone.parent:
770
+ already_bone_names.append(bone.name)
771
+ bones.append(bone)
772
+ bone_name_indices[bone.name] = len(bone_name_indices)
773
+ continue
774
+ elif bone.parent.name in already_bone_names:
775
+ already_bone_names.append(bone.name)
776
+ bones.append(bone)
777
+ bone_name_indices[bone.name] = len(bone_name_indices)
778
+ continue
779
+
780
+ bones_queue.append(bone)
781
+
782
+ local_bone_data = []
783
+ for bone in bones:
784
+
785
+ mat = bone.matrix_local.copy()
786
+
787
+ co = mat.to_translation() * self.scale
788
+ rot = mat.to_quaternion()
789
+
790
+ co.rotate(rot.inverted())
791
+ co.x, co.y, co.z = co.y, co.x, -co.z
792
+
793
+ fix_quat = mathutils.Euler((0, 0, math.radians(-90)), 'XYZ').to_quaternion()
794
+ rot = rot * fix_quat
795
+ rot.w, rot.x, rot.y, rot.z = -rot.z, -rot.y, -rot.x, rot.w
796
+
797
+ co_mat = mathutils.Matrix.Translation(co)
798
+ rot_mat = rot.to_matrix().to_4x4()
799
+ mat = co_mat * rot_mat
800
+
801
+ copy_mat = mat.copy()
802
+ mat[0][0], mat[0][1], mat[0][2], mat[0][3] = copy_mat[0][0], copy_mat[1][0], copy_mat[2][0], copy_mat[3][0]
803
+ mat[1][0], mat[1][1], mat[1][2], mat[1][3] = copy_mat[0][1], copy_mat[1][1], copy_mat[2][1], copy_mat[3][1]
804
+ mat[2][0], mat[2][1], mat[2][2], mat[2][3] = copy_mat[0][2], copy_mat[1][2], copy_mat[2][2], copy_mat[3][2]
805
+ mat[3][0], mat[3][1], mat[3][2], mat[3][3] = copy_mat[0][3], copy_mat[1][3], copy_mat[2][3], copy_mat[3][3]
806
+
807
+ mat_array = []
808
+ for vec in mat:
809
+ mat_array.extend(vec[:])
810
+
811
+ local_bone_data.append({
812
+ 'name': bone.name,
813
+ 'matrix': mat_array,
814
+ })
815
+ return local_bone_data
816
+
817
+ @staticmethod
818
+ def local_bone_data_parser(container):
819
+ """LocalBoneData テキストをパースして辞書を要素とするリストを返す"""
820
+ local_bone_data = []
821
+ for line in container:
822
+ data = line.split(',')
823
+ if len(data) != 2:
824
+ continue
825
+ local_bone_data.append({
826
+ 'name': data[0],
827
+ 'matrix': list(map(float, data[1].split())),
828
+ })
829
+ return local_bone_data
830
+
831
+
832
+ @staticmethod
833
+ def indexed_data_generator(container, prefix='', max_index=9**9, max_pass=50):
834
+ """コンテナ内の数値インデックスをキーに持つ要素を昇順に返すジェネレーター"""
835
+ pass_count = 0
836
+ for i in range(max_index):
837
+ name = prefix + str(i)
838
+ if name not in container:
839
+ pass_count += 1
840
+ if max_pass < pass_count:
841
+ return
842
+ continue
843
+ yield container[name]
844
+
845
+
846
+
847
+ # メニューを登録する関数
848
+ def menu_func(self, context):
849
+ self.layout.operator(export_cm3d2_model.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/model_import.py ADDED
@@ -0,0 +1,671 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bpy, bmesh, mathutils
2
+ import math, struct, time, os
3
+ from collections import Counter
4
+ from . import common
5
+
6
+ # メインオペレーター
7
+ class import_cm3d2_model(bpy.types.Operator):
8
+ bl_idname = 'import_mesh.import_cm3d2_model'
9
+ bl_label = "CM3D2 Model (.model)"
10
+ bl_description = "Imports a model from the game CM3D2"
11
+ bl_options = {'REGISTER'}
12
+
13
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
14
+ filename_ext = ".model"
15
+ filter_glob = bpy.props.StringProperty(default="*.model", options={'HIDDEN'})
16
+
17
+ scale = bpy.props.FloatProperty(name="Scale", default=5, min=0.1, max=100, soft_min=0.1, soft_max=100, step=100, precision=1, description="The amount by which the mesh is scaled when imported. Recommended that you use the same when at the time of export.")
18
+
19
+ is_mesh = bpy.props.BoolProperty(name="Load Mesh", default=True, description="Leaving this on will load in the mesh.")
20
+ is_remove_doubles = bpy.props.BoolProperty(name="Remove Doubles", default=True, description="Doubles will be removed in both the uv and the mesh at the time of import.")
21
+ is_seam = bpy.props.BoolProperty(name="Mark Seams", default=True, description="This will mark the UV seams on your mesh.")
22
+
23
+ is_convert_bone_weight_names = bpy.props.BoolProperty(name="Convert Bone Weight Names to Blender", default=False, description="This will convert bone and vertex group names for use with blender mirroring.")
24
+ is_vertex_group_sort = bpy.props.BoolProperty(name="Sort Vertex Groups", default=True, description="This will sort your vertex groups so they are easier to work with.")
25
+ is_remove_empty_vertex_group = bpy.props.BoolProperty(name="Remove Empty Vertex Groups", default=True, description="Will remove any empty vertex groups to which no vertices are assigned to it.")
26
+
27
+ is_replace_cm3d2_tex = bpy.props.BoolProperty(name="Find Textures", default=True, description="Will search the CM3D2 folder for the textures. (Textures must be in .png format to be loaded)")
28
+ is_decorate = bpy.props.BoolProperty(name="Decorate Material", default=True)
29
+ is_mate_data_text = bpy.props.BoolProperty(name="Export Mate Data to text editor.", default=True, description="Material information will be placed into the text editor.")
30
+
31
+ is_armature = bpy.props.BoolProperty(name="Load Armature", default=True, description="If left, it will load in the corresponding Armature.")
32
+ is_armature_clean = bpy.props.BoolProperty(name="Clean Armature", default=True, description="Will delete any unneeded bones.")
33
+
34
+ is_bone_data_text = bpy.props.BoolProperty(name="Bone Data to Text", default=True, description="All of the bone data will be also placed into the text editor.")
35
+ is_bone_data_obj_property = bpy.props.BoolProperty(name="Bone Data to Object Properties", default=True, description="Bone Data will also be placed in the Objects custom properties.")
36
+ is_bone_data_arm_property = bpy.props.BoolProperty(name="Bone Data to Armature Properties", default=True, description="Bone data will also be placed in the Armatures custom properties.")
37
+
38
+ @classmethod
39
+ def poll(cls, context):
40
+ return True
41
+
42
+ def invoke(self, context, event):
43
+ if common.preferences().model_default_path:
44
+ self.filepath = common.default_cm3d2_dir(common.preferences().model_default_path, "", "model")
45
+ else:
46
+ self.filepath = common.default_cm3d2_dir(common.preferences().model_import_path, "", "model")
47
+ self.scale = common.preferences().scale
48
+ self.is_replace_cm3d2_tex = common.preferences().is_replace_cm3d2_tex
49
+ self.is_convert_bone_weight_names = common.preferences().is_convert_bone_weight_names
50
+ context.window_manager.fileselect_add(self)
51
+ return {'RUNNING_MODAL'}
52
+
53
+ def draw(self, context):
54
+ self.layout.prop(self, 'scale')
55
+ box = self.layout.box()
56
+ box.prop(self, 'is_mesh', icon='MESH_DATA')
57
+ sub_box = box.box()
58
+ sub_box.label("Mesh")
59
+ sub_box.prop(self, 'is_remove_doubles', icon='STICKY_UVS_VERT')
60
+ sub_box.prop(self, 'is_seam', icon='KEY_DEHLT')
61
+ sub_box = box.box()
62
+ sub_box.label("Vertex Group")
63
+ sub_box.prop(self, 'is_vertex_group_sort', icon='SORTALPHA')
64
+ sub_box.prop(self, 'is_remove_empty_vertex_group', icon='DISCLOSURE_TRI_DOWN')
65
+ sub_box.prop(self, 'is_convert_bone_weight_names', icon='BLENDER')
66
+ sub_box = box.box()
67
+ sub_box.label("Material")
68
+ sub_box.prop(self, 'is_replace_cm3d2_tex', icon='BORDERMOVE')
69
+ sub_box.prop(self, 'is_decorate', icon='TEXTURE_SHADED')
70
+ sub_box.prop(self, 'is_mate_data_text', icon='TEXT')
71
+ box = self.layout.box()
72
+ box.prop(self, 'is_armature', icon='ARMATURE_DATA')
73
+ sub_box = box.box()
74
+ sub_box.label("Armature")
75
+ sub_box.prop(self, 'is_armature_clean', icon='X')
76
+ sub_box.prop(self, 'is_convert_bone_weight_names', icon='BLENDER', text="Convert Bone Names for Blender.")
77
+ box = self.layout.box()
78
+ box.label("Bone Data Destination")
79
+ box.prop(self, 'is_bone_data_text', icon='TEXT')
80
+ box.prop(self, 'is_bone_data_obj_property', icon='OBJECT_DATA')
81
+ box.prop(self, 'is_bone_data_arm_property', icon='ARMATURE_DATA')
82
+
83
+ def execute(self, context):
84
+ start_time = time.time()
85
+
86
+ common.preferences().model_import_path = self.filepath
87
+ common.preferences().scale = self.scale
88
+ context.window_manager.progress_begin(0, 10)
89
+ context.window_manager.progress_update(0)
90
+
91
+ try:
92
+ file = open(self.filepath, 'rb')
93
+ except:
94
+ self.report(type={'ERROR'}, message="Failed to open file. The file is inaccessible or does not exist.")
95
+ return {'CANCELLED'}
96
+
97
+ # ヘッダー
98
+ ext = common.read_str(file)
99
+ if ext != 'CM3D2_MESH':
100
+ self.report(type={'ERROR'}, message="This is not a CM3D2 Model File.")
101
+ return {'CANCELLED'}
102
+ struct.unpack('<i', file.read(4))[0]
103
+ context.window_manager.progress_update(0.1)
104
+
105
+ # 名前群を取得
106
+ model_name1 = common.read_str(file)
107
+ model_name2 = common.read_str(file)
108
+ context.window_manager.progress_update(0.2)
109
+
110
+ # ボーン情報読み込み
111
+ bone_data = []
112
+ bone_count = struct.unpack('<i', file.read(4))[0]
113
+ for i in range(bone_count):
114
+ bone_data.append({})
115
+ bone_data[i]['name'] = common.read_str(file)
116
+ bone_data[i]['unknown'] = struct.unpack('<B', file.read(1))[0]
117
+ for i in range(bone_count):
118
+ parent_index = struct.unpack('<i', file.read(4))[0]
119
+ parent_name = None
120
+ if parent_index != -1:
121
+ parent_name = bone_data[parent_index]['name']
122
+ bone_data[i]['parent_index'] = parent_index
123
+ bone_data[i]['parent_name'] = parent_name
124
+ for i in range(bone_count):
125
+ x, y, z = struct.unpack('<3f', file.read(3*4))
126
+ bone_data[i]['co'] = mathutils.Vector((x, y, z))
127
+
128
+ x, y, z = struct.unpack('<3f', file.read(3*4))
129
+ w = struct.unpack('<f', file.read(4))[0]
130
+ bone_data[i]['rot'] = mathutils.Quaternion((w, x, y, z))
131
+ context.window_manager.progress_update(0.3)
132
+
133
+ vertex_count, mesh_count, local_bone_count = struct.unpack('<3i', file.read(3*4))
134
+
135
+ # ローカルボーン情報読み込み
136
+ local_bone_data = []
137
+ for i in range(local_bone_count):
138
+ local_bone_data.append({})
139
+ local_bone_data[i]['name'] = common.read_str(file)
140
+ for i in range(local_bone_count):
141
+ row0 = struct.unpack('<4f', file.read(4*4))
142
+ row1 = struct.unpack('<4f', file.read(4*4))
143
+ row2 = struct.unpack('<4f', file.read(4*4))
144
+ row3 = struct.unpack('<4f', file.read(4*4))
145
+ local_bone_data[i]['matrix'] = mathutils.Matrix([row0, row1, row2, row3])
146
+ context.window_manager.progress_update(0.4)
147
+
148
+ # 頂点情報読み込み
149
+ vertex_data = []
150
+ for i in range(vertex_count):
151
+ co = struct.unpack('<3f', file.read(3*4))
152
+ no = struct.unpack('<3f', file.read(3*4))
153
+ uv = struct.unpack('<2f', file.read(2*4))
154
+ vertex_data.append({'co': co, 'normal': no, 'uv': uv})
155
+ comparison_data = list(hash(repr(v['co']) + " " + repr(v['normal'])) for v in vertex_data)
156
+ comparison_counter = Counter(comparison_data)
157
+ comparison_data = list((comparison_counter[h] > 1) for h in comparison_data)
158
+ del comparison_counter
159
+ unknown_count = struct.unpack('<i', file.read(4))[0]
160
+ for i in range(unknown_count):
161
+ struct.unpack('<4f', file.read(4*4))
162
+ for i in range(vertex_count):
163
+ indexes = struct.unpack('<4H', file.read(4*2))
164
+ values = struct.unpack('<4f', file.read(4*4))
165
+ vertex_data[i]['weights'] = list({
166
+ 'index': index,
167
+ 'value': value,
168
+ 'name': local_bone_data[index]['name'],
169
+ } for index, value in zip(indexes, values))
170
+ context.window_manager.progress_update(0.5)
171
+
172
+ # 面情報読み込み
173
+ face_data = []
174
+ for i in range(mesh_count):
175
+ face_count = int(struct.unpack('<i', file.read(4))[0] / 3)
176
+ face_data.append([tuple(reversed(struct.unpack('<3H', file.read(3*2)))) for j in range(face_count)])
177
+ context.window_manager.progress_update(0.6)
178
+
179
+ # マテリアル情報読み込み
180
+ material_data = []
181
+ material_count = struct.unpack('<i', file.read(4))[0]
182
+ for i in range(material_count):
183
+ material_data.append({})
184
+ material_data[i]['name1'] = common.read_str(file)
185
+ material_data[i]['name2'] = common.read_str(file)
186
+ material_data[i]['name3'] = common.read_str(file)
187
+ material_data[i]['data'] = []
188
+ while True:
189
+ data_type = common.read_str(file)
190
+ if data_type == 'tex':
191
+ material_data[i]['data'].append({'type':data_type})
192
+ material_data[i]['data'][-1]['name'] = common.read_str(file)
193
+ material_data[i]['data'][-1]['type2'] = common.read_str(file)
194
+ if material_data[i]['data'][-1]['type2'] == 'tex2d':
195
+ material_data[i]['data'][-1]['name2'] = common.read_str(file)
196
+ material_data[i]['data'][-1]['path'] = common.read_str(file)
197
+ material_data[i]['data'][-1]['color'] = struct.unpack('<4f', file.read(4*4))
198
+ elif data_type == 'col':
199
+ material_data[i]['data'].append({'type':data_type})
200
+ material_data[i]['data'][-1]['name'] = common.read_str(file)
201
+ material_data[i]['data'][-1]['color'] = struct.unpack('<4f', file.read(4*4))
202
+ elif data_type == 'f':
203
+ material_data[i]['data'].append({'type':data_type})
204
+ material_data[i]['data'][-1]['name'] = common.read_str(file)
205
+ material_data[i]['data'][-1]['float'] = struct.unpack('<f', file.read(4))[0]
206
+ else:
207
+ break
208
+ context.window_manager.progress_update(0.8)
209
+
210
+ # その他情報読み込み
211
+ misc_data = []
212
+ while True:
213
+ data_type = common.read_str(file)
214
+ if data_type == 'morph':
215
+ misc_data.append({'type':data_type})
216
+ misc_data[-1]['name'] = common.read_str(file)
217
+ morph_vert_count = struct.unpack('<i', file.read(4))[0]
218
+ misc_data[-1]['data'] = []
219
+ for i in range(morph_vert_count):
220
+ misc_data[-1]['data'].append({})
221
+ misc_data[-1]['data'][i]['index'] = struct.unpack('<H', file.read(2))[0]
222
+ misc_data[-1]['data'][i]['co'] = mathutils.Vector(struct.unpack('<3f', file.read(3*4)))
223
+ misc_data[-1]['data'][i]['normal'] = struct.unpack('<3f', file.read(3*4))
224
+ else:
225
+ break
226
+
227
+ file.close()
228
+ context.window_manager.progress_update(1)
229
+
230
+ try:
231
+ bpy.ops.object.mode_set(mode='OBJECT')
232
+ except RuntimeError:
233
+ pass
234
+ bpy.ops.object.select_all(action='DESELECT')
235
+
236
+ # アーマチュア作成
237
+ if self.is_armature:
238
+ arm = bpy.data.armatures.new(model_name1 + ".armature")
239
+ arm_ob = bpy.data.objects.new(model_name1 + ".armature", arm)
240
+ bpy.context.scene.objects.link(arm_ob)
241
+ arm_ob.select = True
242
+ bpy.context.scene.objects.active = arm_ob
243
+ bpy.ops.object.mode_set(mode='EDIT')
244
+
245
+ # 基幹ボーンのみ作成
246
+ child_data = []
247
+ for data in bone_data:
248
+ if not data['parent_name']:
249
+ bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names))
250
+ bone.head, bone.tail = (0, 0, 0), (0, 1, 0)
251
+
252
+ co = data['co'].copy() * self.scale
253
+ rot = data['rot']
254
+
255
+ co_mat = mathutils.Matrix.Translation(co)
256
+ rot_mat = rot.to_matrix().to_4x4()
257
+ mat = co_mat * rot_mat
258
+
259
+ fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0))
260
+ fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4()
261
+ fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4()
262
+
263
+ bone.matrix = fix_mat_scale * fix_mat_before * mat * fix_mat_after
264
+
265
+ if data['unknown']: bone["UnknownFlag"] = 1
266
+ else: bone["UnknownFlag"] = 0
267
+ else:
268
+ child_data.append(data)
269
+ context.window_manager.progress_update(1.333)
270
+
271
+ # 子ボーンを追加していく
272
+ while len(child_data):
273
+ data = child_data.pop(0)
274
+ if common.decode_bone_name(data['parent_name'], self.is_convert_bone_weight_names) in arm.edit_bones:
275
+ bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names))
276
+ parent = arm.edit_bones[common.decode_bone_name(data['parent_name'], self.is_convert_bone_weight_names)]
277
+ bone.parent = parent
278
+ bone.head, bone.tail = (0, 0, 0), (0, 1, 0)
279
+
280
+ parent_mats = []
281
+ current_bone = bone
282
+ while current_bone:
283
+ for b in bone_data:
284
+ if common.decode_bone_name(b['name'], self.is_convert_bone_weight_names) == current_bone.name:
285
+ local_co = b['co'].copy()
286
+ local_rot = b['rot'].copy()
287
+ break
288
+
289
+ local_co_mat = mathutils.Matrix.Translation(local_co)
290
+ local_rot_mat = local_rot.to_matrix().to_4x4()
291
+ parent_mats.append(local_co_mat * local_rot_mat)
292
+
293
+ current_bone = current_bone.parent
294
+ parent_mats.reverse()
295
+
296
+ mat = mathutils.Matrix()
297
+ for local_mat in parent_mats:
298
+ mat *= local_mat
299
+ mat *= self.scale
300
+
301
+ fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0))
302
+ fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4()
303
+ fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4()
304
+
305
+ bone.matrix = fix_mat_scale * fix_mat_before * mat * fix_mat_after
306
+
307
+ if data['unknown']: bone["UnknownFlag"] = 1
308
+ else: bone["UnknownFlag"] = 0
309
+ else:
310
+ child_data.append(data)
311
+ context.window_manager.progress_update(1.666)
312
+
313
+ # ボーン整頓
314
+ for bone in arm.edit_bones:
315
+ if len(bone.children) == 0:
316
+ if bone.parent:
317
+ pass
318
+ else:
319
+ bone.length = 0.2 * self.scale
320
+ elif len(bone.children) == 1:
321
+ co = bone.children[0].head - bone.head
322
+ bone.length = co.length
323
+ elif len(bone.children) >= 2:
324
+ if bone.parent:
325
+ max_len = 0.0
326
+ for child_bone in bone.children:
327
+ co = child_bone.head - bone.head
328
+ if max_len < co.length:
329
+ max_len = co.length
330
+ bone.length = max_len
331
+ else:
332
+ bone.length = 0.2 * self.scale
333
+ for bone in arm.edit_bones:
334
+ if len(bone.children) == 0:
335
+ if bone.parent:
336
+ bone.length = bone.parent.length * 0.5
337
+
338
+ # 一部ボーン削除
339
+ if self.is_armature_clean:
340
+ for bone in arm.edit_bones:
341
+ for b in local_bone_data:
342
+ name = common.decode_bone_name(b['name'], self.is_convert_bone_weight_names)
343
+ if bone.name == name:
344
+ break
345
+ else:
346
+ arm.edit_bones.remove(bone)
347
+
348
+ arm.layers[16] = True
349
+ arm.draw_type = 'STICK'
350
+ arm_ob.show_x_ray = True
351
+ bpy.ops.armature.select_all(action='DESELECT')
352
+ bpy.ops.object.mode_set(mode='OBJECT')
353
+ context.window_manager.progress_update(2)
354
+
355
+ if self.is_mesh:
356
+ # メッシュ作成
357
+ me = context.blend_data.meshes.new(model_name1)
358
+ verts, faces = [], []
359
+ for data in vertex_data:
360
+ co = list(data['co'][:])
361
+ co[0] = -co[0]
362
+ co[0] *= self.scale
363
+ co[1] *= self.scale
364
+ co[2] *= self.scale
365
+ verts.append(co)
366
+ context.window_manager.progress_update(2.25)
367
+ for data in face_data:
368
+ faces.extend(data)
369
+ context.window_manager.progress_update(2.5)
370
+ me.from_pydata(verts, [], faces)
371
+ # オブジェクト化
372
+ ob = context.blend_data.objects.new(model_name1, me)
373
+ context.scene.objects.link(ob)
374
+ ob.select = True
375
+ context.scene.objects.active = ob
376
+ bpy.ops.object.shade_smooth()
377
+ context.window_manager.progress_update(2.75)
378
+ # オブジェクト変形
379
+ for bone in bone_data:
380
+ if bone['name'] == model_name2:
381
+ co = bone['co'].copy()
382
+ co.x, co.y, co.z = -co.x, -co.z, co.y
383
+ co *= self.scale
384
+ ob.location = co
385
+
386
+ rot = bone['rot'].copy()
387
+ eul = mathutils.Euler((math.radians(90), 0, 0), 'XYZ')
388
+ rot.rotate(eul)
389
+ ob.rotation_mode = 'QUATERNION'
390
+ ob.rotation_quaternion = rot
391
+
392
+ break
393
+ context.window_manager.progress_update(3)
394
+
395
+ # 頂点グループ作成
396
+ for data in local_bone_data:
397
+ ob.vertex_groups.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names))
398
+ context.window_manager.progress_update(3.333)
399
+ for vert_index, data in enumerate(vertex_data):
400
+ for weight in data['weights']:
401
+ if 0.0 < weight['value']:
402
+ vertex_group = ob.vertex_groups[common.decode_bone_name(weight['name'], self.is_convert_bone_weight_names)]
403
+ vertex_group.add([vert_index], weight['value'], 'REPLACE')
404
+ context.window_manager.progress_update(3.666)
405
+ if self.is_vertex_group_sort:
406
+ bpy.ops.object.vertex_group_sort(sort_type='NAME')
407
+ if self.is_remove_empty_vertex_group:
408
+ for vg in ob.vertex_groups[:]:
409
+ for vert in me.vertices:
410
+ for group in vert.groups:
411
+ if group.group == vg.index:
412
+ if 0.0 < group.weight:
413
+ break
414
+ else:
415
+ continue
416
+ break
417
+ else:
418
+ ob.vertex_groups.remove(vg)
419
+ ob.vertex_groups.active_index = 0
420
+ context.window_manager.progress_update(4)
421
+
422
+ # UV作成
423
+ bpy.ops.mesh.uv_texture_add()
424
+ bm = bmesh.new()
425
+ bm.from_mesh(me)
426
+ for face in bm.faces:
427
+ for loop in face.loops:
428
+ loop[bm.loops.layers.uv.active].uv = vertex_data[loop.vert.index]['uv']
429
+ bm.to_mesh(me)
430
+ bm.free()
431
+ context.window_manager.progress_update(5)
432
+
433
+ # モーフ追加
434
+ morph_count = 0
435
+ for data in misc_data:
436
+ if data['type'] == 'morph':
437
+ if morph_count == 0:
438
+ bpy.ops.object.shape_key_add(from_mix=False)
439
+ me.shape_keys.name = model_name1
440
+ shape_key = ob.shape_key_add(name=data['name'], from_mix=False)
441
+ for vert in data['data']:
442
+ co = vert['co']
443
+ co.x = -co.x
444
+ co *= self.scale
445
+ shape_key.data[vert['index']].co = shape_key.data[vert['index']].co + co
446
+ morph_count += 1
447
+ context.window_manager.progress_update(6)
448
+
449
+ # マテリアル追加
450
+ progress_count_total = 0.0
451
+ for data in material_data:
452
+ progress_count_total += len(data['data'])
453
+ progress_plus_value = 1.0 / progress_count_total
454
+ progress_count = 6.0
455
+
456
+ tex_storage_files = common.get_tex_storage_files()
457
+
458
+ face_seek = 0
459
+ for index, data in enumerate(material_data):
460
+ override = context.copy()
461
+ override['object'] = ob
462
+ bpy.ops.object.material_slot_add(override)
463
+ mate = context.blend_data.materials.new(data['name1'])
464
+ mate['shader1'] = data['name2']
465
+ mate['shader2'] = data['name3']
466
+
467
+ ob.material_slots[-1].material = mate
468
+ # 面にマテリアル割り当て
469
+ for i in range(face_seek, face_seek + len(face_data[index])):
470
+ me.polygons[i].material_index = index
471
+ face_seek += len(face_data[index])
472
+
473
+ # テクスチャ追加
474
+ already_texs = []
475
+ tex_index = 0
476
+ for tex_data in data['data']:
477
+
478
+ if common.preferences().mate_unread_same_value:
479
+ if tex_data['name'] in already_texs:
480
+ continue
481
+ already_texs.append(tex_data['name'])
482
+
483
+ if tex_data['type'] == 'tex':
484
+ slot = mate.texture_slots.create(tex_index)
485
+ tex = context.blend_data.textures.new(tex_data['name'], 'IMAGE')
486
+ slot.texture = tex
487
+ if tex_data['type2'] == 'tex2d':
488
+ slot.color = tex_data['color'][:3]
489
+ slot.diffuse_color_factor = tex_data['color'][3]
490
+ img = context.blend_data.images.new(tex_data['name2'], 128, 128)
491
+ img.filepath = tex_data['path']
492
+ img['cm3d2_path'] = tex_data['path']
493
+ img.source = 'FILE'
494
+ tex.image = img
495
+
496
+ # tex探し
497
+ if self.is_replace_cm3d2_tex:
498
+ if common.replace_cm3d2_tex(img, tex_storage_files) and tex_data['name']=='_MainTex':
499
+ for face in me.polygons:
500
+ if face.material_index == index:
501
+ me.uv_textures.active.data[face.index].image = img
502
+
503
+ elif tex_data['type'] == 'col':
504
+ slot = mate.texture_slots.create(tex_index)
505
+ mate.use_textures[tex_index] = False
506
+ slot.color = tex_data['color'][:3]
507
+ slot.diffuse_color_factor = tex_data['color'][3]
508
+ slot.use_rgb_to_intensity = True
509
+ tex = context.blend_data.textures.new(tex_data['name'], 'BLEND')
510
+ slot.texture = tex
511
+
512
+ elif tex_data['type'] == 'f':
513
+ slot = mate.texture_slots.create(tex_index)
514
+ mate.use_textures[tex_index] = False
515
+ slot.diffuse_color_factor = tex_data['float']
516
+ tex = context.blend_data.textures.new(tex_data['name'], 'BLEND')
517
+ slot.texture = tex
518
+
519
+ tex_index += 1
520
+
521
+ progress_count += progress_plus_value
522
+ context.window_manager.progress_update(progress_count)
523
+ common.decorate_material(mate, self.is_decorate, me, index)
524
+ ob.active_material_index = 0
525
+ context.window_manager.progress_update(7)
526
+
527
+ # メッシュ整頓
528
+ if self.is_remove_doubles:
529
+ pre_mesh_select_mode = context.tool_settings.mesh_select_mode[:]
530
+ context.tool_settings.mesh_select_mode = (True, False, False)
531
+
532
+ bpy.ops.object.mode_set(mode='EDIT')
533
+ bpy.ops.mesh.select_all(action='DESELECT')
534
+ bpy.ops.object.mode_set(mode='OBJECT')
535
+
536
+ for is_comparison, vert in zip(comparison_data, me.vertices):
537
+ if is_comparison:
538
+ vert.select = True
539
+ bpy.ops.object.mode_set(mode='EDIT')
540
+ bpy.ops.mesh.remove_doubles(threshold=0.000001)
541
+ bpy.ops.object.mode_set(mode='OBJECT')
542
+
543
+ context.tool_settings.mesh_select_mode = pre_mesh_select_mode
544
+ if self.is_seam:
545
+ bpy.ops.object.mode_set(mode='EDIT')
546
+ bpy.ops.mesh.select_all(action='SELECT')
547
+ bpy.ops.uv.seams_from_islands()
548
+ bpy.ops.object.mode_set(mode='OBJECT')
549
+ bpy.ops.object.mode_set(mode='EDIT')
550
+ bpy.ops.mesh.select_all(action='DESELECT')
551
+ bpy.ops.object.mode_set(mode='OBJECT')
552
+
553
+ if self.is_armature:
554
+ mod = ob.modifiers.new("Armature", 'ARMATURE')
555
+ mod.object = arm_ob
556
+ context.scene.objects.active = arm_ob
557
+ bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
558
+ context.scene.objects.active = ob
559
+ context.window_manager.progress_update(8)
560
+
561
+ # マテリアル情報のテキスト埋め込み
562
+ if self.is_mate_data_text:
563
+ for index, data in enumerate(material_data):
564
+ txt_name = "Material:" + str(index)
565
+ if txt_name in context.blend_data.texts:
566
+ txt = context.blend_data.texts[txt_name]
567
+ txt.clear()
568
+ else:
569
+ txt = context.blend_data.texts.new(txt_name)
570
+ txt.write("1000" + "\n")
571
+ txt.write(data['name1'].lower() + "\n")
572
+ txt.write(data['name1'] + "\n")
573
+ txt.write(data['name2'] + "\n")
574
+ txt.write(data['name3'] + "\n")
575
+ txt.write("\n")
576
+ for tex_data in data['data']:
577
+ txt.write(tex_data['type'] + "\n")
578
+ if tex_data['type'] == 'tex':
579
+ txt.write("\t" + tex_data['name'] + "\n")
580
+ txt.write("\t" + tex_data['type2'] + "\n")
581
+ if tex_data['type2'] == 'tex2d':
582
+ txt.write("\t" + tex_data['name2'] + "\n")
583
+ txt.write("\t" + tex_data['path'] + "\n")
584
+ col = " ".join([str(tex_data['color'][0]), str(tex_data['color'][1]), str(tex_data['color'][2]), str(tex_data['color'][3])])
585
+ txt.write("\t" + col + "\n")
586
+ elif tex_data['type'] == 'col':
587
+ txt.write("\t" + tex_data['name'] + "\n")
588
+ col = " ".join([str(tex_data['color'][0]), str(tex_data['color'][1]), str(tex_data['color'][2]), str(tex_data['color'][3])])
589
+ txt.write("\t" + col + "\n")
590
+ elif tex_data['type'] == 'f':
591
+ txt.write("\t" + tex_data['name'] + "\n")
592
+ txt.write("\t" + str(tex_data['float']) + "\n")
593
+ txt.current_line_index = 0
594
+ context.window_manager.progress_update(9)
595
+
596
+ # ボーン情報のテキスト埋め込み
597
+ if self.is_bone_data_text:
598
+ if "BoneData" in context.blend_data.texts:
599
+ txt = context.blend_data.texts["BoneData"]
600
+ txt.clear()
601
+ else:
602
+ txt = context.blend_data.texts.new("BoneData")
603
+ for i, data in enumerate(bone_data):
604
+ s = ",".join([data['name'], str(data['unknown']), ""])
605
+ parent_index = data['parent_index']
606
+ if -1 < parent_index:
607
+ s += bone_data[parent_index]['name'] + ","
608
+ else:
609
+ s += "None" + ","
610
+ s += " ".join([str(data['co'][0]), str(data['co'][1]), str(data['co'][2])]) + ","
611
+ s += " ".join([str(data['rot'][0]), str(data['rot'][1]), str(data['rot'][2]), str(data['rot'][3])])
612
+
613
+ if self.is_bone_data_text:
614
+ txt.write(s + "\n")
615
+ if self.is_mesh and self.is_bone_data_obj_property:
616
+ ob["BoneData:" + str(i)] = s
617
+ if self.is_armature and self.is_bone_data_arm_property:
618
+ arm["BoneData:" + str(i)] = s
619
+ if self.is_bone_data_text:
620
+ txt['BaseBone'] = model_name2
621
+ txt.current_line_index = 0
622
+ context.window_manager.progress_update(10)
623
+
624
+ # ローカルボーン情報のテキスト埋め込み
625
+ if self.is_bone_data_text:
626
+ if "LocalBoneData" in context.blend_data.texts:
627
+ txt = context.blend_data.texts["LocalBoneData"]
628
+ txt.clear()
629
+ else:
630
+ txt = context.blend_data.texts.new("LocalBoneData")
631
+ for i, data in enumerate(local_bone_data):
632
+ s = data['name'] + ","
633
+
634
+ mat_list = list(data['matrix'][0])
635
+ mat_list.extend(list(data['matrix'][1]))
636
+ mat_list.extend(list(data['matrix'][2]))
637
+ mat_list.extend(list(data['matrix'][3]))
638
+ for j, f in enumerate(mat_list):
639
+ mat_list[j] = str(f)
640
+ s += " ".join(mat_list)
641
+
642
+ if self.is_bone_data_text:
643
+ txt.write(s + "\n")
644
+ if self.is_mesh and self.is_bone_data_obj_property:
645
+ ob["LocalBoneData:" + str(i)] = s
646
+ if self.is_armature and self.is_bone_data_arm_property:
647
+ arm["LocalBoneData:" + str(i)] = s
648
+ if self.is_bone_data_text:
649
+ txt['BaseBone'] = model_name2
650
+ txt.current_line_index = 0
651
+
652
+ if self.is_mesh and self.is_bone_data_obj_property:
653
+ ob['BaseBone'] = model_name2
654
+ if self.is_armature and self.is_bone_data_arm_property:
655
+ arm['BaseBone'] = model_name2
656
+ context.window_manager.progress_end()
657
+
658
+ require_time_str = str(round(time.time() - start_time, 1))
659
+ filesize = os.path.getsize(self.filepath)
660
+ filesize_str = str(filesize) + " バイト"
661
+ if 1024 * 1024 < filesize:
662
+ filesize_str = str(round(filesize / (1024 * 1024.0), 1)) + " MB"
663
+ elif 1024 < filesize:
664
+ filesize_str = str(round(filesize / 1024.0, 1)) + " KB"
665
+ self.report(type={'INFO'}, message="Model Was Imported Successfuly (" + filesize_str + " / " + require_time_str + " Seconds)")
666
+
667
+ return {'FINISHED'}
668
+
669
+ # メニューを登録する関数
670
+ def menu_func(self, context):
671
+ self.layout.operator(import_cm3d2_model.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/tex_export.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bpy
2
+ import os
3
+ import struct
4
+ from . import common
5
+
6
+ class export_cm3d2_tex(bpy.types.Operator):
7
+ bl_idname = 'image.export_cm3d2_tex'
8
+ bl_label = "Save As .tex"
9
+ bl_description = "Current image will be saved as a (.tex)."
10
+ bl_options = {'REGISTER'}
11
+
12
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
13
+ filename_ext = ".tex"
14
+ filter_glob = bpy.props.StringProperty(default="*.tex", options={'HIDDEN'})
15
+
16
+ is_backup = bpy.props.BoolProperty(name="Backup", default=True, description="Overwritten files will be backed up.")
17
+
18
+ version = bpy.props.IntProperty(name="Version", default=1000, min=1000, max=1111, soft_min=1000, soft_max=1111, step=1)
19
+ path = bpy.props.StringProperty(name="Path", default="assets/texture/texture/*.png")
20
+
21
+ @classmethod
22
+ def poll(cls, context):
23
+ img = context.edit_image
24
+ if img:
25
+ if len(img.pixels) or img.source == 'VIEWER':
26
+ return True
27
+ return False
28
+
29
+ def invoke(self, context, event):
30
+ img = context.edit_image
31
+ if img.filepath:
32
+ common.preferences().tex_export_path = bpy.path.abspath(img.filepath)
33
+ if common.preferences().tex_default_path:
34
+ self.filepath = common.default_cm3d2_dir(common.preferences().tex_default_path, common.remove_serial_number(img.name), "tex")
35
+ else:
36
+ self.filepath = common.default_cm3d2_dir(common.preferences().tex_export_path, common.remove_serial_number(img.name), "tex")
37
+ self.is_backup = bool(common.preferences().backup_ext)
38
+ if 'cm3d2_path' in img:
39
+ self.path = img['cm3d2_path']
40
+ else:
41
+ self.path = "assets/texture/texture/" + os.path.basename(self.filepath)
42
+ if 'tex Name' in img:
43
+ self.filepath = os.path.join(os.path.dirname(self.filepath), img['tex Name'])
44
+ context.window_manager.fileselect_add(self)
45
+ return {'RUNNING_MODAL'}
46
+
47
+ def draw(self, context):
48
+ row = self.layout.row()
49
+ row.prop(self, 'is_backup', icon='FILE_BACKUP')
50
+ if not common.preferences().backup_ext:
51
+ row.enabled = False
52
+ self.layout.prop(self, 'version', icon='LINENUMBERS_ON')
53
+ self.layout.prop(self, 'path', icon='ANIM')
54
+
55
+ def execute(self, context):
56
+ common.preferences().tex_export_path = self.filepath
57
+
58
+ try:
59
+ file = common.open_temporary(self.filepath, 'wb', is_backup=self.is_backup)
60
+ except:
61
+ self.report(type={'ERROR'}, message="Failed to save file, possibly inaccessible.")
62
+ return {'CANCELLED'}
63
+
64
+ try:
65
+ with file:
66
+ self.write_texture(context, file)
67
+ except common.CM3D2ExportException as e:
68
+ self.report(type={'ERROR'}, message=str(e))
69
+ return {'CANCELLED'}
70
+
71
+ return {'FINISHED'}
72
+
73
+ def write_texture(self, context, file):
74
+ # とりあえずpngで保存
75
+ img = context.edit_image
76
+ if img.source != 'VIEWER':
77
+ temp_path = self.filepath + ".temp.png"
78
+ else:
79
+ temp_path = os.path.splitext(self.filepath)[0] + ".png"
80
+ pre_filepath = bpy.path.abspath(img.filepath)
81
+ pre_source = img.source
82
+ override = context.copy()
83
+ override['edit_image'] = img
84
+ try:
85
+ save_as_render = True if pre_source == 'VIEWER' else False
86
+ copy = True if pre_source == 'VIEWER' else False
87
+ bpy.ops.image.save_as(override, save_as_render=save_as_render, copy=copy, filepath=temp_path, relative_path=True, show_multiview=False, use_multiview=False)
88
+ is_remove = True
89
+ except:
90
+ if os.path.exists( bpy.path.abspath(img.filepath) ):
91
+ temp_path = bpy.path.abspath(img.filepath)
92
+ is_remove = False
93
+ else:
94
+ raise common.CM3D2ExportException("Could not export .tex file.")
95
+ if pre_source != 'VIEWER':
96
+ img.filepath = pre_filepath
97
+ img.source = pre_source
98
+
99
+ # pngバイナリを全て読み込み
100
+ with open(temp_path, 'rb') as temp_file:
101
+ temp_data = temp_file.read()
102
+ # 一時ファイルを削除
103
+ if is_remove:
104
+ os.remove(temp_path)
105
+
106
+ # 本命ファイルに書き込み
107
+ common.write_str(file, 'CM3D2_TEX')
108
+ file.write(struct.pack('<i', self.version))
109
+ common.write_str(file, self.path)
110
+ file.write(struct.pack('<i', len(temp_data)))
111
+ file.write(temp_data)
112
+
113
+ # メニューを登録する関数
114
+ def menu_func(self, context):
115
+ self.layout.operator(export_cm3d2_tex.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Converter (English)/tex_import.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, os.path, bpy, struct, os.path
2
+ from . import common
3
+
4
+ class import_cm3d2_tex(bpy.types.Operator):
5
+ bl_idname = 'image.import_cm3d2_tex'
6
+ bl_label = "Import .tex"
7
+ bl_description = "Imports a CM3D2 tex file (.tex)"
8
+ bl_options = {'REGISTER'}
9
+
10
+ filepath = bpy.props.StringProperty(subtype='FILE_PATH')
11
+ filename_ext = ".tex;.png"
12
+ filter_glob = bpy.props.StringProperty(default="*.tex;*.png", options={'HIDDEN'})
13
+
14
+ items = [
15
+ ('PACK', "Package", "", 'PACKAGE', 1),
16
+ ('PNG', "Opens or converts to png", "", 'IMAGE_DATA', 2),
17
+ ]
18
+ mode = bpy.props.EnumProperty(items=items, name="Mode", default='PNG')
19
+
20
+ def invoke(self, context, event):
21
+ if common.preferences().tex_default_path:
22
+ self.filepath = common.default_cm3d2_dir(common.preferences().tex_default_path, "", "tex")
23
+ else:
24
+ self.filepath = common.default_cm3d2_dir(common.preferences().tex_import_path, "", "tex")
25
+ context.window_manager.fileselect_add(self)
26
+ return {'RUNNING_MODAL'}
27
+
28
+ def draw(self, context):
29
+ box = self.layout.box()
30
+ col = box.column(align=True)
31
+ col.label(text="Mode", icon='FILESEL')
32
+ col.prop(self, 'mode', icon='FILESEL', expand=True)
33
+
34
+ def execute(self, context):
35
+ common.preferences().tex_import_path = self.filepath
36
+ try:
37
+ file = open(self.filepath, 'rb')
38
+ except:
39
+ self.report(type={'ERROR'}, message="Failed to open the file, it does not exist or is inaccessible")
40
+ return {'CANCELLED'}
41
+ header_ext = common.read_str(file)
42
+ if header_ext == 'CM3D2_TEX':
43
+ file.seek(4, 1)
44
+ in_path = common.read_str(file)
45
+ png_size = struct.unpack('<i', file.read(4))[0]
46
+ root, ext = os.path.splitext(self.filepath)
47
+ png_path = root + ".png"
48
+ is_png_overwrite = os.path.exists(png_path)
49
+ if self.mode == 'PACK' and is_png_overwrite:
50
+ png_path += ".temp.png"
51
+ png_file = open(png_path, 'wb')
52
+ png_file.write(file.read(png_size))
53
+ png_file.close()
54
+ bpy.ops.image.open(filepath=png_path)
55
+ img = context.edit_image
56
+ img.name = os.path.basename(self.filepath)
57
+ img['cm3d2_path'] = in_path
58
+ else:
59
+ bpy.ops.image.open(filepath=self.filepath)
60
+ img = context.edit_image
61
+ file.close()
62
+ if self.mode == 'PACK':
63
+ img.pack(as_png=True)
64
+ if header_ext == 'CM3D2_TEX':
65
+ os.remove(png_path)
66
+ return {'FINISHED'}
67
+
68
+ # メニューを登録する関数
69
+ def menu_func(self, context):
70
+ self.layout.separator()
71
+ self.layout.operator(import_cm3d2_tex.bl_idname, icon_value=common.preview_collections['main']['KISS'].icon_id)
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/CM3D2 Mod Search.exe ADDED
Binary file (88.6 kB). View file
 
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/CM3D2 Mod Search.html ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <meta charset="utf-8">
4
+ <title>CM3D2 Mod Search 「noire」Search Results</title>
5
+ <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
6
+ </head>
7
+ <body>
8
+ <table cellspacing="0" class="table table-small-font table-hover">
9
+ <thead>
10
+ <tr bgcolor=#ffc692>
11
+ <th><span class="glyphicon glyphicon-file" aria-hidden="true"></span>ファイル</th>
12
+ <th>コメント</th>
13
+ <th data-priority="5">オリジナル</th>
14
+ <th data-priority="4">容量</th>
15
+ <th data-priority="3">日時</th>
16
+ <th><span class="glyphicon glyphicon-cloud-download" aria-hidden="true"></span></th>
17
+ <th> <span class="glyphicon glyphicon-edit" aria-hidden="true"></span></th>
18
+ </tr>
19
+ </thead>
20
+ </table>
21
+ </body>
22
+ </html>
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/CM3D2 Mod Search.ini ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ [Settings]
2
+ URLs=http://ux.getuploader.com/cm3d2/,http://ux.getuploader.com/cm3d2_b/,http://ux.getuploader.com/cm3d2_c/,http://ux.getuploader.com/cm3d2_d/,http://ux.getuploader.com/cm3d2_e/,http://ux.getuploader.com/cm3d2_f/,http://ux.getuploader.com/cm3d2_g/
3
+ RecentSearchWords=noire,
4
+ [Window]
5
+ X=100
6
+ Y=100
7
+ W=800
8
+ H=600
9
+ State=Normal
vae/com3d/[CM3D2]English Mod Tools Pack/CM3D2 Mod Search (English)/Readme & Modder List.txt ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This neat little tool will quickly search any inserted uploaders for whatever keywords you type in.
2
+ it will then show you the results in a neat and concise list.
3
+
4
+ Below are a bunch of modder sites. Feel free to add these to the search list inside of the app.
5
+
6
+ I take no credit for the creation of this app and only for it's translation.
7
+
8
+
9
+ http://ux.getuploader.com/cm3d2/
10
+ http://ux.getuploader.com/cm3d2_b/
11
+ http://ux.getuploader.com/cm3d2_c/
12
+ http://ux.getuploader.com/cm3d2_d/
13
+ http://ux.getuploader.com/cm3d2_e/
14
+ http://ux.getuploader.com/cm3d2_f/
15
+ http://ux.getuploader.com/cm3d2_g/
16
+
17
+ http://ux.getuploader.com/072pro_staff/
18
+ http://ux.getuploader.com/24674/
19
+ http://ux.getuploader.com/2501b/
20
+ http://ux.getuploader.com/99lI_MOD/
21
+ http://ux.getuploader.com/Akatsuki_MOD/
22
+ http://ux.getuploader.com/AllCancel/
23
+ http://ux.getuploader.com/Amaterasunyan/
24
+ http://ux.getuploader.com/Brandish_mod/
25
+ http://ux.getuploader.com/CANTUSandNATURE_01/
26
+ http://ux.getuploader.com/CM3D2MODhanger/
27
+ http://ux.getuploader.com/CM3D2_a901/
28
+ http://ux.getuploader.com/CM3D2_fyi/
29
+ http://ux.getuploader.com/CM3D2mod_08860/
30
+ http://ux.getuploader.com/CMsande_tu_/
31
+ http://ux.getuploader.com/C_take/
32
+ http://ux.getuploader.com/DV_CM3D2_A/
33
+ http://ux.getuploader.com/Eastpoint/
34
+ http://ux.getuploader.com/Extra_B/
35
+ http://ux.getuploader.com/FestaSia_cm3d2/
36
+ http://ux.getuploader.com/GentlemenX/
37
+ http://ux.getuploader.com/HEXAworks/
38
+ http://ux.getuploader.com/IBE/
39
+ http://ux.getuploader.com/KAAN/
40
+ http://ux.getuploader.com/Kikka_Sora/
41
+ http://ux.getuploader.com/LN_preset/
42
+ http://ux.getuploader.com/LaiNC519/
43
+ http://ux.getuploader.com/Lan/
44
+ http://ux.getuploader.com/MISTERJUICE/
45
+ http://ux.getuploader.com/Merchantscache_/
46
+ http://ux.getuploader.com/NekohigeLoda/
47
+ http://ux.getuploader.com/NewSportsX/
48
+ http://ux.getuploader.com/P90X/
49
+ http://ux.getuploader.com/Permafrost_mod_Refrigerator/
50
+ http://ux.getuploader.com/Picomagic/
51
+ http://ux.getuploader.com/Pot_lemon/
52
+ http://ux.getuploader.com/SDK251/
53
+ http://ux.getuploader.com/SDK251_b/
54
+ http://ux.getuploader.com/Satoshi_HiMEz_CM3D2MOD/
55
+ http://ux.getuploader.com/Stuk4Mephisto/
56
+ http://ux.getuploader.com/Su_WH/
57
+ http://ux.getuploader.com/Summer_flights/
58
+ http://ux.getuploader.com/Taker_3D/
59
+ http://ux.getuploader.com/YXQ/
60
+ http://ux.getuploader.com/YYY333/
61
+ http://ux.getuploader.com/YaYeah/
62
+ http://ux.getuploader.com/acer1234040/
63
+ http://ux.getuploader.com/acer1234040smod/
64
+ http://ux.getuploader.com/actA_M10/
65
+ http://ux.getuploader.com/ajicalipton/
66
+ http://ux.getuploader.com/akabane99/
67
+ http://ux.getuploader.com/akathuki01/
68
+ http://ux.getuploader.com/akau4590/
69
+ http://ux.getuploader.com/amb_cm3d2/
70
+ http://ux.getuploader.com/amecloud/
71
+ http://ux.getuploader.com/ash_cm3d2/
72
+ http://ux.getuploader.com/blade_ero/
73
+ http://ux.getuploader.com/butagoya_s/
74
+ http://ux.getuploader.com/cgmuploader/
75
+ http://ux.getuploader.com/cm3d2_Wellvin/
76
+ http://ux.getuploader.com/cm3d2_glossmod/
77
+ http://ux.getuploader.com/cm3d2_helmi/
78
+ http://ux.getuploader.com/cm3d2_marderleone/
79
+ http://ux.getuploader.com/cm3d2_okm/
80
+ http://ux.getuploader.com/cm3d2_snow1/
81
+ http://ux.getuploader.com/cm3d2mod_usac/
82
+ http://ux.getuploader.com/cm3d_fake/
83
+ http://ux.getuploader.com/cmzmrrd/
84
+ http://ux.getuploader.com/customP/
85
+ http://ux.getuploader.com/cycy_harmony/
86
+ http://ux.getuploader.com/drago_00/
87
+ http://ux.getuploader.com/eclipsexxx/
88
+ http://ux.getuploader.com/econo_cm3d2/
89
+ http://ux.getuploader.com/eden_bakamaid/
90
+ http://ux.getuploader.com/eixaregood/
91
+ http://ux.getuploader.com/errafile001/
92
+ http://ux.getuploader.com/es45as/
93
+ http://ux.getuploader.com/exenrar/
94
+ http://ux.getuploader.com/fatelok/
95
+ http://ux.getuploader.com/fel666/
96
+ http://ux.getuploader.com/fenz_cm3d2/
97
+ http://ux.getuploader.com/fr1ed_cm3d2mod/
98
+ http://ux.getuploader.com/futanarichinko/
99
+ http://ux.getuploader.com/galleBlizzg/
100
+ http://ux.getuploader.com/gramcm3d2/
101
+ http://ux.getuploader.com/gucci3_a/
102
+ http://ux.getuploader.com/hads/
103
+ http://ux.getuploader.com/hagesaki_mod/
104
+ http://ux.getuploader.com/hashiokiva/
105
+ http://ux.getuploader.com/hatena37/
106
+ http://ux.getuploader.com/hexbox/
107
+ http://ux.getuploader.com/himuro35/
108
+ http://ux.getuploader.com/homuhomudkawaii/
109
+ http://ux.getuploader.com/honoka391/
110
+ http://ux.getuploader.com/hukami_souka/
111
+ http://ux.getuploader.com/ianman1110/
112
+ http://ux.getuploader.com/insight_MOD/
113
+ http://ux.getuploader.com/jmikam/
114
+ http://ux.getuploader.com/kafil/
115
+ http://ux.getuploader.com/kamonan/
116
+ http://ux.getuploader.com/kazami/
117
+ http://ux.getuploader.com/kensancmmodup/
118
+ http://ux.getuploader.com/kim841213/
119
+ http://ux.getuploader.com/kirisima_presets/
120
+ http://ux.getuploader.com/kk_loader/
121
+ http://ux.getuploader.com/kura_gee/
122
+ http://ux.getuploader.com/kuroto_CM3D2/
123
+ http://ux.getuploader.com/liktomaid/
124
+ http://ux.getuploader.com/lithla/
125
+ http://ux.getuploader.com/maid_yasen/
126
+ http://ux.getuploader.com/maidinnet_01/
127
+ http://ux.getuploader.com/makaroninoana/
128
+ http://ux.getuploader.com/manbo_uploader/
129
+ http://ux.getuploader.com/maro_hato/
130
+ http://ux.getuploader.com/masarun001/
131
+ http://ux.getuploader.com/maumauhanna/
132
+ http://ux.getuploader.com/melala001/
133
+ http://ux.getuploader.com/mikan07/
134
+ http://ux.getuploader.com/mikenuko_uproda/
135
+ http://ux.getuploader.com/mikenuko_uproda02/
136
+ http://ux.getuploader.com/milky_mh_craft/
137
+ http://ux.getuploader.com/minami_cm3d2/
138
+ http://ux.getuploader.com/minittogoma/
139
+ http://ux.getuploader.com/mmm_CM3D2_666/
140
+ http://ux.getuploader.com/modcm3d2izk/
141
+ http://ux.getuploader.com/mogga13/
142
+ http://ux.getuploader.com/monotoneclub/
143
+ http://ux.getuploader.com/motto/
144
+ http://ux.getuploader.com/my_cm3d2_up/
145
+ http://ux.getuploader.com/mycm3d2mod/
146
+ http://ux.getuploader.com/n777_mod/
147
+ http://ux.getuploader.com/nabeochang/
148
+ http://ux.getuploader.com/nabetajin_dress/
149
+ http://ux.getuploader.com/nashiro355/
150
+ http://ux.getuploader.com/nekoko_cm3d2_mod/
151
+ http://ux.getuploader.com/nicocchi25/
152
+ http://ux.getuploader.com/nobelchoco/
153
+ http://ux.getuploader.com/nomorehelpaa/
154
+ http://ux.getuploader.com/nora151104/
155
+ http://ux.getuploader.com/nose_i_xxx_CM3D2/
156
+ http://ux.getuploader.com/opqrstu/
157
+ http://ux.getuploader.com/owl_no_uploader/
158
+ http://ux.getuploader.com/polaris001/
159
+ http://ux.getuploader.com/ponyori/
160
+ http://ux.getuploader.com/popopo_cm3d2/
161
+ http://ux.getuploader.com/purioji/
162
+ http://ux.getuploader.com/qqyp/
163
+ http://ux.getuploader.com/queserasera30/
164
+ http://ux.getuploader.com/quick_quit_001/
165
+ http://ux.getuploader.com/real0311/
166
+ http://ux.getuploader.com/reaper7092/
167
+ http://ux.getuploader.com/reason4/
168
+ http://ux.getuploader.com/reisen3d2/
169
+ http://ux.getuploader.com/reynnoapuroda_cm3d2/
170
+ http://ux.getuploader.com/ro_cm3d2/
171
+ http://ux.getuploader.com/route163/
172
+ http://ux.getuploader.com/ryow_GX_up/
173
+ http://ux.getuploader.com/saidenka_cm3d2/
174
+ http://ux.getuploader.com/salvia_cm3d2/
175
+ http://ux.getuploader.com/sangarianmodcm3d2/
176
+ http://ux.getuploader.com/saphir/
177
+ http://ux.getuploader.com/sasagami/
178
+ http://ux.getuploader.com/satyam/
179
+ http://ux.getuploader.com/sekayuri/
180
+ http://ux.getuploader.com/settun_kossori/
181
+ http://ux.getuploader.com/siromiso/
182
+ http://ux.getuploader.com/skfc_43/
183
+ http://ux.getuploader.com/squids/
184
+ http://ux.getuploader.com/suikoron/
185
+ http://ux.getuploader.com/syano_mod/
186
+ http://ux.getuploader.com/takahashiren/
187
+ http://ux.getuploader.com/tarutarutaru/
188
+ http://ux.getuploader.com/ten4chan/
189
+ http://ux.getuploader.com/test_20160728/
190
+ http://ux.getuploader.com/tfa404953b/
191
+ http://ux.getuploader.com/thethe/
192
+ http://ux.getuploader.com/tk_CM3D2/
193
+ http://ux.getuploader.com/tokinagare/
194
+ http://ux.getuploader.com/toshizi0001/
195
+ http://ux.getuploader.com/trzr_tool/
196
+ http://ux.getuploader.com/umiushi555/
197
+ http://ux.getuploader.com/unyohonyoho/
198
+ http://ux.getuploader.com/uproda114514/
199
+ http://ux.getuploader.com/wahyu_azunyan/
200
+ http://ux.getuploader.com/wakewakame/
201
+ http://ux.getuploader.com/wasabi_mod/
202
+ http://ux.getuploader.com/webhaikyoyoteichi/
203
+ http://ux.getuploader.com/wei/
204
+ http://ux.getuploader.com/wjccc/
205
+ http://ux.getuploader.com/x5993279/
206
+ http://ux.getuploader.com/xxHiryuxx/
207
+ http://ux.getuploader.com/yakinD/
208
+ http://ux.getuploader.com/yamadatarou3/
209
+ http://ux.getuploader.com/yuizero/
210
+ http://ux.getuploader.com/yuki_okiba/
211
+ http://ux.getuploader.com/yuunagimizuki/
212
+ http://ux.getuploader.com/z5517356/
213
+ http://ux.getuploader.com/zerogm10/
vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/Dictionary and How to.txt ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ General:
2
+ File Version = If there are two or more of the same .menu, the one with the highest number will be loaded
3
+ Name = Name of the item (Maximal Number of Characters TBD) Do not edit!
4
+ Describe = Description of the item (Maximal Number of Characters TBD, Maximal Number of Lines: 3?) Do not edit!
5
+ For Copy and Paste = Use �s���s�t to start a new line in the description
6
+ txt path = path to the txt (need more info)
7
+ ���j���[�t�H���_ = Menu folder, there are DRESS... (and BODY? need more info)
8
+ category = Category in which the Menu Icon will appear (Reference List at the Bottom)
9
+ catno = ? (category number? where it will be placed in the category?
10
+ �����lj� = Attribute added? Known attributes in the reference list
11
+ priority = priority will state where the icon will appear. the lower the priority the higher in the list the mod appears.
12
+ name = Name of the item (Maximal Number of Characters TBD)
13
+ setumei = Description of the item (Maximal Number of Characters TBD, Maximal Number of Lines: 3?)
14
+ icons = Icon Texture for the Mod in .tex format
15
+ onclickmenu =
16
+ �A�C�e���p�����[�^ = Item paramters?
17
+ �A�C�e�� = Item (call additional .menu to e.g remove two of these three when selecting teh third: Top, Swimsuit, One-Piece)
18
+ additem = Model for the Mod in .model format (and category)
19
+ maskitem = Categories that will be hidden when this piece is visible, additionally to the ones in the reference list/replacing: Nipples have accNipL and accNipR for Left and Right
20
+ �}�e���A���ύX = Material change. Is useful for setting a quick Material swap.
21
+ ���\�[�X�Q�� = Resource reference
22
+ node���� = node erase (Nodes erase or display certains parts of a maids body associated with the vertex group name.)
23
+ node�\�� = node display (Nodes erase or display certains parts of a maids body associated with the vertex group name.)
24
+ �A�C�e���ꎞ�I�ɓK�p = Items temporarily applied (Also used for removing?)
25
+ �J�X�� = Kasumi?
26
+ ���� = if (cases)
27
+ �I�� = end
28
+
29
+
30
+
31
+ If cases:
32
+ �J�X����panz
33
+ �� = But
34
+ ���� = Invalid
35
+ �Ȃ� = Nara?
36
+
37
+
38
+ Nodes:
39
+ Spine1
40
+ Spine1a
41
+ Uppertwist
42
+ Forearm
43
+ Foretwist
44
+ Hand
45
+ Mune
46
+ None
47
+ ����node�ݒ�I�� = Erasure node setting end
48
+ �V�i���I�p�[�g�J�n = Scenario Part start
49
+ ���h���X�A�b�v���ɃN���b�N���ꂽ���̏��� = �� processing when it is clicked in the dress-up
50
+
51
+
52
+
53
+ Attributes:
54
+ �������\�����Ȃ� = Do not show possession of the number of
55
+
56
+ Clothes:
57
+ --acchat = Hat
58
+ --head = Headdress
59
+ --wear = Top
60
+ --skrt = Bottom
61
+ --onep = One Piece
62
+ --mizugi = Swimsuit
63
+ --bra = Bra
64
+ --pants = Panties
65
+ --stkg = Socks
66
+ --shoe = Shoes
67
+ Accessory
68
+ -acckami = Front Hair
69
+ -megane = glasses
70
+ -acchead = Eye Mask
71
+ -acchana = Nose
72
+ -accmimi = Ears
73
+ -gloves = Gloves
74
+ -acckubi= Necklace
75
+ -acckubiwa = Choker
76
+ -acckamisub = Ribbon
77
+ -accnip = Nipples
78
+ -accude = Arms
79
+ -accesho = Belly
80
+ -accashi = Ankles
81
+ -accsenaka = Back
82
+ -accshippo = Tail
83
+ -accxxx = Genitals
84
+ Head
85
+ -face = Face
86
+ -eye_brow = Eyebrows
87
+ -eye = Eyes
88
+ -eye_hi = Highlights
89
+ -hokoro = Moles
90
+ -lip = Lips
91
+ -accha = Teeth
92
+ Hair
93
+ -hair_f = Front Hair
94
+ -hair_r = Back Hair
95
+ -hair_side = Side Hair
96
+ -hair_twin or hair_pony = Extensions
97
+ -hair_aho = Ahoge
98
+ Body
99
+ -skin = Skin
100
+ -chikubi = Nipples
101
+ -tatoo = Tattoos
102
+ -underhair = Pubic hair
vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/[CM3D2]menuEdit.exe ADDED
Binary file (828 kB). View file
 
vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/readme.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Original JP Version taken from cm3d2_d_84.
2
+ Translated and explained for easy international usage and newcomers by SakuraKoi with the help of the Hongfire Community.
3
+
4
+ -4/20/2017: Tiny edit by krypto5863
vae/com3d/[CM3D2]English Mod Tools Pack/MenuEdit2017420/src/[CM3D2]menuEdit.ahk ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #NoTrayIcon
2
+ FileEncoding, UTF-8-RAW
3
+ #SingleInstance OFF
4
+ SetFormat, float, 0.10
5
+ #NoTrayIcon
6
+
7
+ file_path = %1%
8
+ Loop {
9
+ if (file_path == "") {
10
+ default_path := GetDefaultPath()
11
+ FileSelectFile, file_path, 3, %default_path%, Select a .menu File, Menu File(*.menu)
12
+ }
13
+ if (ErrorLevel == 1) {
14
+ ExitApp
15
+ }
16
+ if (FileExist(file_path) == "") {
17
+ Msgbox, The file does not exist
18
+ file_path := ""
19
+ }
20
+ else {
21
+ break
22
+ }
23
+ }
24
+ file := FileOpen(file_path, "r")
25
+ if (file.Read(file.ReadChar()) != "CM3D2_MENU") {
26
+ MsgBox, This is not a menu file for Custom Maid 3D 2
27
+ ExitApp
28
+ }
29
+
30
+ data := Object()
31
+
32
+ version := file.ReadInt()
33
+ path := ReadString(file)
34
+ name := ReadString(file)
35
+ category := ReadString(file)
36
+ setumei := ReadString(file)
37
+
38
+ end_pos := file.ReadInt() + file.tell() - 1
39
+ Loop, 9999 {
40
+ index := A_Index
41
+ local_size := file.ReadChar()
42
+ Loop, %local_size% {
43
+ data[index, A_Index] := ReadString(file)
44
+ }
45
+ data_size := index
46
+ if (end_pos <= file.tell()) {
47
+ break
48
+ }
49
+ }
50
+ file.Close()
51
+
52
+ SplitPath, file_path, OutFileName, OutDir, OutExtension, OutNameNoExt, OutDrive
53
+ Gui, Add, Text, xm0 ym0 W400 H20 Center, %A_Space%%OutFileName%
54
+ Gui, Add, Text, x+0 yp+0 W100 H20 Center, For Copy and Paste
55
+ Gui, Add, Edit, x+0 yp+0 W125 H20 ReadOnly, 《改行》
56
+
57
+ Gui, Add, Text, xm0 y+0 W100 H20 Center, %A_Space%%A_Space%File Version
58
+ Gui, Add, Edit, x+0 yp+0 W100 H20 VGversion, %version%
59
+ Gui, Add, Text, x+0 yp+0 W75 H20 Center, %A_Space%%A_Space%Name
60
+ Gui, Add, Edit, x+0 yp+0 W350 H20 VGname, %name%
61
+
62
+ Gui, Add, Text, xm0 y+0 W100 H20 Center, %A_Space%%A_Space%Category
63
+ Gui, Add, Edit, x+0 yp+0 W100 H20 VGcategory, %category%
64
+ Gui, Add, Text, x+0 yp+0 W75 H20 Center, %A_Space%%A_Space%Description
65
+ Gui, Add, Edit, x+0 yp+0 W350 H20 VGsetumei, %setumei%
66
+
67
+ Gui, Add, Text, xm0 y+0 W100 H20 Center, %A_Space%%A_Space%txt path
68
+ Gui, Add, Edit, x+0 yp+0 W525 H20 VGpath, %path%
69
+
70
+ Gui, Add, TreeView, xm0 W625 R32 -ReadOnly
71
+
72
+ Gui, Add, Button, xm0 y+5 W100 H20 GUtilAdd, New Parent
73
+ Gui, Add, Button, x+0 yp+0 W100 H20 GUtilAddChild, New Child
74
+ Gui, Add, Button, x+325 yp+0 W100 H20 GUtilDel, Delete
75
+
76
+ Gui, Add, Button, xm0 y+5 W625 H50 GMySubmit, Save
77
+
78
+ Loop, %data_size% {
79
+ index := A_Index
80
+ id := TV_Add(data[index, 1], 0, "Expand")
81
+ local_size := data[index].MaxIndex()
82
+ Loop, %local_size% {
83
+ if (A_Index == 1) {
84
+ continue
85
+ }
86
+ TV_Add(data[index, A_Index], id)
87
+ }
88
+ }
89
+
90
+ Gui, Show, AutoSize
91
+ return
92
+
93
+ GetStringLength(string) {
94
+ count = 0
95
+ Loop, Parse, string
96
+ {
97
+ if (RegExMatch(A_LoopField, "^[^\x01-\x7E]$") != 0) {
98
+ count += 3
99
+ }
100
+ else {
101
+ count += 1
102
+ }
103
+ }
104
+ return count
105
+ }
106
+
107
+ ReadString(file, size=-1) {
108
+ if (size <= -1) {
109
+ size := 0
110
+ chars := Object()
111
+ Loop {
112
+ char := file.ReadUChar()
113
+ chars[A_Index] := char
114
+ if (char < 128) {
115
+ break
116
+ }
117
+ }
118
+ num := GetMaxIndex(chars)
119
+ Loop, %num% {
120
+ char := chars[A_Index]
121
+ multi := 256 ** (A_Index - 1)
122
+ size += char * multi
123
+ if (1 < A_Index) {
124
+ size -= (multi / 2) * (char + 1)
125
+ }
126
+ }
127
+ }
128
+ string := ""
129
+ count = 0
130
+ Loop, 9999 {
131
+ if (size <= count) {
132
+ break
133
+ }
134
+ s := file.Read(1)
135
+ string := string . s
136
+ count += GetStringLength(s)
137
+ if (GetStringLength(s) == 0) {
138
+ pos := file.Pos
139
+ MsgBox, Failed to read the file(place: %pos%)`n Quit
140
+ ExitApp
141
+ }
142
+ }
143
+ return string
144
+ }
145
+
146
+ WriteString(file, string) {
147
+ len := GetStringLength(string)
148
+ if (128 <= len) {
149
+ temp := Mod(len, 128) + 128
150
+ file.WriteChar(temp)
151
+ temp := Floor(len / 128)
152
+ file.WriteChar(temp)
153
+ }
154
+ else {
155
+ file.WriteChar(len)
156
+ }
157
+ file.Write(string)
158
+ }
159
+
160
+ GetMaxIndex(obj) {
161
+ value := obj.MaxIndex()
162
+ if (value == "") {
163
+ return 0
164
+ }
165
+ return value
166
+ }
167
+
168
+ GetDefaultPath() {
169
+ RegRead, path, HKEY_CURRENT_USER, Software\KISS\カスタムメイド3D2, InstallPath
170
+ if (ErrorLevel == 0) {
171
+ path = %path%GameData\
172
+ }
173
+ else {
174
+ path := A_ScriptDir
175
+ }
176
+ return path
177
+ }
178
+
179
+ UtilAdd:
180
+ InputBox, new_name, , Please enter the name of the new parent
181
+ if (ErrorLevel == 0){
182
+ TV_Add(new_name, 0, "Expand")
183
+ }
184
+ return
185
+ UtilAddChild:
186
+ parent := TV_GetSelection()
187
+ if (parent == 0) {
188
+ MsgBox, Please select an item
189
+ return
190
+ }
191
+ if (TV_GetParent(parent) != 0) {
192
+ parent := TV_GetParent(parent)
193
+ }
194
+ InputBox, new_name, , Please enter a name for the new child
195
+ if (ErrorLevel == 0){
196
+ TV_Add(new_name, parent, "Expand")
197
+ }
198
+ return
199
+ UtilDel:
200
+ selected := TV_GetSelection()
201
+ if (selected == 0) {
202
+ MsgBox, Please select an item
203
+ return
204
+ }
205
+ TV_Delete(selected)
206
+ return
207
+
208
+ MySubmit:
209
+ Gui, Submit, NoHide
210
+
211
+ temp_file := FileOpen(file_path . ".temp", "w")
212
+ parent_id = 0
213
+ Loop {
214
+ parent_id := TV_GetNext(parent_id)
215
+ if (parent_id == 0) {
216
+ break
217
+ }
218
+ TV_GetText(name, parent_id)
219
+ child_id := TV_GetChild(parent_id)
220
+ childs := Object()
221
+ if (child_id != 0) {
222
+ Loop {
223
+ TV_GetText(string, child_id)
224
+ childs[A_Index] := string
225
+ child_id := TV_GetNext(child_id)
226
+ if (child_id == 0) {
227
+ break
228
+ }
229
+ }
230
+ }
231
+ max := childs.MaxIndex()
232
+ if (max == "") {
233
+ temp_file.WriteChar(1)
234
+ }
235
+ else {
236
+ temp_file.WriteChar(max + 1)
237
+ }
238
+ WriteString(temp_file, name)
239
+ Loop, %max% {
240
+ string := childs[A_Index]
241
+ WriteString(temp_file, string)
242
+ }
243
+ }
244
+ temp_file.WriteChar(0)
245
+ temp_file.close()
246
+ temp_file := FileOpen(file_path . ".temp", "r")
247
+
248
+ file := FileOpen(file_path, "w")
249
+
250
+ file.WriteChar(10)
251
+ file.Write("CM3D2_MENU")
252
+ file.WriteInt(Gversion)
253
+
254
+ WriteString(file, Gpath)
255
+ WriteString(file, Gname)
256
+ WriteString(file, Gcategory)
257
+ WriteString(file, Gsetumei)
258
+
259
+ file.WriteInt(temp_file.Length)
260
+ temp_file.RawRead(data, temp_file.Length)
261
+ file.RawWrite(data, temp_file.Length)
262
+
263
+ file.close()
264
+ temp_file.close()
265
+ FileDelete, %file_path%.temp
266
+
267
+ SplitPath, file_path, OutFileName, OutDir, OutExtension, OutNameNoExt, OutDrive
268
+ MsgBox, %OutFileName% has been saved
269
+ return
270
+
271
+ GuiEscape:
272
+ GuiClose:
273
+ ExitApp
274
+ return