Compare commits
19 Commits
v3.0-alpha
...
v3.3
Author | SHA1 | Date | |
---|---|---|---|
12d5f8c236 | |||
6fe856fa8e | |||
c2a85a2d86 | |||
dafb679780 | |||
f3663a4280 | |||
9c8d365ab6 | |||
0be036fcea | |||
e153e51abd | |||
d292ce389a | |||
807e006245 | |||
8d7a982e50 | |||
ddf6b7befe | |||
a300ddbb49 | |||
c9e51c9b6a | |||
b58f837a94 | |||
5fe865c621 | |||
9b9fc9cde8 | |||
ef459a210d | |||
7680d11c0e |
2
.gitattributes
vendored
@ -1,3 +1,5 @@
|
||||
# all png are binary
|
||||
*.png binary
|
||||
# our generated mesh should be save as binary
|
||||
*.bin binary
|
||||
# json is data and not good for human reading(althought I edit it on my own hand.)
|
||||
|
33
README.md
@ -9,7 +9,7 @@ The latest commit may not be stable to use, please use the latest commit with gi
|
||||
This plugin contain various aspect of Ballance mapping. However, if some features can be easily gotten from other Blender plugin, this plugin will not provide them duplicatedly. We highly recommend that use this plugin with following plugins.
|
||||
|
||||
* [BenjaminSauder/SimpleLattice](https://github.com/BenjaminSauder/SimpleLattice): Create lattice quickly to transform object.
|
||||
* [egtwobits/Mesh Align Plus](https://github.com/egtwobits/mesh_mesh_align_plus): Provide powerful align functions which far beyond vanilla Blender align function.
|
||||
* [JulienHeijmans/quicksnap](https://github.com/JulienHeijmans/quicksnap): Provide powerful align functions which far beyond vanilla Blender align function.
|
||||
|
||||
## Technical Infomation
|
||||
|
||||
@ -17,11 +17,14 @@ Used BM file spec can be found in [there](https://github.com/yyc12345/gist/blob/
|
||||
Used tools chain principle and the file format located in `meshes` can be found in [there](https://github.com/yyc12345/gist/blob/master/BMFileSpec/YYCToolsChainSpec_ZH.md) (Chinese only).
|
||||
The format of the files which are under the `jsons` folder and belong to the BMERevenge section, can be found in [here](https://github.com/yyc12345/gist/blob/master/BMERevenge/DevDocument_ZH.md) (Chinese only).
|
||||
|
||||
This plugin will continuously support Blender lastest **LTS** version. This plugin will migrate to new version when the new LTS version released. Currently, it based on Blender **3.3.x**.
|
||||
This plugin will continuously support Blender lastest **LTS** version. This plugin will migrate to new version when the new LTS version released. Currently, it based on Blender **3.6.x**.
|
||||
|
||||
## Installation
|
||||
|
||||
Put `ballance_blender_plugin` into Blender's plugin folder, `scripts/addons_contrib`. Then enable this plugin in Blender's preferences (DO NOT forget to configure this plugin's settings after first installation or updating plugin.).
|
||||
Put `ballance_blender_plugin` into Blender's plugin folder, `scripts/addons`. Then enable this plugin in Blender's preferences (DO NOT forget to configure this plugin's settings after first installation or updating plugin.).
|
||||
|
||||
> **Note**
|
||||
After the version 3.3 supporting Blender 3.6 LTS, you should install this plugin in `scripts/addons`, not `scripts/addons_contrib` due to Blender do not support testing plugin anymore. If you still have old version in `scripts/addons_contrib`, please **DELETE** it **BEFORE** install the new version.
|
||||
|
||||
## Feature Introduction
|
||||
|
||||
@ -68,6 +71,10 @@ Note that only convex face is supported. Applying this for a concave face will c
|
||||
In the edit mode, select the surface, click Flatten UV, and then scroll the slider to select an edge as a reference.
|
||||
If the generated UV is not attached correctly, such as the FloorSide's band is pasted to the bottom, you can reselect the reference edge and redo the operation until it is correct.
|
||||
|
||||
For the UV flatten by plugin, it must have a scale property. For example, the UV scale of normal floor is 5. However, the UV scale of sink floor is slightly larger than 5. Because the sink floor is "sink" in the floor block. There are 2 methods provided by plugin to getting this proper scale number. You can choose one from Scale Mode.
|
||||
The first method is that user specify a direct scale number. You just need select Scale Size in Scale Mode and fill with a proper scale number. This option is frequently used for fill a large borderless floor.
|
||||
The second method is reference point mode. You need specify a reference point and corresponding U component of its UV. Plugin will calculate the scale size automatically. This method is used for expanding a path of floor.
|
||||
|
||||
### Quick Struct Adder
|
||||
|
||||
In the add menu, we have added a set of commonly used objects. After adding, the object will move to the 3D cursor.
|
||||
@ -109,26 +116,22 @@ Navigate to `Material Properties` panel, select a material, you can find `Virtoo
|
||||
In default, user created material will not enable Virtools Material feature. You need to click checkbox of `Virtools Material` panel to enable or disable it.
|
||||
|
||||
After enable Virtools Material, `Basic Parameters` section and `Advanced Parameters` section can be set. Set your material peroperties just like operating in Virtools.
|
||||
Just like its name, `Basic Parameters` is basic material properties. `Advanced Parameters` is mainly related to transparent properties and usually used in the bottom of transparent column.
|
||||
Just like its name, `Basic Parameters` is basic material properties. `Advanced Parameters` is mainly related to transparent properties and usually used in the bottom of transparent column.
|
||||
Additionally, `Basic Parameters` section provide a preset function, allowing user to use some preset material settings, which only affect 4 basic colors, just for convenient using.
|
||||
|
||||
In `Operation` section, `Apply Virtools Material` will clean all existed Blender material and create a new material graph according to Virtools material properties.
|
||||
And, `Parse from Blender Principled BSDF` will try parsing a Principled BSDF to Virtools material.
|
||||
If your material highly rely on Blender material, please execute `Parse from Blender Principled BSDF` or disable Virtools Material feature before exporting BM file, otherwise material can not be saved correctly.
|
||||
|
||||
### Select by Group
|
||||
### Select by Virtools Group
|
||||
|
||||
Plugin add 2 selection functions according to Virtools Group in Select menu.
|
||||
Plugin add a selection function according to Virtools Group in Select menu.
|
||||
|
||||
#### Select by Virtools Group
|
||||
This function firstly have 5 different selection strategies which is exactly matched with Blender selection method. Just use it like Blender selection (Set, Extend, Subtract, Invert, Intersect).
|
||||
Then, select your group name to start a selection.
|
||||
|
||||
Select objects in active collection according to its Virtools Group properties.
|
||||
The hidden object also can be selected if you check `Ignore Hide Property`.
|
||||
Check `Merge Selection` will merge current selection and previous selection.
|
||||
|
||||
#### Filter by Virtools Group
|
||||
|
||||
Filter current selected object by its Virtools Group properties.
|
||||
Check `Reverse` remove objects matching the requirements, not keep them.
|
||||
If you can, using Subtract or Intersect modes would be better than other modes. Because these modes avoid analyzing too many objects.
|
||||
For example, first, select a rough range, and then use the Intersect mode to filter objects, which is more efficient than directly using the Start mode to select.
|
||||
|
||||
### Quick Grouping
|
||||
|
||||
|
34
README_ZH.md
@ -9,7 +9,7 @@
|
||||
本插件囊括了Ballance制图中可能会用到的各种功能。对于一些其它插件可以提供的功能,本插件不再重复提供。建议与下列插件合用以取得更好制图效果:
|
||||
|
||||
* [BenjaminSauder/SimpleLattice](https://github.com/BenjaminSauder/SimpleLattice):快速创建晶格以便变形物体。
|
||||
* [egtwobits/Mesh Align Plus](https://github.com/egtwobits/mesh_mesh_align_plus):提供远超Blender原生的对齐功能。
|
||||
* [JulienHeijmans/quicksnap](https://github.com/JulienHeijmans/quicksnap):提供远超Blender原生的对齐功能。
|
||||
|
||||
## 技术信息
|
||||
|
||||
@ -17,11 +17,14 @@
|
||||
使用的制图链标准以及`meshes`文件夹下的文件的格式可以在[这里](https://github.com/yyc12345/gist/blob/master/BMFileSpec/YYCToolsChainSpec_ZH.md)查找
|
||||
`jsons`文件夹下的,隶属于BMERevenge部分的文件的格式可以在[这里](https://github.com/yyc12345/gist/blob/master/BMERevenge/DevDocument_ZH.md)查找
|
||||
|
||||
支持Blender的原则是支持当前最新的 **LTS** 版本,在最新的LTS版本释出之后会花一些时间迁移插件。当前插件基于**3.3.x**版本
|
||||
支持Blender的原则是支持当前最新的 **LTS** 版本,在最新的LTS版本释出之后会花一些时间迁移插件。当前插件基于**3.6.x**版本
|
||||
|
||||
## 安装
|
||||
|
||||
将`ballance_blender_plugin`直接复制到Blender插件目录`scripts/addons_contrib`内即可。然后在Blender偏好设置中启用即可(请在第一次安装后或更新插件后配置插件设置)。
|
||||
将`ballance_blender_plugin`直接复制到Blender插件目录`scripts/addons`内即可。然后在Blender偏好设置中启用即可(请在第一次安装后或更新插件后配置插件设置)。
|
||||
|
||||
> **Note**
|
||||
在对标Blender 3.6 LTS的3.3版本之后,您应该将此插件安装在`scripts/addons`中,而不是`scripts/addons_contrib`中,因为Blender不再支持Testing类型插件。 如果您在`scripts/addons_contrib`中仍有旧版本,请在安装新版本**之前删除**它。
|
||||
|
||||
## 功能介绍
|
||||
|
||||
@ -68,6 +71,10 @@ Ballance 3D是一套简单的用于制图3D相关的轻型工具集合,可以
|
||||
编辑模式下,选中面,点击Flatten UV,然后选中一个边作为参考。
|
||||
如果最后生成的边贴附不对,比如把路面花纹贴到了下部,可以重新选择参考边再进行操作,直到正确为止。
|
||||
|
||||
对于粘贴的贴图的UV,需要具有一定缩放,比如对于平路面,这个缩放比是5,而对于凹路面,则要比5大一些,因为凹路面由于凹进路面。为了方便确认这个缩放值,我们提供了两种方式,可以在Scale Mode种选择。
|
||||
一种是用户直接指定,选择Scale Mode为Scale Size并填写合适的缩放数值即可。此选项适合平谱无边框路面。
|
||||
另一种即为参考点模式。用户指定一个参考点,并指定此参考点在U轴上的位置,插件会自动计算缩放值应为多少。此选项适合展开路面路径的贴图。
|
||||
|
||||
### 快速添加结构
|
||||
|
||||
在添加菜单中我们添加了一系列较为常用的物体。添加后物体会移动到3D游标处。
|
||||
@ -109,7 +116,8 @@ Ballance 3D是一套简单的用于制图3D相关的轻型工具集合,可以
|
||||
默认情况下,由用户创建的材质不启用Virtools Material,您可以通过点击`Virtools Material`面板的复选框来启用或关闭它。
|
||||
|
||||
在启用Virtools Material后,可以在`Basic Parameters`和`Advanced Parameters`中设置材质属性,就像在Virtools中操作一般。
|
||||
`Basic Parameters`是基础材质属性。`Advanced Parameters`则是与透明相关的材质属性,主要用于半透明柱子底部等。
|
||||
`Basic Parameters`是基础材质属性。`Advanced Parameters`则是与透明相关的材质属性,主要用于半透明柱子底部等。
|
||||
另外,`Basic Parameters`部分提供了预设功能,允许用户使用一些预设的材质设置,这些设置只影响4种基本颜色,方便使用。
|
||||
|
||||
`Operation`中的`Apply Virtools Material`将把Virtools Material应用到Blender材质上。
|
||||
而`Parse from Blender Principled BSDF`将尝试将一个原理化BSDF转换为Virtools材质数据。
|
||||
@ -117,21 +125,13 @@ Ballance 3D是一套简单的用于制图3D相关的轻型工具集合,可以
|
||||
|
||||
### 按组选择
|
||||
|
||||
选择菜单中新增了两项按照Virtools归组数据进行筛选的功能。
|
||||
选择菜单中新增了一项按照Virtools归组数据进行筛选的功能。
|
||||
|
||||
#### Select by Virtools Group
|
||||
该功能首先有5种不同的选择策略,与Blender的选择方法完全匹配(开始、扩选、相减、反转、相交)。只需像Blender选择那样使用它。
|
||||
然后,选择你需要的组的名称,然后开始一次选择或筛选。
|
||||
|
||||
将对当前活动集合内的物体按照其Virtools Group属性进行选择。
|
||||
勾选`Ignore Hide Property`后,即使是隐藏的物体,也会被筛选。
|
||||
勾选`Merge Selection`,将会把选中的物体合并到当前选定的内容中。
|
||||
|
||||
#### Filter by Virtools Group
|
||||
|
||||
将会按照Virtools Group属性,过滤当前选中物体。
|
||||
勾选`Reverse`将会反向操作,即去除掉符合条件的物体。
|
||||
|
||||
如果可以,请尽可能使用`Filter by Virtools Group`而不是`Select by Virtools Group`。因为这样可以避免分析过多的物体。
|
||||
例如先选定一个大致的范围,然后使用`Filter by Virtools Group`过滤,比直接使用`Select by Virtools Group`效率更高。
|
||||
如果可以,请尽可能使用相减或相交模式。因为这样可以避免分析过多的物体。
|
||||
例如先选定一个大致的范围,然后使用相交模式过滤,比直接使用开始模式效率更高。
|
||||
|
||||
### 快速归组
|
||||
|
||||
|
@ -2,7 +2,7 @@ import bpy,bmesh,bpy_extras,mathutils
|
||||
import pathlib,zipfile,time,os,tempfile,math
|
||||
import struct, shutil
|
||||
from bpy_extras import io_utils, node_shader_utils
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_file_io, UTILS_zip_helper, UTILS_virtools_prop
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_file_io, UTILS_zip_helper, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_export_bm(bpy.types.Operator, bpy_extras.io_utils.ExportHelper):
|
||||
"""Save a Ballance Map File (BM file spec 1.4)"""
|
||||
@ -26,9 +26,15 @@ class BALLANCE_OT_export_bm(bpy.types.Operator, bpy_extras.io_utils.ExportHelper
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# detect edit mode
|
||||
in_edit_mode = False
|
||||
if bpy.context.object and bpy.context.object.mode == "EDIT":
|
||||
in_edit_mode = True
|
||||
bpy.ops.object.editmode_toggle()
|
||||
|
||||
if ((self.export_mode == 'COLLECTION' and context.scene.BallanceBlenderPluginProperty.collection_picker is None) or
|
||||
(self.export_mode == 'OBJECT' and context.scene.BallanceBlenderPluginProperty.object_picker is None)):
|
||||
UTILS_functions.show_message_box(("No specific target", ), "Lost parameter", 'ERROR')
|
||||
UTILS_functions.show_message_box(("No specific target", ), "Lost parameter", UTILS_icons_manager.blender_error_icon)
|
||||
else:
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
|
||||
@ -40,6 +46,12 @@ class BALLANCE_OT_export_bm(bpy.types.Operator, bpy_extras.io_utils.ExportHelper
|
||||
export_bm(context, self.filepath,
|
||||
prefs.no_component_collection,
|
||||
self.export_mode, context.scene.BallanceBlenderPluginProperty.object_picker)
|
||||
|
||||
# restore edit mode
|
||||
if in_edit_mode:
|
||||
bpy.ops.object.editmode_toggle()
|
||||
|
||||
self.report({'INFO'}, "BM File Export Finished.")
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
@ -161,14 +173,14 @@ def export_bm(context, bmx_filepath, prefs_fncg, opts_exportMode, opts_exportTar
|
||||
mesh_faceIndexPairs = [(face, index) for index, face in enumerate(mesh.polygons)]
|
||||
UTILS_file_io.write_uint32(fmesh, len(mesh_faceIndexPairs) * 3)
|
||||
if mesh.uv_layers.active is not None:
|
||||
uv_layer = mesh.uv_layers.active.data[:]
|
||||
uv_layer = mesh.uv_layers.active.uv
|
||||
for f, f_index in mesh_faceIndexPairs:
|
||||
# it should be triangle face, otherwise throw a error
|
||||
if (f.loop_total != 3):
|
||||
raise Exception("Not a triangle", f.poly.loop_total)
|
||||
|
||||
for loop_index in range(f.loop_start, f.loop_start + f.loop_total):
|
||||
uv = uv_layer[loop_index].uv
|
||||
uv = uv_layer[loop_index].vector
|
||||
# reverse v
|
||||
UTILS_file_io.write_2vector(fmesh, uv[0], -uv[1])
|
||||
else:
|
||||
@ -190,6 +202,10 @@ def export_bm(context, bmx_filepath, prefs_fncg, opts_exportMode, opts_exportTar
|
||||
mesh_usedBlenderMtl = mesh.materials[:]
|
||||
mesh_noMaterial = len(mesh_usedBlenderMtl) == 0
|
||||
for mat in mesh_usedBlenderMtl:
|
||||
# skip empty mtl slot
|
||||
if mat is None:
|
||||
continue
|
||||
# add into mtl set
|
||||
if mat not in materialSet:
|
||||
materialSet.add(mat)
|
||||
materialList.append(mat)
|
||||
@ -200,7 +216,10 @@ def export_bm(context, bmx_filepath, prefs_fncg, opts_exportMode, opts_exportTar
|
||||
mesh_vIndex = []
|
||||
for f, f_index in mesh_faceIndexPairs:
|
||||
# confirm material use
|
||||
if mesh_noMaterial:
|
||||
# a face without mtl have 2 situations. first is the whole object do not have mtl
|
||||
# another is this face use an empty mtl slot.
|
||||
mesh_faceNoMtl = mesh_noMaterial or (mesh_usedBlenderMtl[f.material_index] is None)
|
||||
if mesh_faceNoMtl:
|
||||
mesh_materialIndex = 0
|
||||
else:
|
||||
mesh_materialIndex = materialList.index(mesh_usedBlenderMtl[f.material_index])
|
||||
@ -223,7 +242,7 @@ def export_bm(context, bmx_filepath, prefs_fncg, opts_exportMode, opts_exportTar
|
||||
mesh_vIndex[0], mesh_vtIndex[0], mesh_vnIndex[0])
|
||||
|
||||
# set used material
|
||||
UTILS_file_io.write_bool(fmesh, not mesh_noMaterial)
|
||||
UTILS_file_io.write_bool(fmesh, not mesh_faceNoMtl)
|
||||
UTILS_file_io.write_uint32(fmesh, mesh_materialIndex)
|
||||
|
||||
# free splited normals
|
||||
@ -299,6 +318,8 @@ def export_bm(context, bmx_filepath, prefs_fncg, opts_exportMode, opts_exportTar
|
||||
# get absolute texture path
|
||||
texture_filepath = io_utils.path_reference(texture.filepath, texture_blenderFilePath, utils_tempTextureFolder,
|
||||
'ABSOLUTE', "", None, texture.library)
|
||||
# texture_filepath = bpy.path.abspath(texture.filepath, start=texture_blenderFilePath, library=texture.library)
|
||||
|
||||
# get file name and write it
|
||||
texture_filename = os.path.basename(texture_filepath)
|
||||
UTILS_file_io.write_string(ftexture, texture_filename)
|
||||
|
@ -4,7 +4,7 @@ import struct, shutil
|
||||
from bpy_extras import io_utils,node_shader_utils
|
||||
from bpy_extras.io_utils import unpack_list
|
||||
from bpy_extras.image_utils import load_image
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_file_io, UTILS_zip_helper, UTILS_virtools_prop
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_file_io, UTILS_zip_helper, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_import_bm(bpy.types.Operator, bpy_extras.io_utils.ImportHelper):
|
||||
"""Load a Ballance Map File (BM file spec 1.4)"""
|
||||
@ -63,6 +63,8 @@ class BALLANCE_OT_import_bm(bpy.types.Operator, bpy_extras.io_utils.ImportHelper
|
||||
prefs.no_component_collection, prefs.external_folder, prefs.temp_texture_folder,
|
||||
self.texture_conflict_strategy, self.material_conflict_strategy,
|
||||
self.mesh_conflict_strategy, self.object_conflict_strategy)
|
||||
|
||||
self.report({'INFO'}, "BM File Import Finished.")
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@ -89,7 +91,7 @@ def import_bm(context, bmx_filepath, prefs_fncg, prefs_externalTexture, prefs_te
|
||||
# clean temp folder, output error
|
||||
UTILS_functions.show_message_box(
|
||||
("Unsupported BM spec. Expect: {} Gotten: {}".format(UTILS_constants.bmfile_currentVersion, index_gottenVersion), ),
|
||||
"Unsupported BM spec", 'ERROR')
|
||||
"Unsupported BM spec", UTILS_icons_manager.blender_error_icon)
|
||||
findex.close()
|
||||
utils_tempFolderObj.cleanup()
|
||||
return
|
||||
@ -258,10 +260,10 @@ def import_bm(context, bmx_filepath, prefs_fncg, prefs_externalTexture, prefs_te
|
||||
mesh_target.vertices.foreach_set("co", unpack_list(mesh_vList))
|
||||
mesh_target.loops.foreach_set("vertex_index", unpack_list(_flat_vertices_index(mesh_faceList)))
|
||||
mesh_target.loops.foreach_set("normal", unpack_list(_flat_vertices_normal(mesh_faceList, mesh_vnList)))
|
||||
mesh_target.uv_layers[0].data.foreach_set("uv", unpack_list(_flat_vertices_uv(mesh_faceList, mesh_vtList)))
|
||||
mesh_target.uv_layers[0].uv.foreach_set("vector", unpack_list(_flat_vertices_uv(mesh_faceList, mesh_vtList))) # Blender 3.5 CHANGED
|
||||
for i in range(len(mesh_faceList)):
|
||||
mesh_target.polygons[i].loop_start = i * 3
|
||||
mesh_target.polygons[i].loop_total = 3
|
||||
# mesh_target.polygons[i].loop_total = 3 # Blender 3.6 CHANGED
|
||||
if mesh_faceList[i][9] != -1:
|
||||
mesh_target.polygons[i].material_index = mesh_faceList[i][9]
|
||||
|
||||
|
@ -5,7 +5,7 @@ class BALLANCE_OT_super_align(bpy.types.Operator):
|
||||
"""Align object with 3ds Max style"""
|
||||
bl_idname = "ballance.super_align"
|
||||
bl_label = "3ds Max Align"
|
||||
bl_options = {'UNDO'}
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
align_x: bpy.props.BoolProperty(name="X position")
|
||||
align_y: bpy.props.BoolProperty(name="Y position")
|
||||
@ -18,7 +18,8 @@ class BALLANCE_OT_super_align(bpy.types.Operator):
|
||||
('POINT', "Center (axis)", ""),
|
||||
('MAX', "Max", "")
|
||||
),
|
||||
)
|
||||
default='POINT',
|
||||
)
|
||||
|
||||
target_references: bpy.props.EnumProperty(
|
||||
name="Target (Other Objects)",
|
||||
@ -27,7 +28,8 @@ class BALLANCE_OT_super_align(bpy.types.Operator):
|
||||
('POINT', "Center (axis)", ""),
|
||||
('MAX', "Max", "")
|
||||
),
|
||||
)
|
||||
default='POINT',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
@ -37,9 +39,11 @@ class BALLANCE_OT_super_align(bpy.types.Operator):
|
||||
_align_object(self.align_x, self.align_y, self.align_z, self.current_references, self.target_references)
|
||||
return {'FINISHED'}
|
||||
|
||||
"""
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
"""
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -1,26 +1,69 @@
|
||||
import bpy,mathutils
|
||||
import bmesh
|
||||
import math
|
||||
from . import UTILS_functions
|
||||
|
||||
class ScaleDataUnion(object):
|
||||
def __init__(self):
|
||||
self.UseRefPoint: bool = None
|
||||
def SetAsScale(self, scale_num: float):
|
||||
self.UseRefPoint: bool = False
|
||||
self.ScaleSize: float = scale_num
|
||||
def SetAsRefPoint(self, ref_point: int, ref_point_uv: float):
|
||||
self.UseRefPoint: bool = True
|
||||
self.ReferencePoint: int = ref_point
|
||||
self.ReferenceUV: float = ref_point_uv
|
||||
|
||||
class BALLANCE_OT_flatten_uv(bpy.types.Operator):
|
||||
"""Flatten selected face UV. Only works for convex face"""
|
||||
bl_idname = "ballance.flatten_uv"
|
||||
bl_label = "Flatten UV"
|
||||
bl_options = {'UNDO'}
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
reference_edge : bpy.props.IntProperty(
|
||||
name="Reference edge",
|
||||
description="The references edge of UV. It will be placed in V axis.",
|
||||
name="Reference Edge",
|
||||
description="The references edge of UV.\nIt will be placed in V axis.",
|
||||
min=0,
|
||||
soft_min=0,
|
||||
soft_max=3,
|
||||
soft_min=0, soft_max=3,
|
||||
default=0,
|
||||
)
|
||||
|
||||
scale_mode: bpy.props.EnumProperty(
|
||||
name="Scale Mode",
|
||||
items=(('NUM', "Scale Size", "Scale UV with specific number."),
|
||||
('REF', "Ref. Point", "Scale UV with Reference Point feature."),
|
||||
),
|
||||
)
|
||||
|
||||
scale_number : bpy.props.FloatProperty(
|
||||
name="Scale Size",
|
||||
description="The size which will be applied for scale.",
|
||||
min=0,
|
||||
soft_min=0, soft_max=5,
|
||||
default=5.0,
|
||||
step=0.1, precision=1,
|
||||
)
|
||||
|
||||
reference_point : bpy.props.IntProperty(
|
||||
name="Reference Point",
|
||||
description="The references point of UV.\nIt's U component will be set to the number specified by Reference Point UV.\nThis point index is related to the start point of reference edge.",
|
||||
min=2, # 0 and 1 is invalid. we can not order the reference edge to be set on the outside of uv axis
|
||||
soft_min=2, soft_max=3,
|
||||
default=2,
|
||||
)
|
||||
|
||||
reference_uv : bpy.props.FloatProperty(
|
||||
name="Reference Point UV",
|
||||
description="The U component which should be applied to references point in UV.",
|
||||
soft_min=0, soft_max=1,
|
||||
default=0.5,
|
||||
step=0.1, precision=2,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
obj = bpy.context.active_object
|
||||
if obj == None:
|
||||
if obj is None:
|
||||
return False
|
||||
if obj.type != 'MESH':
|
||||
return False
|
||||
@ -28,24 +71,38 @@ class BALLANCE_OT_flatten_uv(bpy.types.Operator):
|
||||
return False
|
||||
return True
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def execute(self, context):
|
||||
no_processed_count = _real_flatten_uv(bpy.context.active_object.data, self.reference_edge)
|
||||
# construct scale data
|
||||
scale_data: ScaleDataUnion = ScaleDataUnion()
|
||||
if self.scale_mode == 'NUM':
|
||||
scale_data.SetAsScale(self.scale_number)
|
||||
else:
|
||||
scale_data.SetAsRefPoint(self.reference_point, self.reference_uv)
|
||||
|
||||
# do flatten uv and report
|
||||
no_processed_count = _real_flatten_uv(bpy.context.active_object.data, self.reference_edge, scale_data)
|
||||
if no_processed_count != 0:
|
||||
UTILS_functions.show_message_box(
|
||||
("{} faces may not be processed correctly because they have problem.".format(no_processed_count), ),
|
||||
"Warning", 'ERROR'
|
||||
)
|
||||
print("[Flatten UV] {} faces may not be processed correctly because they have problem.".format(no_processed_count))
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.emboss = 'NORMAL'
|
||||
layout.prop(self, "reference_edge")
|
||||
|
||||
def _real_flatten_uv(mesh, reference_edge):
|
||||
layout.separator()
|
||||
layout.label(text="Scale Mode")
|
||||
layout.prop(self, "scale_mode", expand=True)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Scale Config")
|
||||
if self.scale_mode == 'NUM':
|
||||
layout.prop(self, "scale_number")
|
||||
else:
|
||||
layout.prop(self, "reference_point")
|
||||
layout.prop(self, "reference_uv")
|
||||
|
||||
def _real_flatten_uv(mesh, reference_edge, scale_data: ScaleDataUnion):
|
||||
no_processed_count = 0
|
||||
|
||||
if mesh.uv_layers.active is None:
|
||||
@ -53,18 +110,44 @@ def _real_flatten_uv(mesh, reference_edge):
|
||||
mesh.uv_layers.new(do_init=False)
|
||||
|
||||
bm = bmesh.from_edit_mesh(mesh)
|
||||
uv_lay = bm.loops.layers.uv.active
|
||||
uv_lay = bm.loops.layers.uv.active # NOTE: this is a part of bmesh. not affected by Blender 3.5 CHANGED.
|
||||
for face in bm.faces:
|
||||
# ========== only process selected face ==========
|
||||
if not face.select:
|
||||
continue
|
||||
|
||||
# ========== resolve reference edge and point ==========
|
||||
# check reference validation
|
||||
allPoint = len(face.loops)
|
||||
|
||||
if allPoint <= reference_edge:
|
||||
no_processed_count+=1
|
||||
if reference_edge >= allPoint: # reference edge overflow
|
||||
no_processed_count += 1
|
||||
continue
|
||||
|
||||
# get correct new corrdinate system
|
||||
# check scale validation
|
||||
if scale_data.UseRefPoint:
|
||||
if ((scale_data.ReferencePoint <= 1) # reference point too low
|
||||
or (scale_data.ReferencePoint >= allPoint)): # reference point overflow
|
||||
no_processed_count += 1
|
||||
continue
|
||||
else:
|
||||
if round(scale_data.ScaleSize, 7) == 0.0: # invalid scale size
|
||||
no_processed_count += 1
|
||||
continue
|
||||
|
||||
# ========== get correct new corrdinate system ==========
|
||||
# yyc mark:
|
||||
# we use 3 points located in this face to calc
|
||||
# the base of this local uv corredinate system.
|
||||
# however if this 3 points are set in a line,
|
||||
# this method will cause a error, zero vector error.
|
||||
#
|
||||
# if z axis is zero vector, we will try using face normal instead
|
||||
# to try getting correct data.
|
||||
#
|
||||
# zero base is not important. because it will not raise any math exception
|
||||
# just a weird uv. user will notice this problem.
|
||||
|
||||
# get point
|
||||
p1Relative = reference_edge
|
||||
p2Relative = reference_edge + 1
|
||||
p3Relative = reference_edge + 2
|
||||
@ -73,17 +156,23 @@ def _real_flatten_uv(mesh, reference_edge):
|
||||
if p3Relative >= allPoint:
|
||||
p3Relative -= allPoint
|
||||
|
||||
p1=mathutils.Vector(tuple(face.loops[p1Relative].vert.co[x] for x in range(3)))
|
||||
p2=mathutils.Vector(tuple(face.loops[p2Relative].vert.co[x] for x in range(3)))
|
||||
p3=mathutils.Vector(tuple(face.loops[p3Relative].vert.co[x] for x in range(3)))
|
||||
p1 = mathutils.Vector(tuple(face.loops[p1Relative].vert.co[x] for x in range(3)))
|
||||
p2 = mathutils.Vector(tuple(face.loops[p2Relative].vert.co[x] for x in range(3)))
|
||||
p3 = mathutils.Vector(tuple(face.loops[p3Relative].vert.co[x] for x in range(3)))
|
||||
|
||||
# get y axis
|
||||
new_y_axis = p2 - p1
|
||||
new_y_axis.normalize()
|
||||
vec1 = p3 - p2
|
||||
vec1.normalize()
|
||||
|
||||
# get z axis
|
||||
new_z_axis = new_y_axis.cross(vec1)
|
||||
new_z_axis.normalize()
|
||||
if not any(round(v, 7) for v in new_z_axis): # if z is a zero vector, use face normal instead
|
||||
new_z_axis = face.normal.normalized()
|
||||
|
||||
# get x axis
|
||||
new_x_axis = new_y_axis.cross(new_z_axis)
|
||||
new_x_axis.normalize()
|
||||
|
||||
@ -93,28 +182,59 @@ def _real_flatten_uv(mesh, reference_edge):
|
||||
(0, 1.0, 0),
|
||||
(0, 0, 1.0)
|
||||
))
|
||||
origin_base.invert()
|
||||
origin_base.invert_safe()
|
||||
new_base = mathutils.Matrix((
|
||||
(new_x_axis.x, new_y_axis.x, new_z_axis.x),
|
||||
(new_x_axis.y, new_y_axis.y, new_z_axis.y),
|
||||
(new_x_axis.z, new_y_axis.z, new_z_axis.z)
|
||||
))
|
||||
transition_matrix = origin_base @ new_base
|
||||
transition_matrix.invert()
|
||||
transition_matrix.invert_safe()
|
||||
|
||||
# process each face
|
||||
# ========== rescale correction ==========
|
||||
if scale_data.UseRefPoint:
|
||||
# ref point method
|
||||
# get reference point from loop
|
||||
refpRelative = p1Relative + scale_data.ReferencePoint
|
||||
if refpRelative >= allPoint:
|
||||
refpRelative -= allPoint
|
||||
pRef = mathutils.Vector(tuple(face.loops[refpRelative].vert.co[x] for x in range(3))) - p1
|
||||
|
||||
# calc its U component
|
||||
vec_u = abs((transition_matrix @ pRef).x)
|
||||
if round(vec_u, 7) == 0.0:
|
||||
rescale = 1 # fallback. rescale = 1 will not affect anything
|
||||
else:
|
||||
rescale = scale_data.ReferenceUV / vec_u
|
||||
else:
|
||||
# scale size method
|
||||
# apply rescale directly
|
||||
rescale = 1.0 / scale_data.ScaleSize
|
||||
|
||||
# construct matrix
|
||||
# we only rescale U component (X component)
|
||||
# and 5.0 scale for V component (Y component)
|
||||
scale_matrix = mathutils.Matrix((
|
||||
(rescale, 0, 0),
|
||||
(0, 1.0 / 5.0, 0),
|
||||
(0, 0, 1.0)
|
||||
))
|
||||
# order can not be changed. we order do transition first, then scale it.
|
||||
rescale_transition_matrix = scale_matrix @ transition_matrix
|
||||
|
||||
# ========== process each face ==========
|
||||
for loop_index in range(allPoint):
|
||||
pp = mathutils.Vector(tuple(face.loops[loop_index].vert.co[x] for x in range(3)))
|
||||
vec = pp-p1
|
||||
new_vec = transition_matrix @ vec
|
||||
pp = mathutils.Vector(tuple(face.loops[loop_index].vert.co[x] for x in range(3))) - p1
|
||||
ppuv = rescale_transition_matrix @ pp
|
||||
|
||||
# y axis always use 5.0 to scale
|
||||
# however, x need use custom scale correction which has been calculated by our matrix.
|
||||
face.loops[loop_index][uv_lay].uv = (
|
||||
(new_vec.x if new_vec.x >=0 else -new_vec.x) / 5,
|
||||
(new_vec.y) / 5
|
||||
abs(ppuv.x),
|
||||
ppuv.y
|
||||
)
|
||||
|
||||
# Show the updates in the viewport
|
||||
bmesh.update_edit_mesh(mesh)
|
||||
|
||||
return no_processed_count
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import bpy,bmesh
|
||||
import mathutils
|
||||
import bpy.types
|
||||
from . import UTILS_functions
|
||||
from . import UTILS_functions, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_rail_uv(bpy.types.Operator):
|
||||
"""Create a UV for rail"""
|
||||
@ -47,7 +47,7 @@ class BALLANCE_OT_rail_uv(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
if context.scene.BallanceBlenderPluginProperty.material_picker == None:
|
||||
UTILS_functions.show_message_box(("No specific material", ), "Lost parameter", 'ERROR')
|
||||
UTILS_functions.show_message_box(("No specific material", ), "Lost parameter", UTILS_icons_manager.blender_error_icon)
|
||||
else:
|
||||
_create_rail_uv(self.uv_type, context.scene.BallanceBlenderPluginProperty.material_picker, self.uv_scale, self.projection_axis)
|
||||
return {'FINISHED'}
|
||||
@ -141,15 +141,17 @@ def _create_rail_uv(rail_type, material_pointer, scale_size, projection_axis):
|
||||
)
|
||||
real_scale = 1.0 / maxLength
|
||||
|
||||
uv_layer = mesh.uv_layers.active.data
|
||||
# Blender 3.5 CHANGED: mesh.uv_layers.active.data -> mesh.uv_layers.active.uv
|
||||
# .uv -> .vector
|
||||
uv_layer = mesh.uv_layers.active.uv
|
||||
for poly in mesh.polygons:
|
||||
for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total):
|
||||
# get correspond vec index
|
||||
index = mesh.loops[loop_index].vertex_index
|
||||
if rail_type == 'POINT':
|
||||
# set to 1 point
|
||||
uv_layer[loop_index].uv[0] = 0
|
||||
uv_layer[loop_index].uv[1] = 1
|
||||
uv_layer[loop_index].vector[0] = 0
|
||||
uv_layer[loop_index].vector[1] = 1
|
||||
elif rail_type == 'SCALE' or rail_type == 'UNIFORM':
|
||||
# following xy -> uv scale
|
||||
#
|
||||
@ -157,16 +159,16 @@ def _create_rail_uv(rail_type, material_pointer, scale_size, projection_axis):
|
||||
# use X axis: Y->U Z->V
|
||||
# use Y axis: X->U Z->V
|
||||
if projection_axis == 'X':
|
||||
uv_layer[loop_index].uv[0] = vecList[index].co[1] * real_scale
|
||||
uv_layer[loop_index].uv[1] = vecList[index].co[2] * real_scale
|
||||
uv_layer[loop_index].vector[0] = vecList[index].co[1] * real_scale
|
||||
uv_layer[loop_index].vector[1] = vecList[index].co[2] * real_scale
|
||||
elif projection_axis == 'Y':
|
||||
uv_layer[loop_index].uv[0] = vecList[index].co[0] * real_scale
|
||||
uv_layer[loop_index].uv[1] = vecList[index].co[2] * real_scale
|
||||
uv_layer[loop_index].vector[0] = vecList[index].co[0] * real_scale
|
||||
uv_layer[loop_index].vector[1] = vecList[index].co[2] * real_scale
|
||||
elif projection_axis == 'Z':
|
||||
uv_layer[loop_index].uv[0] = vecList[index].co[0] * real_scale
|
||||
uv_layer[loop_index].uv[1] = vecList[index].co[1] * real_scale
|
||||
uv_layer[loop_index].vector[0] = vecList[index].co[0] * real_scale
|
||||
uv_layer[loop_index].vector[1] = vecList[index].co[1] * real_scale
|
||||
elif rail_type == 'TT':
|
||||
(uv_layer[loop_index].uv[0], uv_layer[loop_index].uv[1]) = _tt_reflection_mapping_compute(
|
||||
(uv_layer[loop_index].vector[0], uv_layer[loop_index].vector[1]) = _tt_reflection_mapping_compute(
|
||||
vecList[index].co,
|
||||
mesh.loops[loop_index].normal,
|
||||
(0.0, 0.0, 0.0)
|
||||
@ -175,7 +177,7 @@ def _create_rail_uv(rail_type, material_pointer, scale_size, projection_axis):
|
||||
if len(ignoredObj) != 0:
|
||||
UTILS_functions.show_message_box(
|
||||
("Following objects are not processed due to they are not suit for this function now: ", ) + tuple(ignoredObj),
|
||||
"Execution result", 'INFO'
|
||||
"Execution result", UTILS_icons_manager.blender_info_icon
|
||||
)
|
||||
|
||||
def _tt_reflection_mapping_compute(_point, _n, _refobj):
|
||||
|
@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class rename_system_props(bpy.types.Operator):
|
||||
name_standard: bpy.props.EnumProperty(
|
||||
@ -69,6 +69,52 @@ class BALLANCE_OT_auto_grouping(rename_system_props):
|
||||
# ==========================================
|
||||
# rename misc funcs
|
||||
|
||||
class _RenameErrorType():
|
||||
ERROR = 0
|
||||
WARNING = 1
|
||||
INFO = 2
|
||||
|
||||
@staticmethod
|
||||
def cvt_err_from_int_to_str(err_t):
|
||||
if err_t == _RenameErrorType.ERROR:
|
||||
return "ERROR"
|
||||
elif err_t == _RenameErrorType.WARNING:
|
||||
return "WARNING"
|
||||
elif err_t == _RenameErrorType.INFO:
|
||||
return "INFO"
|
||||
else:
|
||||
raise Exception("Unknow error type.")
|
||||
|
||||
class _RenameErrorItem():
|
||||
def __init__(self, err_t, description):
|
||||
self.err_type = err_t
|
||||
self.description = description
|
||||
|
||||
def get_presentation(self):
|
||||
return "[{}]\t{}".format(_RenameErrorType.cvt_err_from_int_to_str(self.err_type), self.description)
|
||||
|
||||
class _RenameErrorReporter():
|
||||
def __init__(self):
|
||||
self.err_container: list[_RenameErrorItem] = []
|
||||
|
||||
def add_error(self, description):
|
||||
self.err_container.append(_RenameErrorItem(_RenameErrorType.ERROR, description))
|
||||
def add_warning(self, description):
|
||||
self.err_container.append(_RenameErrorItem(_RenameErrorType.WARNING, description))
|
||||
def add_info(self, description):
|
||||
self.err_container.append(_RenameErrorItem(_RenameErrorType.INFO, description))
|
||||
|
||||
def can_report(self):
|
||||
return len(self.err_container) != 0
|
||||
|
||||
def report(self, header):
|
||||
print(header)
|
||||
for i in self.err_container:
|
||||
print('\t' + i.get_presentation())
|
||||
|
||||
def clear(self):
|
||||
self.err_container.clear()
|
||||
|
||||
class _ObjectBasicType():
|
||||
COMPONENT = 0
|
||||
|
||||
@ -140,12 +186,12 @@ def _get_sector_from_ckgroup(group_set):
|
||||
# YYC Tools Chains name standard is Ballance-compatible name standard.
|
||||
# So this functions also serving for `_get_name_info_from_group` function
|
||||
# to help get sector field from PC/PR elements. In ordinary call(external call)
|
||||
# The final error output should be outputed nromally. But in the call from
|
||||
# The final error output should be outputed normally. But in the call from
|
||||
# `_get_name_info_from_group`, this function should not output any error.
|
||||
# So parameter `call_internal` is served for this work. In common it is False
|
||||
# to let function output error str normally. But only set it to True in
|
||||
# the call from `_get_name_info_from_group` to disable error output.
|
||||
def _get_name_info_from_yyc_name(obj_name, call_internal = False):
|
||||
def _get_name_info_from_yyc_name(obj_name, err_reporter: _RenameErrorReporter, call_internal = False):
|
||||
|
||||
# check component first
|
||||
regex_result = UTILS_constants.rename_regexYYCComponent.match(obj_name)
|
||||
@ -191,11 +237,11 @@ def _get_name_info_from_yyc_name(obj_name, call_internal = False):
|
||||
|
||||
# only output in external calling
|
||||
if not call_internal:
|
||||
print("[ERROR]\t{}:\tName match lost.".format(obj_name))
|
||||
err_reporter.add_error("Name match lost.")
|
||||
|
||||
return None
|
||||
|
||||
def _get_name_info_from_imengyu_name(obj_name):
|
||||
def _get_name_info_from_imengyu_name(obj_name, err_reporter: _RenameErrorReporter):
|
||||
|
||||
# check component first
|
||||
regex_result = UTILS_constants.rename_regexImengyuComponent.match(obj_name)
|
||||
@ -238,10 +284,10 @@ def _get_name_info_from_imengyu_name(obj_name):
|
||||
if obj_name.startswith("O_"):
|
||||
return _NameInfoHelper(_ObjectBasicType.DECORATION)
|
||||
|
||||
print("[ERROR]\t{}:\tName match lost.".format(obj_name))
|
||||
err_reporter.add_error("Name match lost.")
|
||||
return None
|
||||
|
||||
def _get_name_info_from_group(obj):
|
||||
def _get_name_info_from_group(obj, err_reporter: _RenameErrorReporter):
|
||||
group_list = UTILS_virtools_prop.get_virtools_group_data(obj)
|
||||
if len(group_list) == 0:
|
||||
# name it as a decoration
|
||||
@ -262,24 +308,24 @@ def _get_name_info_from_group(obj):
|
||||
# these type's data should be gotten from its name
|
||||
# use _get_name_info_from_yyc_name to get it
|
||||
# _get_name_info_from_yyc_name is Ballance-compatible name standard
|
||||
data = _get_name_info_from_yyc_name(obj.name, call_internal=True)
|
||||
data = _get_name_info_from_yyc_name(obj.name, err_reporter, call_internal=True)
|
||||
if data is None:
|
||||
print("[ERROR]\t{}:\tPC_Checkpoints or PR_Resetpoints detected. But couldn't get sector from name.".format(obj.name))
|
||||
err_reporter.add_error("PC_Checkpoints or PR_Resetpoints detected. But couldn't get sector from name.")
|
||||
return None
|
||||
if data.basic_type != _ObjectBasicType.CHECKPOINT and data.basic_type != _ObjectBasicType.RESETPOINT:
|
||||
# check whether it is checkpoint or resetpoint
|
||||
# if not, it mean that we got error data from name
|
||||
# return None instead
|
||||
print("[ERROR]\t{}:\tPC_Checkpoints or PR_Resetpoints detected. But name is illegal.".format(obj.name))
|
||||
err_reporter.add_error("PC_Checkpoints or PR_Resetpoints detected. But name is illegal.")
|
||||
return None
|
||||
# otherwise return data
|
||||
return data
|
||||
else:
|
||||
print("[ERROR]\t{}:\tThe match of Unique Component lost.".format(obj.name))
|
||||
err_reporter.add_error("The match of Unique Component lost.")
|
||||
return None
|
||||
elif len(set_result) != 0:
|
||||
# must be a weird grouping, report it
|
||||
print("[ERROR]\t{}:\tA Multi-grouping Unique Component.".format(obj.name))
|
||||
err_reporter.add_error("A Multi-grouping Unique Component.")
|
||||
return None
|
||||
|
||||
# distinguish normal elements
|
||||
@ -291,7 +337,7 @@ def _get_name_info_from_group(obj):
|
||||
gotten_sector = _get_sector_from_ckgroup(group_set)
|
||||
if gotten_sector is None:
|
||||
# fail to get sector
|
||||
print("[ERROR]\t{}:\tComponent detected. But couldn't get sector from CKGroup data.".format(obj.name))
|
||||
err_reporter.add_error("Component detected. But couldn't get sector from CKGroup data.")
|
||||
return None
|
||||
|
||||
data = _NameInfoHelper(_ObjectBasicType.COMPONENT)
|
||||
@ -300,7 +346,7 @@ def _get_name_info_from_group(obj):
|
||||
return data
|
||||
elif len(set_result) != 0:
|
||||
# must be a weird grouping, report it
|
||||
print("[ERROR]\t{}:\tA Multi-grouping Component.".format(obj.name))
|
||||
err_reporter.add_error("A Multi-grouping Component.")
|
||||
return None
|
||||
|
||||
# distinguish road
|
||||
@ -316,7 +362,7 @@ def _get_name_info_from_group(obj):
|
||||
elif len(floor_result) == 0 and len(rail_result) > 0:
|
||||
return _NameInfoHelper(_ObjectBasicType.WOOD)
|
||||
else:
|
||||
print("[WARNING]\t{}:\tCan't distinguish between Floors and Rails. Suppose it is Floors".format(obj.name))
|
||||
err_reporter.add_warning("Can't distinguish object between Floors and Rails. Suppose it is Floors.")
|
||||
return _NameInfoHelper(_ObjectBasicType.FLOOR)
|
||||
elif 'Phys_FloorStopper' in group_set:
|
||||
return _NameInfoHelper(_ObjectBasicType.STOPPER)
|
||||
@ -324,10 +370,10 @@ def _get_name_info_from_group(obj):
|
||||
return _NameInfoHelper(_ObjectBasicType.DEPTH_CUBE)
|
||||
|
||||
# no matched
|
||||
print("[ERROR]\t{}:\tGroup match lost.".format(obj.name))
|
||||
err_reporter.add_error("Group match lost.")
|
||||
return None
|
||||
|
||||
def _set_for_yyc_name(obj, name_info):
|
||||
def _set_for_yyc_name(obj, name_info, err_reporter: _RenameErrorReporter):
|
||||
basic_type = name_info.basic_type
|
||||
if basic_type == _ObjectBasicType.DECORATION:
|
||||
obj.name = "D_"
|
||||
@ -357,7 +403,7 @@ def _set_for_yyc_name(obj, name_info):
|
||||
obj.name = "{}_{:0>2d}_".format(name_info.component_type, name_info.sector)
|
||||
|
||||
|
||||
def _set_for_imengyu_name(obj, name_info):
|
||||
def _set_for_imengyu_name(obj, name_info, err_reporter: _RenameErrorReporter):
|
||||
basic_type = name_info.basic_type
|
||||
if basic_type == _ObjectBasicType.DECORATION:
|
||||
obj.name = "O_"
|
||||
@ -388,7 +434,7 @@ def _set_for_imengyu_name(obj, name_info):
|
||||
|
||||
# NOTE: the implement of this function are copied from
|
||||
# BallanceVirtoolsHelper/bvh/features/mapping/grouping.cpp
|
||||
def _set_for_group(obj, name_info):
|
||||
def _set_for_group(obj, name_info, err_reporter: _RenameErrorReporter):
|
||||
gps = []
|
||||
basic_type = name_info.basic_type
|
||||
|
||||
@ -441,23 +487,23 @@ def _set_for_group(obj, name_info):
|
||||
# ==========================================
|
||||
# assemble funcs
|
||||
|
||||
def _get_data(obj, standard):
|
||||
def _get_data(obj, standard, err_reporter: _RenameErrorReporter):
|
||||
if standard == _NameStandard.YYC:
|
||||
return _get_name_info_from_yyc_name(obj.name)
|
||||
return _get_name_info_from_yyc_name(obj.name, err_reporter)
|
||||
elif standard == _NameStandard.IMENGYU:
|
||||
return _get_name_info_from_imengyu_name(obj.name)
|
||||
return _get_name_info_from_imengyu_name(obj.name, err_reporter)
|
||||
elif standard == _NameStandard.CKGROUP:
|
||||
return _get_name_info_from_group(obj)
|
||||
return _get_name_info_from_group(obj, err_reporter)
|
||||
else:
|
||||
raise Exception("Unknow standard")
|
||||
|
||||
def _set_data(obj, name_info, standard):
|
||||
def _set_data(obj, name_info, standard, err_reporter: _RenameErrorReporter):
|
||||
if standard == _NameStandard.YYC:
|
||||
return _set_for_yyc_name(obj, name_info)
|
||||
return _set_for_yyc_name(obj, name_info, err_reporter)
|
||||
elif standard == _NameStandard.IMENGYU:
|
||||
return _set_for_imengyu_name(obj, name_info)
|
||||
return _set_for_imengyu_name(obj, name_info, err_reporter)
|
||||
elif standard == _NameStandard.CKGROUP:
|
||||
return _set_for_group(obj, name_info)
|
||||
return _set_for_group(obj, name_info, err_reporter)
|
||||
else:
|
||||
raise Exception("Unknow standard")
|
||||
|
||||
@ -467,23 +513,43 @@ def _rename_core(source_std, dest_std):
|
||||
# we do not to do anything
|
||||
return
|
||||
|
||||
# create fail counter and error reporter
|
||||
failed_obj_counter = 0
|
||||
all_obj_counter = 0
|
||||
err_reporter = _RenameErrorReporter()
|
||||
|
||||
print('============')
|
||||
print('Rename system report')
|
||||
print('Rename System Report')
|
||||
print('------------')
|
||||
for obj in _get_selected_objects():
|
||||
# set counter and name
|
||||
all_obj_counter += 1
|
||||
info = _get_data(obj, source_std)
|
||||
old_name = new_name = obj.name
|
||||
# get data
|
||||
info = _get_data(obj, source_std, err_reporter)
|
||||
|
||||
# do operation according to whether getting data successfully
|
||||
if info is None:
|
||||
failed_obj_counter += 1
|
||||
continue
|
||||
else:
|
||||
_set_data(obj, info, dest_std, err_reporter)
|
||||
# refresh obj name
|
||||
new_name = obj.name
|
||||
|
||||
_set_data(obj, info, dest_std)
|
||||
# report result
|
||||
if err_reporter.can_report():
|
||||
if new_name == old_name:
|
||||
report_header = 'For object "{}"'.format(new_name)
|
||||
else:
|
||||
report_header = 'For object "{}" (Old name: "{}")'.format(new_name, old_name)
|
||||
|
||||
err_reporter.report(report_header)
|
||||
# clear report
|
||||
err_reporter.clear()
|
||||
|
||||
|
||||
print('------------')
|
||||
print('All/failed - {}/{}'.format(all_obj_counter, failed_obj_counter))
|
||||
print('All / Failed - {} / {}'.format(all_obj_counter, failed_obj_counter))
|
||||
print('============')
|
||||
|
||||
UTILS_functions.show_message_box(
|
||||
@ -491,6 +557,5 @@ def _rename_core(source_std, dest_std):
|
||||
'View console to get more detail',
|
||||
'All: {}'.format(all_obj_counter),
|
||||
'Failed: {}'.format(failed_obj_counter)),
|
||||
"Info",
|
||||
"INFO"
|
||||
"Info", UTILS_icons_manager.blender_error_icon
|
||||
)
|
||||
|
@ -1,23 +1,10 @@
|
||||
import bpy, mathutils
|
||||
from . import UTILS_constants, UTILS_functions
|
||||
|
||||
# ================================================= actual add
|
||||
|
||||
class BALLANCE_OT_add_components(bpy.types.Operator):
|
||||
"""Add sector related elements"""
|
||||
bl_idname = "ballance.add_components"
|
||||
bl_label = "Add elements"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
elements_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="This element type",
|
||||
items=tuple(map(lambda x: (x, x, ""), UTILS_constants.bmfile_componentList)),
|
||||
)
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_icons_manager
|
||||
|
||||
# =============== Common Class ================
|
||||
class common_add_component_props(bpy.types.Operator):
|
||||
attentionElements = ("PC_TwoFlames", "PR_Resetpoint")
|
||||
uniqueElements = ("PS_FourFlames", "PE_Balloon")
|
||||
canDuplicatedElements = ('P_Extra_Point', 'P_Modul_18', 'P_Modul_26')
|
||||
|
||||
elements_sector: bpy.props.IntProperty(
|
||||
name="Sector",
|
||||
@ -26,41 +13,46 @@ class BALLANCE_OT_add_components(bpy.types.Operator):
|
||||
default=1,
|
||||
)
|
||||
|
||||
elements_duplicated: bpy.props.BoolProperty(
|
||||
name="Duplicated",
|
||||
description="Whether duplicate elements (Nong xxx / 脓xxx)",
|
||||
default=False,
|
||||
)
|
||||
elements_dup_times: bpy.props.IntProperty(
|
||||
name="Duplication Times",
|
||||
description="How many this element should be duplicated.",
|
||||
min=1, max=64,
|
||||
soft_min=1, soft_max=32,
|
||||
default=1,
|
||||
def get_component_name(self, raw_comp_name):
|
||||
if raw_comp_name in self.uniqueElements:
|
||||
return raw_comp_name + "_01"
|
||||
elif raw_comp_name in self.attentionElements:
|
||||
return raw_comp_name + "_0" + str(self.elements_sector)
|
||||
else:
|
||||
return raw_comp_name + "_0" + str(self.elements_sector) + "_"
|
||||
|
||||
def parent_draw(self, parent_layout, raw_comp_name):
|
||||
if raw_comp_name not in self.uniqueElements:
|
||||
parent_layout.prop(self, 'elements_sector')
|
||||
|
||||
class BALLANCE_OT_add_components(common_add_component_props):
|
||||
"""Add Elements"""
|
||||
bl_idname = "ballance.add_components"
|
||||
bl_label = "Add Elements"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
elements_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="This element type",
|
||||
#items=tuple(map(lambda x: (x, x, ""), UTILS_constants.bmfile_componentList)),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(blk, blk, "", UTILS_icons_manager.get_element_icon(blk), idx)
|
||||
for idx, blk in enumerate(UTILS_constants.bmfile_componentList)
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# get name
|
||||
if self.elements_type in self.uniqueElements:
|
||||
finalObjectName = self.elements_type + "_01"
|
||||
elif self.elements_type in self.attentionElements:
|
||||
finalObjectName = self.elements_type + "_0" + str(self.elements_sector)
|
||||
else:
|
||||
finalObjectName = self.elements_type + "_0" + str(self.elements_sector) + "_"
|
||||
finalObjectName = self.get_component_name(self.elements_type)
|
||||
|
||||
# create object
|
||||
loadedMesh = UTILS_functions.load_component(
|
||||
UTILS_constants.bmfile_componentList.index(self.elements_type))
|
||||
UTILS_constants.bmfile_componentList.index(self.elements_type)
|
||||
)
|
||||
obj = bpy.data.objects.new(finalObjectName, loadedMesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
|
||||
# extra duplication
|
||||
if self.elements_type in self.canDuplicatedElements:
|
||||
for i in range(self.elements_dup_times - 1):
|
||||
obj = bpy.data.objects.new(finalObjectName, loadedMesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@ -71,16 +63,172 @@ class BALLANCE_OT_add_components(bpy.types.Operator):
|
||||
layout = self.layout
|
||||
# attension notice
|
||||
if self.elements_type in self.attentionElements:
|
||||
layout.label(text="Please note that sector is suffix.")
|
||||
if self.elements_type in self.canDuplicatedElements:
|
||||
layout.label(text="This element can use duplication feature.")
|
||||
layout.label(text="NOTE: Check Sector ID carefully.")
|
||||
if self.elements_type in self.uniqueElements:
|
||||
layout.label(text="NOTE: This element have unique name.")
|
||||
|
||||
# cfg
|
||||
layout.prop(self, "elements_type")
|
||||
if self.elements_type not in self.uniqueElements:
|
||||
layout.prop(self, "elements_sector")
|
||||
self.parent_draw(layout, self.elements_type)
|
||||
|
||||
if self.elements_type in self.canDuplicatedElements:
|
||||
layout.separator()
|
||||
layout.prop(self, "elements_duplicated")
|
||||
layout.prop(self, "elements_dup_times")
|
||||
@classmethod
|
||||
def draw_blc_menu(self, layout):
|
||||
for item in UTILS_constants.bmfile_componentList:
|
||||
cop = layout.operator(
|
||||
self.bl_idname, text=item,
|
||||
icon_value = UTILS_icons_manager.get_element_icon(item))
|
||||
cop.elements_type = item
|
||||
|
||||
|
||||
class BALLANCE_OT_add_components_dup(common_add_component_props):
|
||||
"""Add Duplicated Elements"""
|
||||
bl_idname = "ballance.add_components_dup"
|
||||
bl_label = "Add Duplicated Elements"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
can_duplicated_elements = (
|
||||
'P_Extra_Point', 'P_Modul_18', 'P_Modul_26'
|
||||
)
|
||||
|
||||
elements_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="This element type",
|
||||
#items=tuple(map(lambda x: (x, x, ""), UTILS_constants.bmfile_componentList)),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(blk, blk, "", UTILS_icons_manager.get_element_icon(blk), idx)
|
||||
for idx, blk in enumerate(can_duplicated_elements)
|
||||
),
|
||||
)
|
||||
|
||||
elements_dup_times: bpy.props.IntProperty(
|
||||
name="Duplication Count",
|
||||
description="How many this element should be duplicated.",
|
||||
min=2, max=64,
|
||||
soft_min=2, soft_max=32,
|
||||
default=2,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# get name
|
||||
finalObjectName = self.get_component_name(self.elements_type)
|
||||
|
||||
# load mesh
|
||||
loadedMesh = UTILS_functions.load_component(
|
||||
UTILS_constants.bmfile_componentList.index(self.elements_type)
|
||||
)
|
||||
# create object
|
||||
for i in range(self.elements_dup_times):
|
||||
obj = bpy.data.objects.new(finalObjectName, loadedMesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "elements_type")
|
||||
self.parent_draw(layout, self.elements_type)
|
||||
layout.prop(self, "elements_dup_times")
|
||||
|
||||
@classmethod
|
||||
def draw_blc_menu(self, layout):
|
||||
for item in self.can_duplicated_elements:
|
||||
cop = layout.operator(
|
||||
self.bl_idname, text=item,
|
||||
icon_value = UTILS_icons_manager.get_element_icon(item))
|
||||
cop.elements_type = item
|
||||
|
||||
|
||||
class BALLANCE_OT_add_components_series(common_add_component_props):
|
||||
"""Add Elements with a Series."""
|
||||
bl_idname = "ballance.add_components_series"
|
||||
bl_label = "Add Series Elements"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
supported_series = {
|
||||
# format: key: (description: str, real_component: str, unit_transition: mathutils.Vector, default_span: float)
|
||||
# key will become enum property's identifier
|
||||
"MODUL_41": ('Tilting Block Series', 'P_Modul_41', mathutils.Vector((1.0, 0.0, 0.0)), 6.0022),
|
||||
"MODUL_18_V": ('Fan Vertical Series', 'P_Modul_18', mathutils.Vector((0.0, 0.0, 1.0)), 15),
|
||||
"MODUL_18_H": ('Fan Horizonal Series', 'P_Modul_18', mathutils.Vector((1.0, 0.0, 0.0)), 30),
|
||||
}
|
||||
|
||||
# the updator for default span
|
||||
def element_type_updated(self, context):
|
||||
# set span
|
||||
self.elements_span = BALLANCE_OT_add_components_series.supported_series[self.elements_type][3]
|
||||
|
||||
# blender required
|
||||
return None
|
||||
|
||||
elements_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="This element type",
|
||||
#items=tuple(map(lambda x: (x, x, ""), UTILS_constants.bmfile_componentList)),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(skey, sitem[0], "", UTILS_icons_manager.get_element_icon(sitem[1]), idx)
|
||||
for (idx, (skey, sitem)) in enumerate(supported_series.items())
|
||||
),
|
||||
default=0,
|
||||
update=element_type_updated
|
||||
)
|
||||
|
||||
elements_dup_times: bpy.props.IntProperty(
|
||||
name="Duplication Count",
|
||||
description="How many this element should be duplicated.",
|
||||
min=2, max=64,
|
||||
soft_min=2, soft_max=32,
|
||||
default=2,
|
||||
)
|
||||
|
||||
elements_span: bpy.props.FloatProperty(
|
||||
name="Elements Span",
|
||||
description="The span between each elements.",
|
||||
min=0.0,
|
||||
default=0.0,
|
||||
)
|
||||
|
||||
def invoke(self, context, event):
|
||||
# force trigger span update once to treat span normally
|
||||
self.element_type_updated(context)
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
def execute(self, context):
|
||||
# get unit span and real element name for loading mesh and creating name
|
||||
(_, real_element_name, unit_span, _) = self.supported_series[self.elements_type]
|
||||
|
||||
# get name
|
||||
finalObjectName = self.get_component_name(real_element_name)
|
||||
# load mesh
|
||||
loadedMesh = UTILS_functions.load_component(
|
||||
UTILS_constants.bmfile_componentList.index(real_element_name)
|
||||
)
|
||||
|
||||
# create object
|
||||
for i in range(self.elements_dup_times):
|
||||
obj = bpy.data.objects.new(finalObjectName, loadedMesh)
|
||||
UTILS_functions.add_into_scene_and_move_to_cursor(obj)
|
||||
obj.matrix_world.translation += unit_span * (self.elements_span * i)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "elements_type")
|
||||
self.parent_draw(layout, self.elements_type)
|
||||
layout.prop(self, "elements_dup_times")
|
||||
layout.prop(self, "elements_span")
|
||||
|
||||
@classmethod
|
||||
def draw_blc_menu(self, layout):
|
||||
for key, item in self.supported_series.items():
|
||||
cop = layout.operator(
|
||||
self.bl_idname, text=item[0],
|
||||
icon_value = UTILS_icons_manager.get_element_icon(item[1]))
|
||||
cop.elements_type = key
|
||||
|
@ -4,18 +4,45 @@ import ast
|
||||
from bpy_extras import io_utils,node_shader_utils
|
||||
# from bpy_extras.io_utils import unpack_list
|
||||
from bpy_extras.image_utils import load_image
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_safe_eval
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_safe_eval, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_add_floors(bpy.types.Operator):
|
||||
"""Add Ballance floor"""
|
||||
bl_idname = "ballance.add_floors"
|
||||
bl_label = "Add floor"
|
||||
bl_options = {'UNDO'}
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
# the updator for default side value
|
||||
def floor_type_updated(self, context):
|
||||
# get floor prototype
|
||||
floor_prototype = UTILS_constants.floor_blockDict[self.floor_type]
|
||||
|
||||
# try sync default value
|
||||
default_sides = floor_prototype['DefaultSideConfig']
|
||||
self.use_2d_top = default_sides['UseTwoDTop']
|
||||
self.use_2d_right = default_sides['UseTwoDRight']
|
||||
self.use_2d_bottom = default_sides['UseTwoDBottom']
|
||||
self.use_2d_left = default_sides['UseTwoDLeft']
|
||||
self.use_3d_top = default_sides['UseThreeDTop']
|
||||
self.use_3d_bottom = default_sides['UseThreeDBottom']
|
||||
|
||||
# blender required
|
||||
return None
|
||||
|
||||
floor_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="Floor type",
|
||||
items=tuple((x, x, "") for x in UTILS_constants.floor_blockDict.keys()),
|
||||
#items=tuple(
|
||||
# # token, display name, descriptions
|
||||
# (blk, blk, "")
|
||||
# for blk in UTILS_constants.floor_blockDict.keys()
|
||||
#),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(blk, blk, "", UTILS_icons_manager.get_floor_icon(blk), idx)
|
||||
for idx, blk in enumerate(UTILS_constants.floor_blockDict.keys())
|
||||
),
|
||||
update=floor_type_updated
|
||||
)
|
||||
|
||||
expand_length_1 : bpy.props.IntProperty(
|
||||
@ -40,26 +67,30 @@ class BALLANCE_OT_add_floors(bpy.types.Operator):
|
||||
)
|
||||
|
||||
use_2d_top : bpy.props.BoolProperty(
|
||||
name="Top edge"
|
||||
name="Top edge",
|
||||
default=True
|
||||
)
|
||||
use_2d_right : bpy.props.BoolProperty(
|
||||
name="Right edge"
|
||||
name="Right edge",
|
||||
default=False
|
||||
)
|
||||
use_2d_bottom : bpy.props.BoolProperty(
|
||||
name="Bottom edge"
|
||||
name="Bottom edge",
|
||||
default=True
|
||||
)
|
||||
use_2d_left : bpy.props.BoolProperty(
|
||||
name="Left edge"
|
||||
name="Left edge",
|
||||
default=True
|
||||
)
|
||||
use_3d_top : bpy.props.BoolProperty(
|
||||
name="Top face"
|
||||
name="Top face",
|
||||
default=True
|
||||
)
|
||||
use_3d_bottom : bpy.props.BoolProperty(
|
||||
name="Bottom face"
|
||||
name="Bottom face",
|
||||
default=True
|
||||
)
|
||||
|
||||
previous_floor_type = ''
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
@ -115,25 +146,25 @@ class BALLANCE_OT_add_floors(bpy.types.Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
# yyc marked. Blumia reported.
|
||||
# prepare settings before registing
|
||||
# otherwise the mesh will not be created when first run.
|
||||
# (do not change any properties)
|
||||
|
||||
# yyc marked again.
|
||||
# now I migrate default side value setter to updator of enum property.
|
||||
# nothing need to process in here now.
|
||||
|
||||
# trigger default side props updator
|
||||
self.floor_type_updated(context)
|
||||
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
def draw(self, context):
|
||||
# get floor prototype
|
||||
floor_prototype = UTILS_constants.floor_blockDict[self.floor_type]
|
||||
|
||||
# try sync default value
|
||||
if self.previous_floor_type != self.floor_type:
|
||||
self.previous_floor_type = self.floor_type
|
||||
|
||||
default_sides = floor_prototype['DefaultSideConfig']
|
||||
self.use_2d_top = default_sides['UseTwoDTop']
|
||||
self.use_2d_right = default_sides['UseTwoDRight']
|
||||
self.use_2d_bottom = default_sides['UseTwoDBottom']
|
||||
self.use_2d_left = default_sides['UseTwoDLeft']
|
||||
self.use_3d_top = default_sides['UseThreeDTop']
|
||||
self.use_3d_bottom = default_sides['UseThreeDBottom']
|
||||
|
||||
# show property
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
@ -149,12 +180,13 @@ class BALLANCE_OT_add_floors(bpy.types.Operator):
|
||||
col.prop(self, "expand_length_2")
|
||||
col.label(text="Unit size: " + floor_prototype['UnitSize'])
|
||||
col.label(text="Expand mode: " + floor_prototype['ExpandType'])
|
||||
grids = col.grid_flow(row_major=True, columns=3)
|
||||
grids = col.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
|
||||
grids.alignment = 'CENTER'
|
||||
grids.separator()
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][0])
|
||||
grids.separator()
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][3])
|
||||
grids.template_icon(icon_value = UTILS_constants.icons_floorDict[self.floor_type])
|
||||
grids.template_icon(icon_value = UTILS_icons_manager.get_floor_icon(self.floor_type))
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][1])
|
||||
grids.separator()
|
||||
grids.label(text=UTILS_constants.floor_expandDirectionMap[floor_prototype['InitColumnDirection']][floor_prototype['ExpandType']][2])
|
||||
@ -168,12 +200,13 @@ class BALLANCE_OT_add_floors(bpy.types.Operator):
|
||||
|
||||
col.separator()
|
||||
col.label(text="Sides")
|
||||
grids = col.grid_flow(row_major=True, columns=3)
|
||||
grids = col.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
|
||||
grids.alignment = 'CENTER'
|
||||
grids.separator()
|
||||
grids.prop(self, "use_2d_top")
|
||||
grids.separator()
|
||||
grids.prop(self, "use_2d_left")
|
||||
grids.template_icon(icon_value = UTILS_constants.icons_floorDict[self.floor_type])
|
||||
grids.template_icon(icon_value = UTILS_icons_manager.get_floor_icon(self.floor_type))
|
||||
grids.prop(self, "use_2d_right")
|
||||
grids.separator()
|
||||
grids.prop(self, "use_2d_bottom")
|
||||
@ -221,7 +254,7 @@ def _create_or_get_material(material_name, prefs_externalTexture):
|
||||
try_item['data']['ambient'], try_item['data']['diffuse'],
|
||||
try_item['data']['specular'], try_item['data']['emissive'],
|
||||
try_item['data']['power'],
|
||||
False, False, False, False,
|
||||
False, False, True, False,
|
||||
texture)
|
||||
)
|
||||
break
|
||||
@ -436,13 +469,18 @@ def _load_basic_floor(mesh, floor_type, rotation, height_multiplier, d1, d2, sid
|
||||
_virtual_foreach_set(mesh.vertices, "co", global_offset_vec, vecList)
|
||||
_virtual_foreach_set(mesh.loops, "vertex_index", global_offset_loops, faceList)
|
||||
_virtual_foreach_set(mesh.loops, "normal", global_offset_loops, normalList)
|
||||
_virtual_foreach_set(mesh.uv_layers[0].data, "uv", global_offset_loops, uvList)
|
||||
# Blender 3.5 CHANGED. MeshUVLoop is deprecated and removed in 4.0
|
||||
# See https://wiki.blender.org/wiki/Reference/Release_Notes/3.5/Python_API
|
||||
# use MeshUVLoopLayer.uv[i].vector instead. MeshUVLoopLayer can be fetched from `mesh.uv_layers[i]` or `mesh.uv_layers.active`
|
||||
_virtual_foreach_set(mesh.uv_layers[0].uv, "vector", global_offset_loops, uvList)
|
||||
|
||||
cache_counter = 0
|
||||
for i in range(len(faceMatList)):
|
||||
indCount = faceIndList[i]
|
||||
mesh.polygons[i + global_offset_polygons].loop_start = global_offset_loops + cache_counter
|
||||
mesh.polygons[i + global_offset_polygons].loop_total = indCount
|
||||
# Blender 3.6 CHANGED. loop_total is readonly now. the count of consumed vertices is decided by next loop's loop_start
|
||||
# See: https://wiki.blender.org/wiki/Reference/Release_Notes/3.6/Python_API
|
||||
# mesh.polygons[i + global_offset_polygons].loop_total = indCount
|
||||
mesh.polygons[i + global_offset_polygons].material_index = faceMatList[i]
|
||||
mesh.polygons[i + global_offset_polygons].use_smooth = True
|
||||
cache_counter += indCount
|
||||
|
@ -10,9 +10,11 @@ class BALLANCE_OT_add_rails(bpy.types.Operator):
|
||||
rail_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="Rail type",
|
||||
items=(('MONO', "Monorail", ""),
|
||||
('DOUBLE', "Rail", ""),
|
||||
),
|
||||
items=(
|
||||
('MONO', "Monorail", ""),
|
||||
('DOUBLE', "Rail", ""),
|
||||
),
|
||||
default='DOUBLE',
|
||||
)
|
||||
|
||||
rail_radius: bpy.props.FloatProperty(
|
||||
@ -38,6 +40,11 @@ class BALLANCE_OT_add_rails(bpy.types.Operator):
|
||||
# merge
|
||||
firstObj = _merge_two_circle(firstObj, secondObj)
|
||||
|
||||
# rename
|
||||
if self.rail_type == 'DOUBLE':
|
||||
firstObj.name = "A_Rail_"
|
||||
else:
|
||||
firstObj.name = "A_Rail_Mono_"
|
||||
# apply 3d cursor
|
||||
UTILS_functions.move_to_cursor(firstObj)
|
||||
|
||||
@ -89,6 +96,8 @@ class BALLANCE_OT_add_tunnels(bpy.types.Operator):
|
||||
# merge
|
||||
firstObj = _merge_two_circle(firstObj, secondObj)
|
||||
|
||||
# rename
|
||||
firstObj.name = "A_Rail_Tunnel_"
|
||||
# apply 3d cursor
|
||||
UTILS_functions.move_to_cursor(firstObj)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_select_virtools_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Select objects by Virtools Group."""
|
||||
@ -7,32 +7,55 @@ class BALLANCE_OT_select_virtools_group(UTILS_virtools_prop.common_group_name_pr
|
||||
bl_label = "Select by Virtools Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
merge_selection: bpy.props.BoolProperty(
|
||||
name="Merge Selection",
|
||||
description="Merge selection, rather than re-select them.",
|
||||
default=False,
|
||||
)
|
||||
|
||||
ignore_hide: bpy.props.BoolProperty(
|
||||
name="Ignore Hide Property",
|
||||
description="Select objects without considering visibility.",
|
||||
default=False,
|
||||
selection_type: bpy.props.EnumProperty(
|
||||
name="Mode",
|
||||
description="Selection mode",
|
||||
items=(
|
||||
('SET', "Set", "Sets a new selection.", "SELECT_SET", 0),
|
||||
('EXTEND', "Extend", "Adds newly selected items to the existing selection.", "SELECT_EXTEND", 1),
|
||||
('SUBTRACT', "Subtract", "Removes newly selected items from the existing selection.", "SELECT_SUBTRACT", 2),
|
||||
('DIFFERENCE', "Invert", "Inverts the selection.", "SELECT_DIFFERENCE", 3),
|
||||
('INTERSECT', "Intersect", "Selects items that intersect with the existing selection.", "SELECT_INTERSECT", 4),
|
||||
),
|
||||
default='SET'
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# iterate object
|
||||
for obj in bpy.context.scene.objects:
|
||||
# ignore hidden objects
|
||||
if (not self.ignore_hide) and obj.hide_get() == True:
|
||||
continue
|
||||
if self.selection_type == 'SET':
|
||||
# iterate object
|
||||
for obj in bpy.context.scene.objects:
|
||||
# check group and decide whether select this obj
|
||||
obj.select_set(UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()))
|
||||
|
||||
elif self.selection_type == 'EXTEND':
|
||||
# also iterate all objects
|
||||
for obj in bpy.context.scene.objects:
|
||||
# directly add if group matched. do not deselect anything
|
||||
if UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()):
|
||||
obj.select_set(True)
|
||||
elif self.selection_type == 'SUBTRACT':
|
||||
# subtract only involving selected item. so we get selected objest first
|
||||
# and iterate it to reduce useless operations
|
||||
selected = bpy.context.selected_objects[:]
|
||||
for obj in selected:
|
||||
# remove matched only
|
||||
if UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()):
|
||||
obj.select_set(False)
|
||||
|
||||
# check group
|
||||
if UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()):
|
||||
# select object
|
||||
obj.select_set(True)
|
||||
else:
|
||||
# if not in merge mode, deselect them
|
||||
if not self.merge_selection:
|
||||
elif self.selection_type == 'DIFFERENCE':
|
||||
# construct a selected obj set for convenient operations
|
||||
selected_set = set(bpy.context.selected_objects)
|
||||
# iterate all objects
|
||||
for obj in bpy.context.scene.objects:
|
||||
# use xor to select
|
||||
# in_selected XOR in_group
|
||||
obj.select_set((obj in selected_set) ^ UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()))
|
||||
elif self.selection_type == 'INTERSECT':
|
||||
# like subtract, only iterate selected obj
|
||||
selected = bpy.context.selected_objects[:]
|
||||
for obj in selected:
|
||||
# remove not matched
|
||||
if not UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()):
|
||||
obj.select_set(False)
|
||||
|
||||
return {'FINISHED'}
|
||||
@ -40,63 +63,13 @@ class BALLANCE_OT_select_virtools_group(UTILS_virtools_prop.common_group_name_pr
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row()
|
||||
row.prop(self, 'ignore_hide')
|
||||
row.prop(self, 'merge_selection')
|
||||
layout.label(text='Selection Parameters')
|
||||
layout.prop(self, 'selection_type', expand=True, icon_only=True)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text='Group Parameters')
|
||||
self.parent_draw(layout)
|
||||
|
||||
class BALLANCE_OT_filter_virtools_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Filter objects by Virtools Group."""
|
||||
bl_idname = "ballance.filter_virtools_group"
|
||||
bl_label = "Filter by Virtools Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
reverse_selection: bpy.props.BoolProperty(
|
||||
name="Reverse",
|
||||
description="Reverse operation. Remove matched objects.",
|
||||
default=False,
|
||||
)
|
||||
|
||||
ignore_hide: bpy.props.BoolProperty(
|
||||
name="Ignore Hide Property",
|
||||
description="Select objects without considering visibility.",
|
||||
default=False,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# make a copy for all objects, to ensure it is not viotile
|
||||
# becuase we need deselect some objects in for statement
|
||||
selected = bpy.context.selected_objects[:]
|
||||
# iterate object
|
||||
for obj in selected:
|
||||
# ignore hidden objects
|
||||
if (not self.ignore_hide) and obj.hide_get() == True:
|
||||
continue
|
||||
|
||||
# check group and decide select
|
||||
is_selected = UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string())
|
||||
if self.reverse_selection:
|
||||
is_selected = not is_selected
|
||||
|
||||
# select object
|
||||
obj.select_set(is_selected)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row()
|
||||
row.prop(self, 'ignore_hide')
|
||||
row.prop(self, 'reverse_selection')
|
||||
|
||||
layout.separator()
|
||||
self.parent_draw(layout)
|
||||
|
||||
|
||||
|
||||
class BALLANCE_OT_ctx_set_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Grouping selected objects"""
|
||||
bl_idname = "ballance.ctx_set_group"
|
||||
@ -118,7 +91,10 @@ class BALLANCE_OT_ctx_set_group(UTILS_virtools_prop.common_group_name_props):
|
||||
|
||||
# throw a warning if some objects have duplicated group
|
||||
if has_duplicated:
|
||||
UTILS_functions.show_message_box(("Some objects have duplicated group name.", "These objects have been omitted.", ), "Duplicated Group", 'ERROR')
|
||||
UTILS_functions.show_message_box(
|
||||
("Some objects have duplicated group name.", "These objects have been omitted.", ),
|
||||
"Duplicated Group", UTILS_icons_manager.blender_error_icon
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@ -151,7 +127,10 @@ class BALLANCE_OT_ctx_unset_group(UTILS_virtools_prop.common_group_name_props):
|
||||
|
||||
# throw a warning if some objects have duplicated group
|
||||
if lack_group:
|
||||
UTILS_functions.show_message_box(("Some objects lack specified group name.", "These objects have been omitted.", ), "Lack Group", 'ERROR')
|
||||
UTILS_functions.show_message_box(
|
||||
("Some objects lack specified group name.", "These objects have been omitted.", ),
|
||||
"Lack Group", UTILS_icons_manager.blender_error_icon
|
||||
)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@ -169,11 +148,14 @@ class BALLANCE_OT_ctx_clear_group(bpy.types.Operator):
|
||||
def poll(self, context):
|
||||
return len(bpy.context.selected_objects) != 0
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_confirm(self, event)
|
||||
|
||||
def execute(self, context):
|
||||
# iterate object
|
||||
for obj in bpy.context.selected_objects:
|
||||
UTILS_virtools_prop.clear_virtools_group_data(obj)
|
||||
|
||||
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_add_virtools_group(UTILS_virtools_prop.common_group_name_props):
|
||||
"""Add a Virtools Group for Active Object."""
|
||||
@ -15,7 +15,7 @@ class BALLANCE_OT_add_virtools_group(UTILS_virtools_prop.common_group_name_props
|
||||
# try adding
|
||||
obj = context.object
|
||||
if not UTILS_virtools_prop.add_virtools_group_data(obj, self.get_group_name_string()):
|
||||
UTILS_functions.show_message_box(("Group name is duplicated!", ), "Duplicated Name", 'ERROR')
|
||||
UTILS_functions.show_message_box(("Group name is duplicated!", ), "Duplicated Name", UTILS_icons_manager.blender_error_icon)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@ -44,9 +44,29 @@ class BALLANCE_OT_rm_virtools_group(bpy.types.Operator):
|
||||
UTILS_virtools_prop.remove_virtools_group_data_by_index(obj, int(UTILS_virtools_prop.get_active_virtools_group(obj)))
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_OT_clear_virtools_group(bpy.types.Operator):
|
||||
"""Clear All Virtools Group for Active Object."""
|
||||
bl_idname = "ballance.clear_virtools_group"
|
||||
bl_label = "Clear Virtools Group"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return context.object is not None
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_confirm(self, event)
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.object
|
||||
UTILS_virtools_prop.clear_virtools_group_data(obj)
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_UL_virtools_group(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
layout.prop(item, 'group_name', icon='GROUP', emboss=False, text="")
|
||||
layout.label(text=item.group_name, translate=False, icon='GROUP')
|
||||
#layout.prop(item, 'group_name', icon='GROUP', emboss=False, text="")
|
||||
|
||||
class BALLANCE_PT_virtools_group(bpy.types.Panel):
|
||||
"""Show Virtools Group Properties."""
|
||||
@ -71,3 +91,5 @@ class BALLANCE_PT_virtools_group(bpy.types.Panel):
|
||||
col = row.column(align=True)
|
||||
col.operator(BALLANCE_OT_add_virtools_group.bl_idname, icon='ADD', text="")
|
||||
col.operator(BALLANCE_OT_rm_virtools_group.bl_idname, icon='REMOVE', text="")
|
||||
col.separator()
|
||||
col.operator(BALLANCE_OT_clear_virtools_group.bl_idname, icon='TRASH', text="")
|
||||
|
@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_virtools_prop, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_OT_apply_virtools_material(bpy.types.Operator):
|
||||
"""Apply Virtools Material to Blender Material."""
|
||||
@ -19,7 +19,7 @@ class BALLANCE_OT_apply_virtools_material(bpy.types.Operator):
|
||||
if mtl_data[0]:
|
||||
UTILS_functions.create_material_nodes(mtl, mtl_data)
|
||||
else:
|
||||
UTILS_functions.show_message_box(("Virtools Material is not enabled.", ), "Apply Failed", 'ERROR')
|
||||
UTILS_functions.show_message_box(("Virtools Material is not enabled.", ), "Apply Failed", UTILS_icons_manager.blender_error_icon)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@ -37,12 +37,54 @@ class BALLANCE_OT_parse_virtools_material(bpy.types.Operator):
|
||||
mtl = context.material
|
||||
mtl_data = UTILS_functions.parse_material_nodes(mtl)
|
||||
if mtl_data is None:
|
||||
UTILS_functions.show_message_box(("Fail to parse Principled BSDF.", ), "Parsing Failed", 'ERROR')
|
||||
UTILS_functions.show_message_box(("Fail to parse Principled BSDF.", ), "Parsing Failed", UTILS_icons_manager.blender_error_icon)
|
||||
else:
|
||||
UTILS_virtools_prop.set_virtools_material_data(mtl, mtl_data)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_OT_preset_virtools_material(bpy.types.Operator):
|
||||
"""Preset Virtools Material with Original Ballance Data."""
|
||||
bl_idname = "ballance.preset_virtools_material"
|
||||
bl_label = "Preset Virtools Material"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
preset_type: bpy.props.EnumProperty(
|
||||
name="Preset",
|
||||
description="The preset which you want to apply.",
|
||||
items=tuple(
|
||||
(str(idx), item["human-readable"], "Suit for: " + ", ".join(item["member"]))
|
||||
for idx, item in enumerate(UTILS_constants.floor_materialStatistic)
|
||||
),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.material is not None
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
self.layout.prop(self, "preset_type")
|
||||
|
||||
def execute(self, context):
|
||||
preset_idx = int(self.preset_type)
|
||||
preset_data = UTILS_constants.floor_materialStatistic[preset_idx]
|
||||
|
||||
# get data self and only change core colors
|
||||
mtl = context.material
|
||||
vtmtl = UTILS_virtools_prop.get_virtools_material(mtl)
|
||||
|
||||
vtmtl.ambient = preset_data['data']['ambient']
|
||||
vtmtl.diffuse = preset_data['data']['diffuse']
|
||||
vtmtl.specular = preset_data['data']['specular']
|
||||
vtmtl.emissive = preset_data['data']['emissive']
|
||||
vtmtl.specular_power = preset_data['data']['power']
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class BALLANCE_PT_virtools_material(bpy.types.Panel):
|
||||
"""Show Virtools Material Properties."""
|
||||
bl_label = "Virtools Material"
|
||||
@ -69,7 +111,9 @@ class BALLANCE_PT_virtools_material(bpy.types.Panel):
|
||||
layout.enabled = target.enable_virtools_material
|
||||
|
||||
# draw layout
|
||||
layout.label(text="Basic Parameters")
|
||||
row = layout.row()
|
||||
row.label(text="Basic Parameters")
|
||||
row.operator(BALLANCE_OT_preset_virtools_material.bl_idname, text="", icon="PRESET")
|
||||
layout.prop(target, 'ambient')
|
||||
layout.prop(target, 'diffuse')
|
||||
layout.prop(target, 'specular')
|
||||
@ -86,6 +130,6 @@ class BALLANCE_PT_virtools_material(bpy.types.Panel):
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Operations")
|
||||
layout.operator("ballance.apply_virtools_material", icon="NODETREE")
|
||||
layout.operator("ballance.parse_virtools_material", icon="HIDE_OFF")
|
||||
layout.operator(BALLANCE_OT_apply_virtools_material.bl_idname, icon="NODETREE")
|
||||
layout.operator(BALLANCE_OT_parse_virtools_material.bl_idname, icon="HIDE_OFF")
|
||||
|
||||
|
@ -169,13 +169,14 @@ floor_textureReflactionMap = {
|
||||
"BallStone": "Ball_Stone.bmp"
|
||||
}
|
||||
|
||||
# WARNING: this data is shared with `BallanceVirtoolsPlugin/bvh/features/mapping/fix_texture.cpp`
|
||||
# WARNING: this data is shared with `BallanceVirtoolsPlugin/bvh/features/mapping/bmfile_fix_texture.cpp`
|
||||
floor_materialStatistic = [
|
||||
{
|
||||
"human-readable": "Floor Side",
|
||||
"member": [
|
||||
"FloorSide",
|
||||
"FloorTopBorder_ForSide",
|
||||
"FloorTopBorderless_ForSide"
|
||||
"FloorSide",
|
||||
"FloorTopBorder_ForSide",
|
||||
"FloorTopBorderless_ForSide"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (0, 0, 0),
|
||||
@ -186,12 +187,13 @@ floor_materialStatistic = [
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Floor Top",
|
||||
"member": [
|
||||
"FloorTopBorder",
|
||||
"FloorTopBorderless",
|
||||
"FloorTopFlat",
|
||||
"FloorTopProfil",
|
||||
"FloorTopProfilFlat"
|
||||
"FloorTopBorder",
|
||||
"FloorTopBorderless",
|
||||
"FloorTopFlat",
|
||||
"FloorTopProfil",
|
||||
"FloorTopProfilFlat"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (0, 0, 0),
|
||||
@ -202,8 +204,9 @@ floor_materialStatistic = [
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Transform Paper",
|
||||
"member": [
|
||||
"BallPaper"
|
||||
"BallPaper"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (25 / 255.0, 25 / 255.0, 25 / 255.0),
|
||||
@ -213,10 +216,11 @@ floor_materialStatistic = [
|
||||
"power": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
"human-readable": "Transform Stone & Wood",
|
||||
"member": [
|
||||
"BallStone",
|
||||
"BallWood"
|
||||
"BallStone",
|
||||
"BallWood"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (25 / 255.0, 25 / 255.0, 25 / 255.0),
|
||||
@ -225,6 +229,45 @@ floor_materialStatistic = [
|
||||
"emissive": (60 / 255.0, 60 / 255.0, 60 / 255.0),
|
||||
"power": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Rail",
|
||||
"member": [
|
||||
"Rail"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (0.0, 0.0, 0.0),
|
||||
"diffuse": (100 / 255.0, 118 / 255.0, 133 / 255.0),
|
||||
"specular": (210 / 255.0, 210 / 255.0, 210 / 255.0),
|
||||
"emissive": (124 / 255.0, 134 / 255.0, 150 / 255.0),
|
||||
"power": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Wood Path",
|
||||
"member": [
|
||||
"WoodPanel"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (2 / 255.0, 2 / 255.0, 2 / 255.0),
|
||||
"diffuse": (1.0, 1.0, 1.0),
|
||||
"specular": (59 / 255.0, 59 / 255.0, 59 / 255.0),
|
||||
"emissive": (30 / 255.0, 30 / 255.0, 30 / 255.0),
|
||||
"power": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Wood Chip",
|
||||
"member": [
|
||||
"WoodPlain2"
|
||||
],
|
||||
"data": {
|
||||
"ambient": (25 / 255.0, 25 / 255.0, 25 / 255.0),
|
||||
"diffuse": (1.0, 1.0, 1.0),
|
||||
"specular": (100 / 255.0, 100 / 255.0, 100 / 255.0),
|
||||
"emissive": (50 / 255.0, 50 / 255.0, 50 / 255.0),
|
||||
"power": 50
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@ -247,11 +290,6 @@ for walk_root, walk_dirs, walk_files in os.walk(os.path.join(os.path.dirname(__f
|
||||
floor_derivedBlockList.append(item["Type"])
|
||||
floor_blockDict[item["Type"]] = item
|
||||
|
||||
icons_floor = None
|
||||
icons_floorDict = {}
|
||||
# blenderIcon_elements = None
|
||||
# blenderIcon_elements_dict = {}
|
||||
|
||||
rename_normalComponentsGroupName = set([
|
||||
"P_Extra_Life",
|
||||
"P_Extra_Point",
|
||||
|
@ -105,7 +105,7 @@ def parse_material_nodes(mtl):
|
||||
# return value
|
||||
return (True,
|
||||
mtl_ambient, mtl_diffuse, mtl_specular, mtl_emissive, mtl_specularPower,
|
||||
False, False, False, False,
|
||||
False, False, True, False,
|
||||
mtl_texture
|
||||
)
|
||||
|
||||
@ -116,8 +116,21 @@ def parse_material_nodes(mtl):
|
||||
# load component
|
||||
|
||||
def load_component(component_id):
|
||||
# get file first
|
||||
# get component name from id
|
||||
component_name = UTILS_constants.bmfile_componentList[component_id]
|
||||
|
||||
# create real mesh.
|
||||
# if component mesh is existed, use existed one.
|
||||
(mesh, skip_init) = create_instance_with_option(
|
||||
UTILS_constants.BmfileInfoType.MESH,
|
||||
"BlcBldPlg_EleMesh_" + component_name,
|
||||
'CURRENT'
|
||||
)
|
||||
if skip_init:
|
||||
return mesh
|
||||
|
||||
# mesh is not existing. start to load mesh
|
||||
# get file first
|
||||
selected_file = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'meshes',
|
||||
@ -126,9 +139,6 @@ def load_component(component_id):
|
||||
|
||||
# read file. please note this sector is sync with import_bm's mesh's code. when something change, please change each other.
|
||||
fmesh = open(selected_file, 'rb')
|
||||
|
||||
# create real mesh, we don't need to consider name. blender will solve duplicated name
|
||||
mesh = bpy.data.meshes.new('mesh_' + component_name)
|
||||
|
||||
vList = []
|
||||
vnList = []
|
||||
@ -168,8 +178,7 @@ def load_component(component_id):
|
||||
mesh.loops.foreach_set("normal", unpack_list(_flat_component_vertices_normal(faceList, vnList)))
|
||||
for i in range(len(faceList)):
|
||||
mesh.polygons[i].loop_start = i * 3
|
||||
mesh.polygons[i].loop_total = 3
|
||||
|
||||
# mesh.polygons[i].loop_total = 3 # Blender 3.6 CHANGED
|
||||
mesh.polygons[i].use_smooth = True
|
||||
|
||||
mesh.validate(clean_customdata=False)
|
||||
@ -204,6 +213,10 @@ def create_instance_with_option(instance_type, instance_name, instance_opt,
|
||||
For object, you should provide `extra_mesh`.
|
||||
For texture, you should provide `extra_texture_path` and `extra_texture_filename`.
|
||||
|
||||
Value type:
|
||||
`instance_type`: one integer in UTILS_constants.BmfileInfoType
|
||||
`instance_name`: a string of new data block name
|
||||
`instance_opt`: 'RENAME' or 'CURRENT'
|
||||
"""
|
||||
|
||||
def get_instance():
|
||||
|
98
ballance_blender_plugin/UTILS_icons_manager.py
Normal file
@ -0,0 +1,98 @@
|
||||
import bpy
|
||||
import bpy.utils.previews
|
||||
import os
|
||||
from . import UTILS_constants
|
||||
|
||||
blender_info_icon = 'INFO'
|
||||
blender_warning_icon = 'ERROR'
|
||||
blender_error_icon = 'CANCEL'
|
||||
|
||||
# universal icon loader, all icon are stored in this preview collection
|
||||
universal_icons = None
|
||||
|
||||
# empty icon for placeholder
|
||||
empty_icon_id = 0
|
||||
|
||||
# a map. key is block name, value is loaded icon id
|
||||
floor_icons_map: dict = {}
|
||||
element_icons_map: dict = {}
|
||||
groupext_icons_map: dict = {}
|
||||
|
||||
group_name_conv_map: dict = {
|
||||
"PS_Levelstart": "PS_FourFlames",
|
||||
"PE_Levelende": "PE_Balloon",
|
||||
"PC_Checkpoints": "PC_TwoFlames",
|
||||
"PR_Resetpoints": "PR_Resetpoint",
|
||||
|
||||
"Sound_HitID_01": "SoundID_01",
|
||||
"Sound_RollID_01": "SoundID_01",
|
||||
"Sound_HitID_02": "SoundID_02",
|
||||
"Sound_RollID_02": "SoundID_02",
|
||||
"Sound_HitID_03": "SoundID_03",
|
||||
"Sound_RollID_03": "SoundID_03"
|
||||
}
|
||||
|
||||
def register_icons():
|
||||
global universal_icons
|
||||
global empty_icon_id
|
||||
global floor_icons_map, element_icons_map, groupext_icons_map
|
||||
|
||||
# create preview collection and get icon folder
|
||||
icon_path = os.path.join(os.path.dirname(__file__), "icons")
|
||||
universal_icons = bpy.utils.previews.new()
|
||||
|
||||
# load empty
|
||||
universal_icons.load("BlcBldPlg_EmptyIcon", os.path.join(icon_path, "Empty.png"), 'IMAGE')
|
||||
empty_icon_id = universal_icons["BlcBldPlg_EmptyIcon"].icon_id
|
||||
|
||||
# add floor icon
|
||||
for key, value in UTILS_constants.floor_blockDict.items():
|
||||
blockIconName = "BlcBldPlg_FloorIcon_" + key
|
||||
universal_icons.load(blockIconName, os.path.join(icon_path, "floor", value["BindingDisplayTexture"]), 'IMAGE')
|
||||
floor_icons_map[key] = universal_icons[blockIconName].icon_id
|
||||
|
||||
# add elements icon
|
||||
for elename in UTILS_constants.bmfile_componentList:
|
||||
blockIconName = "BlcBldPlg_ElementIcon_" + elename
|
||||
universal_icons.load(blockIconName, os.path.join(icon_path, "element", elename + '.png'), 'IMAGE')
|
||||
element_icons_map[elename] = universal_icons[blockIconName].icon_id
|
||||
|
||||
# add extra group icon
|
||||
for grp in ("SoundID_01", "SoundID_02", "SoundID_03"):
|
||||
blockIconName = "BlcBldPlg_GroupIcon_" + grp
|
||||
universal_icons.load(blockIconName, os.path.join(icon_path, "group", grp + '.png'), 'IMAGE')
|
||||
groupext_icons_map[grp] = universal_icons[blockIconName].icon_id
|
||||
|
||||
def unregister_icons():
|
||||
global universal_icons
|
||||
global floor_icons_map, element_icons_map, groupext_icons_map
|
||||
|
||||
bpy.utils.previews.remove(universal_icons)
|
||||
floor_icons_map.clear()
|
||||
element_icons_map.clear()
|
||||
groupext_icons_map.clear()
|
||||
|
||||
def get_floor_icon(floor_blk_name: str):
|
||||
# default return empty icon
|
||||
return floor_icons_map.get(floor_blk_name, empty_icon_id)
|
||||
|
||||
def get_element_icon(element_name: str):
|
||||
# default return empty icon
|
||||
return element_icons_map.get(element_name, empty_icon_id)
|
||||
|
||||
def get_group_icon(group_name: str):
|
||||
# try parse string
|
||||
# if not found, return self
|
||||
conv_name = group_name_conv_map.get(group_name, group_name)
|
||||
|
||||
# get from extra group icon first
|
||||
idx = groupext_icons_map.get(conv_name, empty_icon_id)
|
||||
if idx != empty_icon_id:
|
||||
return idx
|
||||
|
||||
# if failed, get from element. if still failed, return empty icon
|
||||
return get_element_icon(conv_name)
|
||||
|
||||
# no matter how, register icon always
|
||||
# and no unregister call
|
||||
register_icons()
|
@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
from . import UTILS_constants, UTILS_functions
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_icons_manager
|
||||
|
||||
class BALLANCE_PG_virtools_material(bpy.types.PropertyGroup):
|
||||
enable_virtools_material: bpy.props.BoolProperty(
|
||||
@ -7,29 +7,37 @@ class BALLANCE_PG_virtools_material(bpy.types.PropertyGroup):
|
||||
default=False,
|
||||
)
|
||||
|
||||
ambient: bpy.props.FloatVectorProperty(name="Ambient",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.0])
|
||||
ambient: bpy.props.FloatVectorProperty(
|
||||
name="Ambient",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[76 / 255, 76 / 255, 76 / 255]
|
||||
)
|
||||
|
||||
diffuse: bpy.props.FloatVectorProperty(name="Diffuse",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.0])
|
||||
diffuse: bpy.props.FloatVectorProperty(
|
||||
name="Diffuse",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[178 / 255, 178 / 255, 178 / 255]
|
||||
)
|
||||
|
||||
specular: bpy.props.FloatVectorProperty(name="Specular",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.0])
|
||||
specular: bpy.props.FloatVectorProperty(
|
||||
name="Specular",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[127 / 255, 127 / 255, 127 / 255]
|
||||
)
|
||||
|
||||
emissive: bpy.props.FloatVectorProperty(name="Emissive",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.0])
|
||||
emissive: bpy.props.FloatVectorProperty(
|
||||
name="Emissive",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0, 0.0, 0.0]
|
||||
)
|
||||
|
||||
specular_power: bpy.props.FloatProperty(
|
||||
name="Specular Power",
|
||||
@ -53,7 +61,7 @@ class BALLANCE_PG_virtools_material(bpy.types.PropertyGroup):
|
||||
z_buffer: bpy.props.BoolProperty(
|
||||
name="Z Buffer",
|
||||
description="ZFunc: VXCMP_LESSEQUAL.",
|
||||
default=False,
|
||||
default=True,
|
||||
)
|
||||
|
||||
two_sided: bpy.props.BoolProperty(
|
||||
@ -84,7 +92,12 @@ class common_group_name_props(bpy.types.Operator):
|
||||
group_name: bpy.props.EnumProperty(
|
||||
name="Group Name",
|
||||
description="Pick vanilla Ballance group name.",
|
||||
items=tuple((x, x, "") for x in UTILS_constants.propsVtGroups_availableGroups),
|
||||
#items=tuple((x, x, "") for x in UTILS_constants.propsVtGroups_availableGroups),
|
||||
items=tuple(
|
||||
# token, display name, descriptions, icon, index
|
||||
(grp, grp, "", UTILS_icons_manager.get_group_icon(grp), idx)
|
||||
for idx, grp in enumerate(UTILS_constants.propsVtGroups_availableGroups)
|
||||
),
|
||||
)
|
||||
|
||||
custom_group_name: bpy.props.StringProperty(
|
||||
|
@ -2,10 +2,10 @@ bl_info={
|
||||
"name":"Ballance Blender Plugin",
|
||||
"description":"Ballance mapping tools for Blender",
|
||||
"author":"yyc12345",
|
||||
"version":(3,0),
|
||||
"blender":(3,3,0),
|
||||
"version":(3,3),
|
||||
"blender":(3,6,0),
|
||||
"category":"Object",
|
||||
"support":"TESTING",
|
||||
"support":"COMMUNITY",
|
||||
"warning": "Please read document before using this plugin.",
|
||||
"wiki_url": "https://github.com/yyc12345/BallanceBlenderHelper",
|
||||
"tracker_url": "https://github.com/yyc12345/BallanceBlenderHelper/issues"
|
||||
@ -13,9 +13,8 @@ bl_info={
|
||||
|
||||
# =============================================
|
||||
# import system
|
||||
import bpy, bpy_extras
|
||||
import bpy.utils.previews
|
||||
import os
|
||||
import bpy
|
||||
|
||||
# import my code (with reload)
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
@ -33,6 +32,8 @@ if "bpy" in locals():
|
||||
importlib.reload(UTILS_virtools_prop)
|
||||
if "UTILS_safe_eval" in locals():
|
||||
importlib.reload(UTILS_safe_eval)
|
||||
if "UTILS_icons_manager" in locals():
|
||||
importlib.reload(UTILS_icons_manager)
|
||||
|
||||
if "BMFILE_export" in locals():
|
||||
importlib.reload(BMFILE_export)
|
||||
@ -63,7 +64,7 @@ if "bpy" in locals():
|
||||
if "PROPS_virtools_material" in locals():
|
||||
importlib.reload(PROPS_virtools_material)
|
||||
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_preferences, UTILS_virtools_prop, UTILS_safe_eval
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_preferences, UTILS_virtools_prop, UTILS_safe_eval, UTILS_icons_manager
|
||||
from . import BMFILE_export, BMFILE_import
|
||||
from . import MODS_3dsmax_align, MODS_flatten_uv, MODS_rail_uv
|
||||
from . import OBJS_add_components, OBJS_add_floors, OBJS_add_rails, OBJS_group_opers
|
||||
@ -86,7 +87,7 @@ class BALLANCE_MT_ThreeDViewerMenu(bpy.types.Menu):
|
||||
layout.operator(MODS_flatten_uv.BALLANCE_OT_flatten_uv.bl_idname)
|
||||
|
||||
class BALLANCE_MT_AddFloorMenu(bpy.types.Menu):
|
||||
"""Add Ballance floor"""
|
||||
"""Add Ballance Floor"""
|
||||
bl_idname = "BALLANCE_MT_AddFloorMenu"
|
||||
bl_label = "Floors"
|
||||
|
||||
@ -97,7 +98,7 @@ class BALLANCE_MT_AddFloorMenu(bpy.types.Menu):
|
||||
for item in UTILS_constants.floor_basicBlockList:
|
||||
cop = layout.operator(
|
||||
OBJS_add_floors.BALLANCE_OT_add_floors.bl_idname,
|
||||
text=item, icon_value = UTILS_constants.icons_floorDict[item])
|
||||
text=item, icon_value = UTILS_icons_manager.get_floor_icon(item))
|
||||
cop.floor_type = item
|
||||
|
||||
layout.separator()
|
||||
@ -105,11 +106,11 @@ class BALLANCE_MT_AddFloorMenu(bpy.types.Menu):
|
||||
for item in UTILS_constants.floor_derivedBlockList:
|
||||
cop = layout.operator(
|
||||
OBJS_add_floors.BALLANCE_OT_add_floors.bl_idname,
|
||||
text=item, icon_value = UTILS_constants.icons_floorDict[item])
|
||||
text=item, icon_value = UTILS_icons_manager.get_floor_icon(item))
|
||||
cop.floor_type = item
|
||||
|
||||
class BALLANCE_MT_AddRailMenu(bpy.types.Menu):
|
||||
"""Add Ballance rail"""
|
||||
"""Add Ballance Rail"""
|
||||
bl_idname = "BALLANCE_MT_AddRailMenu"
|
||||
bl_label = "Rails"
|
||||
|
||||
@ -118,6 +119,37 @@ class BALLANCE_MT_AddRailMenu(bpy.types.Menu):
|
||||
layout.operator(OBJS_add_rails.BALLANCE_OT_add_rails.bl_idname, text="Rail Section")
|
||||
layout.operator(OBJS_add_rails.BALLANCE_OT_add_tunnels.bl_idname, text="Tunnel Section")
|
||||
|
||||
class BALLANCE_MT_AddNormalElementsMenu(bpy.types.Menu):
|
||||
"""Add Ballance Elements"""
|
||||
bl_idname = "BALLANCE_MT_AddNormalElementsMenu"
|
||||
bl_label = "Elements"
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
OBJS_add_components.BALLANCE_OT_add_components.draw_blc_menu(layout)
|
||||
class BALLANCE_MT_AddDupElementsMenu(bpy.types.Menu):
|
||||
"""Add Ballance Elements"""
|
||||
bl_idname = "BALLANCE_MT_AddDupElementsMenu"
|
||||
bl_label = "Elements"
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
OBJS_add_components.BALLANCE_OT_add_components_dup.draw_blc_menu(layout)
|
||||
class BALLANCE_MT_AddElementsMenu(bpy.types.Menu):
|
||||
"""Add Ballance Elements"""
|
||||
bl_idname = "BALLANCE_MT_AddElementsMenu"
|
||||
bl_label = "Elements"
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.label(text="Basic Elements")
|
||||
OBJS_add_components.BALLANCE_OT_add_components.draw_blc_menu(layout)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Duplicated Elements")
|
||||
OBJS_add_components.BALLANCE_OT_add_components_dup.draw_blc_menu(layout)
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="Elements Series")
|
||||
OBJS_add_components.BALLANCE_OT_add_components_series.draw_blc_menu(layout)
|
||||
|
||||
# =============================================
|
||||
# blender call system
|
||||
@ -135,11 +167,14 @@ classes = (
|
||||
BALLANCE_MT_ThreeDViewerMenu,
|
||||
|
||||
OBJS_add_components.BALLANCE_OT_add_components,
|
||||
OBJS_add_components.BALLANCE_OT_add_components_dup,
|
||||
OBJS_add_components.BALLANCE_OT_add_components_series,
|
||||
OBJS_add_rails.BALLANCE_OT_add_rails,
|
||||
OBJS_add_rails.BALLANCE_OT_add_tunnels,
|
||||
OBJS_add_floors.BALLANCE_OT_add_floors,
|
||||
BALLANCE_MT_AddFloorMenu,
|
||||
BALLANCE_MT_AddRailMenu,
|
||||
BALLANCE_MT_AddElementsMenu,
|
||||
|
||||
NAMES_rename_system.BALLANCE_OT_rename_by_group,
|
||||
NAMES_rename_system.BALLANCE_OT_convert_name,
|
||||
@ -149,14 +184,15 @@ classes = (
|
||||
UTILS_virtools_prop.BALLANCE_PG_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_OT_add_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_OT_rm_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_OT_clear_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_UL_virtools_group,
|
||||
PROPS_virtools_group.BALLANCE_PT_virtools_group,
|
||||
PROPS_virtools_material.BALLANCE_OT_apply_virtools_material,
|
||||
PROPS_virtools_material.BALLANCE_OT_parse_virtools_material,
|
||||
PROPS_virtools_material.BALLANCE_OT_preset_virtools_material,
|
||||
PROPS_virtools_material.BALLANCE_PT_virtools_material,
|
||||
|
||||
OBJS_group_opers.BALLANCE_OT_select_virtools_group,
|
||||
OBJS_group_opers.BALLANCE_OT_filter_virtools_group,
|
||||
OBJS_group_opers.BALLANCE_OT_ctx_set_group,
|
||||
OBJS_group_opers.BALLANCE_OT_ctx_unset_group,
|
||||
OBJS_group_opers.BALLANCE_OT_ctx_clear_group,
|
||||
@ -176,9 +212,10 @@ def menu_func_ballance_add(self, context):
|
||||
layout.label(text="Ballance")
|
||||
layout.menu(BALLANCE_MT_AddFloorMenu.bl_idname, icon='MESH_CUBE')
|
||||
layout.menu(BALLANCE_MT_AddRailMenu.bl_idname, icon='MESH_CIRCLE')
|
||||
layout.operator_menu_enum(
|
||||
OBJS_add_components.BALLANCE_OT_add_components.bl_idname,
|
||||
"elements_type", icon='MESH_ICOSPHERE', text="Elements")
|
||||
layout.menu(BALLANCE_MT_AddElementsMenu.bl_idname, icon='MESH_ICOSPHERE')
|
||||
#layout.operator_menu_enum(
|
||||
# OBJS_add_components.BALLANCE_OT_add_components.bl_idname,
|
||||
# "elements_type", icon='MESH_ICOSPHERE', text="Elements")
|
||||
def menu_func_ballance_rename(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
@ -192,8 +229,7 @@ def menu_func_ballance_select(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.label(text="Ballance")
|
||||
layout.operator(OBJS_group_opers.BALLANCE_OT_select_virtools_group.bl_idname, icon='SELECT_SET')
|
||||
layout.operator(OBJS_group_opers.BALLANCE_OT_filter_virtools_group.bl_idname, icon='FILTER')
|
||||
layout.operator(OBJS_group_opers.BALLANCE_OT_select_virtools_group.bl_idname, icon='RESTRICT_SELECT_OFF')
|
||||
def menu_func_ballance_grouping(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
@ -207,12 +243,7 @@ def menu_func_ballance_grouping(self, context):
|
||||
|
||||
def register():
|
||||
# we need init all icon first
|
||||
icon_path = os.path.join(os.path.dirname(__file__), "icons")
|
||||
UTILS_constants.icons_floor = bpy.utils.previews.new()
|
||||
for key, value in UTILS_constants.floor_blockDict.items():
|
||||
blockIconName = "Ballance_FloorIcon_" + key
|
||||
UTILS_constants.icons_floor.load(blockIconName, os.path.join(icon_path, "floor", value["BindingDisplayTexture"]), 'IMAGE')
|
||||
UTILS_constants.icons_floorDict[key] = UTILS_constants.icons_floor[blockIconName].icon_id
|
||||
#UTILS_icons_manager.register_icons()
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
@ -253,7 +284,7 @@ def unregister():
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
# we need uninstall all icon after all classes unregister
|
||||
bpy.utils.previews.remove(UTILS_constants.icons_floor)
|
||||
#UTILS_icons_manager.unregister_icons()
|
||||
|
||||
if __name__=="__main__":
|
||||
register()
|
BIN
ballance_blender_plugin/icons/Empty.png
Normal file
After Width: | Height: | Size: 785 B |
BIN
ballance_blender_plugin/icons/element/PC_TwoFlames.png
Normal file
After Width: | Height: | Size: 663 B |
BIN
ballance_blender_plugin/icons/element/PE_Balloon.png
Normal file
After Width: | Height: | Size: 745 B |
BIN
ballance_blender_plugin/icons/element/PR_Resetpoint.png
Normal file
After Width: | Height: | Size: 945 B |
BIN
ballance_blender_plugin/icons/element/PS_FourFlames.png
Normal file
After Width: | Height: | Size: 818 B |
BIN
ballance_blender_plugin/icons/element/P_Ball_Paper.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
ballance_blender_plugin/icons/element/P_Ball_Stone.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
ballance_blender_plugin/icons/element/P_Ball_Wood.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
ballance_blender_plugin/icons/element/P_Box.png
Normal file
After Width: | Height: | Size: 984 B |
BIN
ballance_blender_plugin/icons/element/P_Dome.png
Normal file
After Width: | Height: | Size: 611 B |
BIN
ballance_blender_plugin/icons/element/P_Extra_Life.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
ballance_blender_plugin/icons/element/P_Extra_Point.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
ballance_blender_plugin/icons/element/P_Modul_01.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
ballance_blender_plugin/icons/element/P_Modul_03.png
Normal file
After Width: | Height: | Size: 471 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_08.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
ballance_blender_plugin/icons/element/P_Modul_17.png
Normal file
After Width: | Height: | Size: 494 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_18.png
Normal file
After Width: | Height: | Size: 360 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_19.png
Normal file
After Width: | Height: | Size: 992 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_25.png
Normal file
After Width: | Height: | Size: 444 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_26.png
Normal file
After Width: | Height: | Size: 691 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_29.png
Normal file
After Width: | Height: | Size: 775 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_30.png
Normal file
After Width: | Height: | Size: 807 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_34.png
Normal file
After Width: | Height: | Size: 652 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_37.png
Normal file
After Width: | Height: | Size: 695 B |
BIN
ballance_blender_plugin/icons/element/P_Modul_41.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
ballance_blender_plugin/icons/element/P_Trafo_Paper.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
ballance_blender_plugin/icons/element/P_Trafo_Stone.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
ballance_blender_plugin/icons/element/P_Trafo_Wood.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
ballance_blender_plugin/icons/group/SoundID_01.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
ballance_blender_plugin/icons/group/SoundID_02.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
ballance_blender_plugin/icons/group/SoundID_03.png
Normal file
After Width: | Height: | Size: 251 B |